Vehicles/VehicleScripts/FuelTank.lua

FuelTank adds some features to vehicles regarding fuel. Without using this script, your vehicle will not use any fuel. It also handles refueling.

FuelTank is therefore also responsible for the sounds that are played while refueling. You can specify custom sounds for your vehicle using fuelTankRefillLoop, fuelTankRefillStart and fuelTankRefillStop within your vehicle's data table. The configuration will look similar to the usual configuration of vehicle sounds. In case you have no sounds specified, the game will fall back to the default sounds that are initialized below.

  29  FuelTank                            = FuelTank or {};
  30  FuelTank.consumptionCoeff           = 1;
  31  
  32  FuelTank.loopSound                  = { prefab  = "$sounds/fuelStation/loop",   };
  33  FuelTank.startSound                 = { prefab  = "$sounds/fuelStation/start",  };
  34  FuelTank.stopSound                  = { prefab  = "$sounds/fuelStation/stop",   };

FuelTank:load(dataTable)

This will initialize the vehicle script. First, we set up some custom functions for our vehicle. Afterwards, we initialize some variables and finally we set up the actual sounds using the loadSingleSound function provided by the Vehicle class.

  39  function FuelTank:load(dataTable)
  40      self.addFuelUsage               = VehicleManager:newFunction("addFuelUsage");
  41      self.setIsRefuelling            = VehicleManager:newFunction("setIsRefuelling");
  42      self.getHasRunOutOfFuel         = FuelTank.getHasRunOutOfFuel;
  43      self.getCanRefillFuel           = FuelTank.getCanRefillFuel;
  44      self.setIsFuelStationInRange    = FuelTank.setIsFuelStationInRange;
  45  
  46      self.fuelTankCapacity           = math.max(dataTable.fuelTankCapacity   or 50, 1);
  47      self.fuelUsagePerSecond         = (dataTable.fuelUsagePerHour           or 5) / 3600;
  48      self.fuelUsagePerMetre          = (dataTable.fuelUsagePer100Km          or 15.0) * 0.00001;
  49      self.refuelSpeed                = math.abs(dataTable.refuelSpeed        or 20);
  50  
  51      self.fuelStationInRange         = false;
  52      self.fuelStationInRangeById     = {};
  53  
  54      self.fuelTankCurrentAmount      = self.fuelTankCapacity;
  55      self.lastFuelTankAmount         = self.fuelTankCapacity;
  56      self.refuelSoundActiveUntil     = -1;
  57  
  58      self.isRefuelling               = false;
  59      self.refuelSoundPlaying         = false;
  60  
  61      -- load sounds
  62      self.fuelTankRefillLoop         = self:loadSingleSound(dataTable.fuelTankRefillLoop     or FuelTank.loopSound);
  63      self.fuelTankRefillStart        = self:loadSingleSound(dataTable.fuelTankRefillStart    or FuelTank.startSound);
  64      self.fuelTankRefillStop         = self:loadSingleSound(dataTable.fuelTankRefillStop     or FuelTank.stopSound);
  65  
  66  end;

FuelTank:loadFromTable(tbl)

Loads the current fuel tank amount from the savegame.

  70  function FuelTank:loadFromTable(tbl)
  71      if tbl == nil then return end;
  72  
  73      self.fuelTankCurrentAmount      = getNoNil(tbl.fuelTankCurrentAmount, self.fuelTankCurrentAmount);
  74  end;

FuelTank:saveToTable(tbl)

Saves the current fuel tank amount to the savegame.

  78  function FuelTank:saveToTable(tbl)
  79      if tbl == nil then return end;
  80  
  81      tbl.fuelTankCurrentAmount       = self.fuelTankCurrentAmount;
  82  end;

FuelTank:addFuelUsage(dt, deltaWay)

Adds some amount of fuel usage (depending on the vehicle's configuration).

Fuel is consumed on a time basis. dt (float) is the time in seconds. Additionally, for each movement, some more fuel is consumed. deltaWay (float) specifies the way in metres.

We are aware that this method of determining fuel usage is not very accurate. However, it is sufficient for our use case, and saves performance compared to more verbose implementations.

Note that calling this function only has an effect if done on the server or in singleplayer. Clients cannot influence the fuel level of their vehicle.

  93  function FuelTank:addFuelUsage(dt, deltaWay)
  94      if g_isClient then
  95          return;
  96      end;
  97      self.fuelTankCurrentAmount      = math.max(self.fuelTankCurrentAmount - (self.fuelUsagePerSecond * dt + math.abs(self.fuelUsagePerMetre * deltaWay)) * FuelTank.consumptionCoeff, 0);
  98  end;

FuelTank:setIsFuelStationInRange(fuelStationId, colliderId, inRange)

This is called by FuelStationTrigger every time the vehicle enters or leaves a fuel station trigger.

 102  function FuelTank:setIsFuelStationInRange(fuelStationId, colliderId, inRange)
 103      self.fuelStationInRangeById[colliderId] = self.fuelStationInRangeById[colliderId] or {};
 104      local stationsInRange                   = self.fuelStationInRangeById[colliderId];
 105      stationsInRange[fuelStationId]          = ifelse(inRange, true, nil);
 106  
 107      if count(stationsInRange) == 0 then
 108          self.fuelStationInRangeById[colliderId] = nil;
 109      end;
 110  
 111      self.fuelStationInRange                 = count(self.fuelStationInRangeById) > 0;
 112  end;

FuelTank:getHasRunOutOfFuel()

Returns whether the vehicle has run out of fuel.

 116  function FuelTank:getHasRunOutOfFuel()
 117      return self.fuelTankCurrentAmount <= 0;
 118  end;

FuelTank:onReset()

Sometimes, vehicles may be resetted due to lack of fuel (e.g. if a player can't reach a fuel station in time). Therefore, we need to refuel the vehicle if its fuel tank is low.

Note that the price is considerably higher than for usual refueling.

 124  function FuelTank:onReset()
 125      if self.fuelTankCurrentAmount < 0.3 * self.fuelTankCapacity then
 126          -- we need to refill
 127          local delta                 = 0.3 * self.fuelTankCapacity - self.fuelTankCurrentAmount;
 128          local price                 = delta * g_scenario.ecoSystem.fuelPricePerLiterReset;
 129  
 130          -- always do this, even if the player couldn't pay this (otherwise his vehicle would be lost)
 131          g_scenario.accounting:addExpense("vehicles", -price);
 132  
 133          self.fuelTankCurrentAmount  = 0.3 * self.fuelTankCapacity;
 134      end;
 135  end;

FuelTank:setIsRefuelling(isRefuelling, noEvent)

Is called whenever the vehicle shall be refuelled.

 138  function FuelTank:setIsRefuelling(isRefuelling, noEvent)
 139      if self.isRefuelling == isRefuelling then
 140          return;
 141      end;
 142  
 143      self.isRefuelling               = isRefuelling;
 144      
 145      if g_isClient and not noEvent then
 146          EventRefuelVehicle:send(self, isRefuelling);
 147      end;
 148  end;

FuelTank:update(dt)

We need to update fuel usage and refueling every frame, as well as sounds and GUI displays.

 152  function FuelTank:update(dt)
 153      if not self.isActive and not self.refuelSoundPlaying then return end;
 154      
 155      local isRefuelling              = false;
 156  
 157      -- client side code
 158      if self:getIsInputActive() then
 159          -- allow refuelling even if we are not close to a fuel station, for there might be client-side errors
 160          -- and we always keep server authority
 161          self:setIsRefuelling(InputMapper:getKey(InputMapper.Vehicle_RefillFuel));
 162  
 163          if self.fuelStationInRange and self.fuelTankCurrentAmount <= self.fuelTankCapacity - 0.5 then
 164  
 165              g_GUI:addKeyHint(InputMapper.Vehicle_RefillFuel, l10n.get("Input_Vehicle_RefillFuel"));
 166  
 167              if g_scenario.tutorialAgent ~= nil then
 168                  g_scenario.tutorialAgent:callByScript("fuelStation");
 169              end;
 170          end;
 171      end;
 172  
 173      if g_isClient then
 174          isRefuelling                = self.lastFuelTankAmount < self.fuelTankCurrentAmount;
 175          self.lastFuelTankAmount     = self.fuelTankCurrentAmount;
 176  
 177          -- above detection will only trigger directly after the frame in which packets are received from server
 178          -- hence wait 1sec for the falling edge
 179          if isRefuelling then
 180              -- activate sound for 1 second (if not already full)
 181              if self.fuelTankCurrentAmount >= self.fuelTankCapacity - 0.25 then
 182                  self.refuelSoundActiveUntil = -1;
 183              else
 184                  self.refuelSoundActiveUntil = getTime() + 1;
 185              end;
 186          else
 187              -- keep active for some time
 188              isRefuelling            = self.refuelSoundActiveUntil > getTime();
 189          end;
 190  
 191      -- check on non-clients (=> server or singleplayer) whether we need to refill
 192      elseif self.isRefuelling then
 193  
 194          if self.fuelTankCurrentAmount <= self.fuelTankCapacity - 0.5 and self:getIsActive() and self.fuelStationInRange then
 195              -- let's refuel
 196              local delta             = math.min(self.refuelSpeed * dt, self.fuelTankCapacity - self.fuelTankCurrentAmount);
 197  
 198              -- check if player can afford this
 199              local price             = delta * g_scenario.ecoSystem.fuelPricePerLiter;
 200  
 201              if g_scenario:canAffordExpense(price) then
 202                  -- refuel
 203                  self.fuelTankCurrentAmount  = math.min(self.fuelTankCurrentAmount + delta, self.fuelTankCapacity);
 204                  g_scenario.accounting:addExpense("vehicles", -price);
 205  
 206                  isRefuelling        = true;
 207              end;
 208          end;
 209      end;
 210  
 211      isRefuelling                    = isRefuelling and self:getIsLocalPlayerEntered();
 212  
 213      if self.refuelSoundPlaying ~= isRefuelling then
 214          if isRefuelling then
 215              -- start playing sounds
 216              self:playSound(self.fuelTankRefillLoop);
 217              self:playSound(self.fuelTankRefillStart);
 218              self:stopSound(self.fuelTankRefillStop);
 219          else
 220              self:stopSound(self.fuelTankRefillStart);
 221              self:stopSound(self.fuelTankRefillLoop);
 222              self:playSound(self.fuelTankRefillStop);
 223          end;
 224          self.refuelSoundPlaying     = isRefuelling;
 225      end;
 226  
 227      if self:getIsGUIActive() then
 228          self.vehicleHUD:showFuelAmount(self.fuelTankCurrentAmount, self.fuelTankCapacity);
 229      end;
 230  
 231  end;

FuelTank:onHUDActivate()

Activates the fuel-related UI elements in the vehicle HUD.

 235  function FuelTank:onHUDActivate()
 236      self.vehicleHUD:activateFuelDisplay();
 237  end;

FuelTank:onLeave(player, isLocalPlayer)

Stops all sounds when leaving a vehicle.

 241  function FuelTank:onLeave(player, isLocalPlayer)
 242      self.isRefuelling               = false;
 243  
 244      if isLocalPlayer then
 245          self:stopSound(self.fuelTankRefillStart);
 246          self:stopSound(self.fuelTankRefillLoop);
 247          self:stopSound(self.fuelTankRefillStop);
 248          self.refuelSoundPlaying     = false;
 249      end;
 250  end;

FuelTank:writeUpdate(isLocalPlayerEntered)

Sends the current fuel level from the server to the client.

 254  function FuelTank:writeUpdate(isLocalPlayerEntered)
 255      if g_isServer then
 256          streamBeginWriteBitwise();
 257          Utils.streamWriteFloatN(self.fuelTankCurrentAmount, 16, 0, self.fuelTankCapacity);
 258          streamEndWriteBitwise();
 259      end;
 260  end;

FuelTank:readUpdate()

Reads the current fuel level. Will be displayed by the UI in the next frame's update call.

 264  function FuelTank:readUpdate()
 265      if g_isClient then
 266          streamBeginReadBitwise();
 267          self.fuelTankCurrentAmount  = Utils.streamReadFloatN(16, 0, self.fuelTankCapacity);
 268          streamEndReadBitwise();
 269      end;
 270  end;

All contents of this page may be used for modding use for Winter Resort Simulator - Season 2 only. Any use exceeding this regulation is not permitted.

Copyright (C) HR Innoways, 2021. All Rights Reserved.