--
-- the play module; controls scoring, player actions, etc
--

function play_ctor (self)

   self.compression = 10 -- spacetime compression; 1 == realistic timeframes
   self.car = nil -- the player car
   self.road = nil
   self.roadstream = nil
   self.traffic = nil
   self.money = 20 -- money in dollars
   self.score = 0 -- current score
   self.distance_m = 0 -- total distance travelled
   self.score_distance_m = 0 -- accumulate our distance in m to add to score ever N meters
   self.fuel_l = 16.5
   self.adventure_flag = nil -- flag if we're in adventure mode
   self.blood_alpha = 0 -- if the player is dying, we increase this to create a blood effect
   self.fadein_alpha = 1 -- fades towards zero; a blank-screen fadein
   self.sanity = 1
   self.special = 0
   self.special_keys = {}
   self.deaths = 0
   self.mood = "OK"
   self.last_mood = "OK"
   self.nofuel_counter = 10
   self.passed = 0
end

play = class (play_ctor)

function play:set_car (Car)

   self.car = Car
   self.car:set_speed_kph (100)
end

function play:mental (DMental)

   self.sanity = clamp (self.sanity + DMental, 0.0, 1.0)
end

function play:soothe (Factor)

   self:mental (0.005 * nz (Factor, 1))
end

function play:agitate (Factor)

   self:mental (-0.005 * nz (Factor, 1))
end

function play:experience (Key)

   if (self.special_keys[Key]) then return
   end
   self.special = self.special + 1
   self.special_keys[Key] = true
   self.car.max_speed_kph = self.car.max_speed_kph + 10
end

function play:advance (AdvanceM)

   self.car:set_shakiness (1.0 - self.sanity)

   -- decrease fuel
   local LPM = mpg2lpm (self.car.mpg)
   self.fuel_l = self.fuel_l - LPM * AdvanceM * self.compression

   -- score increases
   self.distance_m = self.distance_m + AdvanceM * self.compression
   self.score_distance_m = self.score_distance_m + AdvanceM -- true advance scoring
   while (self.score_distance_m > 100) do

      self.score = self.score + 50 / self.compression -- less compression = more points per true km
      self.score_distance_m = self.score_distance_m - 100
      if (self.car.speed_kph > 100) then self:agitate ()
      end
   end

   -- advance the traffic
   self.traffic:advance (AdvanceM)
end

function play:set_adventure (Node)

   cur_adventure:set_node (Node)
   self.adventure_flag = true
end

function play:set_roadstream (Roadstream)

   self.adventure_flag = nil

   if (Roadstream.terrain_type ~= 1) then self:experience ("terrain" .. tostring (Roadstream.terrain_type))
   end

   self.roadstream = Roadstream

   self.road = road ()
   self.road:init (self.roadstream)

   self.traffic = traffic ()
   self.traffic:init_road (self.road)
   self.car:init_road (self.road)
   self.car:set_speed_kph (self.roadstream:get_want_speed ())

   self.fadein_alpha = 1.0

   local CurSeg = self.car:get_cur_roadseg ()
   if (CurSeg) then self.car:set_lane (CurSeg.lanes)
   end
end

function play:update (T)

   if (self.adventure_flag) then

      cur_adventure:update (T)
      return
   end

   -- update the player car
   self.car:update (T)

   -- update the traffic
   self.traffic:update (T)

   -- advance that much
   local AdvanceM = self.car.distance_m - self.road.distance_m
   self:advance (AdvanceM)

   -- advance the road
   local ExitState = self.car:get_exit_state ()
   if (not ExitState) then self.road:advance (AdvanceM)
   elseif (2 == ExitState) then

      self:set_adventure (self.car.exit_node)
   end

   -- check for spinout, other special car state
   if (self.car.spinout_flag) then

      self.blood_alpha = interpolate_towards (self.blood_alpha, 1.0, .15, T)
      if (self.blood_alpha >= 1.0) then

         self.mood = "Gone"
         self:set_adventure (node_heaven (1))
         self.car:set_speed_kph (0)
      end

      if (self.mood ~= "Blood") then

         self.last_mood = self.mood
         self.mood = "Blood"
      end

      return
   else

      local NewMood = self:get_mood ()
      if (NewMood ~= self.mood) then

         if (NewMood == "Despondant") then self:experience ("despondance")
         end
         self.mood = NewMood
      end
   end

   if (self.fuel_l <= 0.0) then

      if (self.car.speed_kph == 0.0) then

         self.nofuel_counter = self.nofuel_counter - T
         if (self.nofuel_counter <= 0.0) then self:set_adventure (node_heaven (2))
         end
      end
      self.car:set_want_speed_kph (0)
      self.car:lanechange (1)

      return
   end

   if (self.fadein_alpha > 0.0) then

      self.fadein_alpha = interpolate_towards (self.fadein_alpha, 0.0, 0.5, T)
   end

   -- adjust player speed based on up/down arrows
   local SpeedDKPH = 0
   if (keys_down["UP"]) then SpeedDKPH = 10
   elseif (keys_down["DOWN"]) then SpeedDKPH = -50
   end
   if (SpeedDKPH) then self.car:set_want_speed_kph (self.car.speed_kph + SpeedDKPH)
   end

   -- set lane change based on l/r arrows
   local LaneD
   if (keys_down["LEFT"]) then LaneD = -1
   elseif (keys_down["RIGHT"]) then LaneD = 1
   end
   if (LaneD) then self.car:lanechange (LaneD)
   end

   -- stopped?
   if (0 == self.car.speed_kph and not self.car.spinout_flag) then self:experience ("stoppage")
   end

   if (self.car.speed_kph < 100) then self:soothe (T * 0.001)
   end
end

function play:render (R)

   if (self.adventure_flag) then

      return cur_adventure:render (R)
   end

   -- playing?
   local RList = {}
   table.insert (RList, R:camera (0, 200))
   table.insert (RList, R:rgba (1, 1, 1, 1))
   table.insert (RList, self.road:render (R))
   table.insert (RList, self.car:render (R))
   table.insert (RList, self.traffic:render (R))

   -- fadein alpha
   if (self.fadein_alpha > 0.0) then

      table.insert (RList, R:rgba (0, 0, 0, self.fadein_alpha))
      table.insert (RList, R:rect (0, 200, 400, 300))
   end

   -- blood alpha
   if (self.blood_alpha > 0.0) then

      table.insert (RList, R:rgba (1, 0, 0, self.blood_alpha))
      table.insert (RList, R:rect (0, 200, 400, 300))

      if (self.blood_alpha > 0.5) then

         table.insert (RList, R:rgba (0, 0, 0, (self.blood_alpha - 0.5) * 2))
         table.insert (RList, R:rect (0, 200, 400, 300))
      end
   end

   return RList
end

function play:keypress (K)

   if (self.adventure_flag) then

      cur_adventure:keypress (K)
      return
   end
end

function play:get_next_terrain ()

   -- for changing terrain; can depend on player's mood
   local CurType = self.roadstream.terrain_type
   local TWeights = { [1] = 1, [0] = 5 }
   TWeights[1] = TWeights[1] + self.special
   local TDelta = set_choose_weighted (TWeights)
   return clamp (CurType + TDelta, 1, 3)
end

function play:get_mood ()

   local Mood
   local Sanity = self.sanity
   if (Sanity < 0.1) then Mood = "Despondant"
   elseif (Sanity < 0.25) then Mood = "Desperate"
   elseif (Sanity < 0.5) then Mood = "Agitated"
   elseif (Sanity < 0.75) then Mood = "Upset"
   elseif (Sanity < 0.9) then Mood = "Lonely"
   else Mood = "OK"
   end
   return Mood
end

function play:pass ()

   self.passed = self.passed + 1
   self.score = self.score + 10
end