Vehicles/VehicleScripts/VehicleLighting.lua

VehicleLighting implements various different types of lights (headlights, low/high beam, brake lights, reverse lights, turn lights, beacon lights, strobe lights and custom lights).

  25  VehicleLighting                     = VehicleLighting or {};

VehicleLighting:load(dataTable)

This function sets up all necessary functions and afterwards loads the configuration for each individual light type.

Note that any inverse lights will always be turned on if the actual light is off (e.g. lights in headlightsInverse will be only off if the ones in headlights are turned on). This can be helpful if you have Z-fighting issues, where multiple objects are rendered at the same position.

  31  function VehicleLighting:load(dataTable)
  32      -- let's get to load our stuff
  33      self.setHeadlightsState         = VehicleManager:newFunction("setHeadlightsState");
  34      self.setTurnLightsState         = VehicleManager:newFunction("setTurnLightsState");
  35      self.setBeaconLightsState       = VehicleManager:newFunction("setBeaconLightsState");
  36      self.setCustomLightState        = VehicleManager:newFunction("setCustomLightState");
  37      self.setCustomLightState        = VehicleManager:newFunction("setCustomLightState");
  38      self.setRotatableLightRotation  = VehicleManager:newFunction("setRotatableLightRotation");
  39      
  40      if dataTable.lights ~= nil then
  41          self.headlightIds           = VehicleLighting.loadLights(self, dataTable.lights.headlights);
  42          self.brakelightIds          = VehicleLighting.loadLights(self, dataTable.lights.brakelights);
  43          self.reverselightIds        = VehicleLighting.loadLights(self, dataTable.lights.reverselights);
  44          self.turnLeftLightIds       = VehicleLighting.loadLights(self, dataTable.lights.leftIndicator);
  45          self.turnRightLightIds      = VehicleLighting.loadLights(self, dataTable.lights.rightIndicator);
  46          self.beaconLightIds         = VehicleLighting.loadLights(self, dataTable.lights.beaconLights);
  47          self.strobeLightIds         = VehicleLighting.loadLights(self, dataTable.lights.strobeLights);
  48  
  49          -- inverse of them
  50          self.headlightIds0          = VehicleLighting.loadLights(self, dataTable.lights.headlightsInverse);
  51          self.brakelightIds0         = VehicleLighting.loadLights(self, dataTable.lights.brakelightsInverse);
  52          self.reverselightIds0       = VehicleLighting.loadLights(self, dataTable.lights.reverselightsInverse);
  53          self.turnLeftLightIds0      = VehicleLighting.loadLights(self, dataTable.lights.leftIndicatorInverse);
  54          self.turnRightLightIds0     = VehicleLighting.loadLights(self, dataTable.lights.rightIndicatorInverse);
  55          self.beaconLightIds0        = VehicleLighting.loadLights(self, dataTable.lights.beaconLightsInverse);
  56          self.strobeLightIds0        = VehicleLighting.loadLights(self, dataTable.lights.strobeLightsInverse);
  57          
  58          -- low/high beam
  59          self.lowBeamIds             = VehicleLighting.loadLights(self, dataTable.lights.lowBeam);
  60          self.lowBeamIds0            = VehicleLighting.loadLights(self, dataTable.lights.lowBeamInverse);
  61          self.highBeamIds            = VehicleLighting.loadLights(self, dataTable.lights.highBeam);
  62          self.highBeamIds0           = VehicleLighting.loadLights(self, dataTable.lights.highBeamInverse);
  63  
  64          if dataTable.lights.customLights ~= nil then
  65              self.customLights       = {};
  66              self.customLightsByOrder= {};
  67  
  68              for k, v in pairs(dataTable.lights.customLights) do
  69                  local light         = {
  70                      ids             = VehicleLighting.loadLights(self, v.indexes),
  71                      inverseIds      = VehicleLighting.loadLights(self, v.indexesInverse),
  72                      inputKey        = v.inputKey or "",
  73                      state           = v.state or false,
  74                      name            = v.name or k,
  75                      key             = #self.customLightsByOrder + 1,
  76                  };
  77                  self.customLights[light.name]   = light;
  78                  table.insert(self.customLightsByOrder, light);
  79  
  80                  VehicleLighting.setLightsState(self, light.ids, light.inverseIds, light.state);
  81              end;
  82          end;
  83          if dataTable.lights.rotatableLights ~= nil then
  84              self.rotatableLights        = {};
  85              for k,light in ipairs(dataTable.lights.rotatableLights) do
  86                  local rotLight      = {
  87                      controlId       = getChild(self.id, light.controlId),
  88                      light           = getChild(self.id, light.rotatableLight),
  89                      rotation        = 0;
  90                  }
  91                  
  92                  if rotLight.controlId ~= nil then
  93                      ControlElement.new(rotLight.controlId);
  94              
  95                      ControlElement.setCallback(rotLight.controlId, 2,
  96                          function()
  97                              rotLight.rotation       = rotLight.rotation + Input.getAxis("Mouse X") * 2;
  98                              self:setRotatableLightRotation(k, rotLight.rotation);
  99                          end
 100                      );
 101              
 102                      ControlElement.setName(rotLight.controlId, l10n.get("controlElement_searchLightRotation"));
 103                  end;
 104      
 105                  table.insert(self.rotatableLights, rotLight);
 106              end;
 107          end;
 108      end;
 109  
 110      self.headlightsState            = 0; -- 0: off, 1: low beam, 2: high beam
 111      self.turnLightsState            = 0; -- 0: off, 1: left, 2: right, 3: both
 112      self.beaconLightOn              = false;
 113  
 114      self.beaconLightsRotSpeed       = dataTable.lights ~= nil and dataTable.lights.beaconLightsRotSpeed or 200; -- degrees per second
 115      self.strobeLightsPace           = dataTable.lights ~= nil and dataTable.lights.strobeLightsPace     or 1;
 116      
 117      self.blinkPulse                 = false;
 118      self.lastBlinkPulse             = false;
 119  
 120      if dataTable.sounds ~= nil then
 121          self.blinkTickOn            = self:loadSingleSound(dataTable.sounds.blinkTickOn);
 122          self.blinkTickOff           = self:loadSingleSound(dataTable.sounds.blinkTickOff);
 123      end;
 124  
 125      self:setTurnLightsState(0, true);
 126      self:setHeadlightsState(0, true);
 127      self:setBeaconLightsState(false, true);
 128  end;

VehicleLighting:saveToTable(tbl)

Saves the current state of all lights to the savegame.

 132  function VehicleLighting:saveToTable(tbl)
 133      if tbl == nil then return end;
 134  
 135      tbl.headlightsState             = self.headlightsState;
 136      tbl.beaconLightOn               = self.beaconLightOn;
 137  
 138      -- save turn lights state
 139      tbl.turnLightsState             = self.turnLightsState;
 140  
 141      if self.customLights ~= nil then
 142          tbl.customLights                = {};
 143  
 144          for k, v in pairs(self.customLights) do
 145              tbl.customLights[k]         = v.state;
 146          end;
 147      end;
 148  end;

VehicleLighting:loadFromTable(tbl)

Applies the state of all lights in the savegame.

 152  function VehicleLighting:loadFromTable(tbl)
 153      if tbl == nil then return end;
 154  
 155      self:setHeadlightsState(tbl.headlightsState or 0);
 156      self:setTurnLightsState(tbl.turnLightsState or 0);
 157      self:setBeaconLightsState(tbl.beaconLightOn or false);
 158  
 159      if self.customLights ~= nil and tbl.customLights ~= nil then
 160          for k, v in pairs(self.customLights) do
 161              if tbl.customLights[k] ~= nil then
 162                  self:setCustomLightState(v.key, tbl.customLights[k]);
 163              end;
 164          end;
 165      end;
 166  end;

VehicleLighting:loadLights(dataTable)

This helper function actually loads the light's indices. It is only called by the code in VehicleLighting:load().

 170  function VehicleLighting:loadLights(dataTable)
 171      if dataTable == nil then
 172          return nil;
 173      end;
 174      local ids                       = {};
 175      
 176      for i, v in pairs(dataTable) do
 177          local headlightsIndex       = v or "";
 178          
 179          if headlightsIndex == "" then break else
 180              table.insert(ids, getChild(self.id, headlightsIndex));
 181          end;
 182          
 183          i                           = i + 1;
 184      end;
 185      return ids;
 186  end;

VehicleLighting:setLightsState(lights, inverseLights, state)

This is a helper function again, which helps us make our code easier and shorter. All objects within lights will be set to active/inactive depending on state (bool). All objects within inverseLights will be set to the exact inverse state.

 192  function VehicleLighting:setLightsState(lights, inverseLights, state)
 193      if lights ~= nil then
 194          for _, id in pairs(lights) do
 195              setActive(id, state or false);
 196          end;
 197      end;
 198      if inverseLights ~= nil then
 199          for _, id in pairs(inverseLights) do
 200              setActive(id, not state);
 201          end;
 202      end;
 203  end;

VehicleLighting:setHeadlightsState(state, noEvent)

Turns the headlights on/off, depending on state (int, range 0-2: 0 = off, 1 = low beam, 2 = high beam).

 207  function VehicleLighting:setHeadlightsState(state, noEvent)
 208      if state > 2 or (state > 1 and self.highBeamIds == nil) then
 209          state                       = 0;
 210      end;
 211      self.headlightsState            = state;
 212  
 213      VehicleLighting.setLightsState(self, self.headlightIds, self.headlightIds0, state > 0);
 214      VehicleLighting.setLightsState(self, self.lowBeamIds,   self.lowBeamIds0,   state == 1);
 215      VehicleLighting.setLightsState(self, self.highBeamIds,  self.highBeamIds0,  state == 2);
 216  
 217      if not noEvent then
 218          EventSetLightState:send(self, self.headlightsState, self.turnLightsState, self.beaconLightOn);
 219      end;
 220  end;

VehicleLighting:setBeaconLightsState(state, noEvent)

Turns the beacon/strobe lights on or off, depending on state (bool).

 224  function VehicleLighting:setBeaconLightsState(state, noEvent)
 225      self.beaconLightOn              = state;
 226      
 227      VehicleLighting.setLightsState(self, self.beaconLightIds, self.beaconLightIds0, state);
 228  
 229      if not state then
 230          VehicleLighting.setLightsState(self, self.strobeLightIds, self.strobeLightIds0, false);
 231      end;
 232  
 233      if not noEvent then
 234          EventSetLightState:send(self, self.headlightsState, self.turnLightsState, self.beaconLightOn);
 235      end;
 236  end;

VehicleLighting:setCustomLightState(key, state, noEvent)

Turns the custom light named key (string) on or off, depending on state (bool).

 240  function VehicleLighting:setCustomLightState(key, state, noEvent)
 241      local customLight               = self.customLightsByOrder[key or 1];
 242  
 243      if customLight == nil then return end;
 244  
 245      customLight.state               = state;
 246  
 247      VehicleLighting.setLightsState(self, customLight.ids, customLight.inverseIds, state);
 248  
 249      if not noEvent then
 250          EventSetCustomLight:send(self, key, state);
 251      end;
 252  end;

VehicleLighting:setTurnLightsState(state, noEvent)

Sets the turn lights on or off, depending on state (0 = off, 1 = turn left, 2 = turn right, 3 = hazard lights)

 256  function VehicleLighting:setTurnLightsState(state, noEvent)
 257      self.turnLightsLeftActive       = state == 1 or state == 3;
 258      self.turnLightsRightActive      = state == 2 or state == 3;
 259  
 260      self.turnLightsState            = state;
 261  
 262      if not noEvent then
 263          EventSetLightState:send(self, self.headlightsState, self.turnLightsState, self.beaconLightOn);
 264      end;
 265  end;

VehicleLighting:setRotatableLightRotation(key, rotY, noEvent)

Sets the rotation of lights, that can be rotated over control elements.

 269  function VehicleLighting:setRotatableLightRotation(key, rotY, noEvent)
 270      self.rotatableLights[key].rotation          = rotY;
 271      setRotationY(self.rotatableLights[key].light, rotY);
 272  
 273      if not noEvent then
 274          EventSetLightRotation:send(self, key, rotY);
 275      end;
 276  end;

VehicleLighting:update(dt)

Checks whether the player wants to switch any lights on or off. Some lights (such as indicators or beacon lights) need to be updated every frame.

 279  function VehicleLighting:update(dt)
 280      if self:getIsInputActive() then
 281          if g_scenario.environment.isNight ~= (self.headlightsState ~= 0) then
 282              g_GUI:addKeyHint(InputMapper.Vehicle_Lights,    l10n.get("Input_Vehicle_Lights"));
 283          end;
 284          
 285          if InputMapper:getKeyDown(InputMapper.Vehicle_Lights) then
 286              self:setHeadlightsState(self.headlightsState + 1);
 287              self:playOnOffSound(self.headlightsState > 0, self.switchSound1, self.switchSound0);
 288          end;
 289          
 290          if InputMapper:getKeyDown(InputMapper.VehicleCar_IndicatorLeft) then
 291              self:setTurnLightsState(self.turnLightsLeftActive and 0 or 1);
 292              self:playOnOffSound(self.turnLightsLeftActive, self.switchSound1, self.switchSound0);
 293          end;
 294          if InputMapper:getKeyDown(InputMapper.VehicleCar_HazardLights) then
 295              self:setTurnLightsState((self.turnLightsLeftActive and self.turnLightsRightActive) and 0 or 3);
 296              self:playOnOffSound(self.turnLightsLeftActive, self.switchSound1, self.switchSound0);
 297          end;
 298          if InputMapper:getKeyDown(InputMapper.VehicleCar_IndicatorRight) then
 299              self:setTurnLightsState(self.turnLightsRightActive and 0 or 2);
 300              self:playOnOffSound(self.turnLightsRightActive, self.switchSound1, self.switchSound0);
 301          end;
 302          if InputMapper:getKeyDown(InputMapper.Vehicle_BeaconLight) then
 303              self:setBeaconLightsState(not self.beaconLightOn);
 304              self:playOnOffSound(self.beaconLightOn, self.switchSound1, self.switchSound0);
 305          end;
 306  
 307          if self.customLights ~= nil then
 308              for k, v in pairs(self.customLights) do
 309                  if v.inputKey ~= "" and InputMapper:getKeyDown(InputMapper[v.inputKey]) then
 310                      self:setCustomLightState(v.key, not v.state);
 311                      self:playOnOffSound(v.state, self.switchSound1, self.switchSound0);
 312                  end;
 313              end;
 314          end;
 315      end;
 316      
 317      -- set brake lights state
 318      VehicleLighting.setLightsState(self, self.brakelightIds,    self.brakelightIds0,    self.brakeValue > 1e-4);
 319      VehicleLighting.setLightsState(self, self.reverselightIds,  self.reverselightIds0,  self.currentGear == 1);
 320      
 321      -- set turn lights state
 322      self.lastBlinkPulse             = self.blinkPulse;
 323      self.blinkPulse                 = (getTime() % 1) < 0.5;
 324      VehicleLighting.setLightsState(self, self.turnLeftLightIds,     self.turnLeftLightIds0,     self.turnLightsLeftActive  and self.blinkPulse);
 325      VehicleLighting.setLightsState(self, self.turnRightLightIds,    self.turnRightLightIds0,    self.turnLightsRightActive and self.blinkPulse);
 326  
 327      if self.beaconLightOn then
 328          -- update beacon lights
 329          if self.beaconLightIds ~= nil then
 330              for _, id in pairs(self.beaconLightIds) do
 331                  rotate(id, 0, self.beaconLightsRotSpeed * dt, 0, false);
 332              end;
 333          end;
 334  
 335          -- and strobe lights
 336          if self.strobeLightsPace ~= nil then
 337              local strobeLightsTime  = (getTime() % self.strobeLightsPace) / self.strobeLightsPace;
 338              local strobeState       = (strobeLightsTime < 0.12) or (strobeLightsTime > 0.3 and strobeLightsTime < 0.42);
 339  
 340              VehicleLighting.setLightsState(self, self.strobeLightIds, self.strobeLightIds0, strobeState);
 341          end;
 342      end;
 343      
 344      if self:getIsGUIActive() then
 345          if self.turnLightsLeftActive or self.turnLightsRightActive then
 346  
 347              if self.lastBlinkPulse ~= self.blinkPulse then
 348                  self:playOnOffSound(self.blinkPulse, self.blinkTickOn, self.blinkTickOff);
 349              end;
 350          end;
 351  
 352          self.vehicleHUD:setTurnLights(self.turnLightsLeftActive and self.blinkPulse, self.turnLightsRightActive and self.blinkPulse);
 353          self.vehicleHUD:setLights(self.headlightsState == 1, self.headlightsState == 2);
 354      end;
 355  end;

VehicleLighting:onLeave(player, isLocalPlayer)

Stops the indicator sound if the player has left the vehicle.

 359  function VehicleLighting:onLeave(player, isLocalPlayer)
 360      -- stop playing audio
 361      if isLocalPlayer then
 362          if self.blinkTickOn ~= nil then         AudioSource.stop(self.blinkTickOn);         end;
 363          if self.blinkTickOff ~= nil then        AudioSource.stop(self.blinkTickOff);        end;
 364      end;
 365  end;

VehicleLighting:writeResync()

Resynchronizes all variables when a new player joins the game. The data sent by writeResync will be received by readResync.

 369  function VehicleLighting:writeResync()
 370      streamBeginWriteBitwise();
 371      streamWriteUIntN(self.headlightsState, 2);
 372      streamWriteUIntN(self.turnLightsState, 2);
 373      streamWriteBit(self.beaconLightOn);
 374  
 375      if self.customLightsByOrder ~= nil then
 376          for k, v in ipairs(self.customLightsByOrder) do
 377              streamWriteBit(v.state);
 378          end;
 379      end;
 380  
 381      streamEndWriteBitwise();
 382  end;

VehicleLighting:readResync()

Resynchronizes all variables when a new player joins the game. The data sent by writeResync will be received by readResync.

 386  function VehicleLighting:readResync()
 387      streamBeginReadBitwise();
 388      local headlight                 = streamReadUIntN(2);
 389      local turnLight                 = streamReadUIntN(2);
 390      local beaconLight               = streamReadBit();
 391  
 392      if self.customLightsByOrder ~= nil then
 393          for k, v in ipairs(self.customLightsByOrder) do
 394              self:setCustomLightState(v.key, streamReadBit(), true);
 395          end;
 396      end;
 397  
 398      streamEndReadBitwise();
 399  
 400      self:setHeadlightsState(headlight, true);
 401      self:setTurnLightsState(turnLight, true);
 402      self:setBeaconLightsState(beaconLight, true);
 403  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.