Vehicles/VehicleScripts/Seats.lua

Seats is the script which makes the vehicle enterable, i.e. without this script, you cannot enter the vehicle at all (neither via the Tab key nor by clicking some control element). The most common use-case of non-enterable vehicles are snow cannons. For most other vehicles (such as car, snowcats, snow mobiles, tractors, …) it makes sense to have this vehicle script active.

Generally, every time you can take place on a seat, this seat will be powered by VehicleSeat. This is true for vehicles and ropeway carriers, but also for stationary objects (e.g. sun deck chairs or the chairs in some ropeway control rooms).

Note: Seats supports multiple seats (that can be used either as second driver seat or as passenger seat). This means you can have multiple seats in your vehicle from which it can be controlled.

  29  Seats                               = Seats or {};
  30  Seats.playerNameColor               = { 200, 10, 10 };

Seats:load(dataTable, isCarrier)

Load the configuration data (i.e. what seats are there and what cameras can be enabled). Currently, the camera slot can be between 1 and 4 (1 = interior camera, 2 = exterior camera, 3 and 4 = custom cameras)

Note that this function is also used to initialize the seats of ropeway carriers. In that case, self represents the ropeway carrier instance (instead of the vehicle instance). dataTable will be the carrier's data table.

  37  function Seats:load(dataTable, isCarrier)
  38      self.seats                      = {};
  39      self.driverSeat                 = nil; -- main driver seat (for tab function)
  40      self.nonTabbable                = self.nonTabbable or false; -- could be overridden by other vehicleScripts
  41  
  42      -- isCarrier must be false for vehicles
  43      isCarrier                       = isCarrier or false;
  44      
  45      local cameras                   = {};
  46      self.camerasToDestroy           = {};
  47  
  48      -- note that the data table MUST consist cameras if you want to have working seats.
  49      for n, v in pairs(dataTable.cameras) do
  50          local camIndex              = v.index or "";
  51          local rotIndex              = v.rotIndex or "";
  52          local zoomIndex             = v.zoomIndex or "";
  53          local isInterieur           = v.isInterieur or false;
  54          local maxCameraAccelerationZoom = v.maxCameraAccelerationZoom or 0;
  55          local camId                 = getChild(self.id, camIndex);
  56          local rotId, zoomId         = nil, nil;
  57          
  58          if rotIndex ~= "" then      rotId   = getChild(self.id, rotIndex);      end;
  59          if zoomIndex ~= "" then     zoomId  = getChild(self.id, zoomIndex);     end;
  60          
  61          -- create a new camera and make sure its destroy is correctly called upon destroying the vehicle
  62          local camera                = VehicleCamera:new(camId, rotId, zoomId, isCarrier, self.id, maxCameraAccelerationZoom);
  63          table.insert(self.camerasToDestroy, camera);
  64  
  65          cameras[n]                  = camera;
  66          cameras[n].slot             = v.slot or 2;
  67          cameras[n].isInterieur      = isInterieur;
  68      end;
  69      
  70      for i, v in pairs(dataTable.seats) do
  71          local seatIndex             = v.index or "";
  72          
  73          if seatIndex == "" then break else
  74              
  75              local colId             = getChild(self.id, seatIndex);
  76              local camId             = getChild(self.id, v.cameraIndex   or "");
  77              local leaveId           = getChild(self.id, v.leaveIndex    or "");
  78              local characterNode     = nil;
  79              if v.characterIndex ~= nil then
  80                  characterNode = getChild(self.id, v.characterIndex);
  81              end;
  82              
  83              local characterPose     = v.characterPose or "VehicleSit";
  84              local footIk            = nil;
  85              if v.footIk ~= nil then
  86                  footIk          = {
  87                      footIkLeft      = getChild(self.id, v.footIk.footIkLeft),
  88                      footIkRight     = getChild(self.id, v.footIk.footIkRight),
  89                  };
  90              end;
  91              local handIk            = nil;
  92              if v.handIk ~= nil then
  93                  handIk          = {
  94                      handIkLeft      = getChild(self.id, v.handIk.handIkLeft),
  95                      handIkRight     = getChild(self.id, v.handIk.handIkRight),
  96                  };
  97              end;
  98              
  99              local seat              = VehicleSeat:new(colId, camId, leaveId, characterNode, characterPose, footIk, handIk, isCarrier);
 100              if not isCarrier and v.isDriver and self.driverSeat == nil then
 101                  -- only one driver seat allowed (because of multiplayer)
 102                  seat:setParentVehicle(self, true);
 103                  self.driverSeat     = seat;
 104              else
 105                  seat:setParentVehicle(self, false);
 106              end;
 107  
 108              self:registerNewSeat(seat);
 109  
 110              table.insert(self.seats, seat);
 111              
 112              for n, camera in pairs(cameras) do
 113                  local slotId        = camera.slot;
 114                  seat:addCamera(slotId, camera);
 115              end;
 116          end;
 117      end;
 118  
 119      self.isInterieurCamera              = true;
 120      self.currentCharacter = nil;
 121      if not isCarrier then
 122          if dataTable.playerNameLabel ~= nil then
 123              self.playerNameLabel        = getChild(self.id, dataTable.playerNameLabel);
 124          else
 125              -- automatically create it
 126              self.playerNameLabel        = createGameObject("PlayerNameLabel");
 127              setParent(self.playerNameLabel, self.mainId);
 128              setPosition(self.playerNameLabel, 0, 2.5, 0);
 129          end;
 130      end;
 131      
 132  end;

Seats:saveToTable(tbl, isCarrier)

Contrary to some other games, we always save the currently active camera position. If the player saves the game while sitting in a vehicle, that vehicle will also be active after loading the savegame, and even the same camera will be active.

 136  function Seats:saveToTable(tbl, isCarrier)
 137      if tbl == nil then return end;
 138  
 139      -- save all seats, but save cameras only once
 140      tbl.seats                       = {};
 141      local withoutCameras            = false;
 142  
 143      for k, v in pairs(self.seats) do
 144          -- note: for carriers, we only save the one seat where the player is actually sitting
 145          if not isCarrier or v.seatActive then
 146              tbl.seats[k]            = v:saveToTable(nil, withoutCameras);
 147              withoutCameras          = true;
 148          end;
 149      end;
 150  end;

Seats:loadFromTable(tbl)

Pass the data from our savegame on to the VehicleSeat.

 154  function Seats:loadFromTable(tbl)
 155      if tbl == nil then return end;
 156      if tbl.seats == nil then return end;
 157  
 158      for k, v in pairs(self.seats) do
 159          local seatTbl               = tbl.seats[k];
 160  
 161          if seatTbl ~= nil then
 162              v:loadFromTable(seatTbl);
 163          end;
 164      end;
 165  end;

Seats:update(dt)

Not in use any more

 169  function Seats:update(dt)
 170      -- don't update seats (this is done by BaseScenario)!
 171  end;

Seats:destroy()

 173  function Seats:destroy()
 174      for _, seat in pairs(self.seats) do
 175          seat:destroy();
 176      end;
 177  
 178      for k, v in pairs(self.camerasToDestroy) do
 179          v:destroy();
 180      end;
 181  end;

Seats:onEnter(player, isLocalPlayer)

Place the player character on the seat if a player enters the vehicle.

 185  function Seats:onEnter(player, isLocalPlayer)
 186      -- connect sitting character to seats script
 187      self.currentCharacter                   = player.playerCharacterSit;
 188  
 189      self.driverSeat.currentPlayerCharacter  = self.currentCharacter;
 190  
 191      if self.driverSeat.characterNode ~= nil then
 192          -- enable player
 193          setActive(self.currentCharacter, true);
 194  
 195          -- set parent and bind player to seat
 196          setParent(self.currentCharacter, self.driverSeat.characterNode);
 197          setPosition(self.currentCharacter, 0,0,0);
 198          setRotation(self.currentCharacter, 0,0,0);
 199  
 200          if self.driverSeat.footIk ~= nil then
 201              self.currentUser.footIkTargetLeft       = self.driverSeat.footIk.footIkLeft;
 202              self.currentUser.footIkTargetRight      = self.driverSeat.footIk.footIkRight;
 203          else
 204              self.currentUser.footIkTargetLeft       = nil;
 205              self.currentUser.footIkTargetRight      = nil;
 206          end;
 207      end;
 208  
 209      setActive(self.currentCharacter, not isLocalPlayer or not self.driverSeat.isInterieurCamera);
 210  
 211      -- set player IK hand targets
 212      self.currentUser.handIkTargetLeft               = self.anchorSteeringLeftIK;
 213      self.currentUser.handIkTargetRight              = self.anchorSteeringRightIK;
 214      
 215      if isLocalPlayer and self.driverSeat ~= nil then
 216          self.driverSeat:onEnter(player, isLocalPlayer);
 217      end;
 218  
 219      -- apply sit animation
 220      if self.driverSeat.characterPose ~= nil then
 221          Animator.setTrigger(self.currentCharacter, self.driverSeat.characterPose);
 222      end;
 223  end;
 224  --[[
 225  Remove the player character from the seat when the player leaves the vehicle.
 
 226  function Seats:onLeave(player, isLocalPlayer)
 227      player.handIkTargetLeft             = nil;
 228      player.handIkTargetRight            = nil;
 229  
 230      -- check for character nodes
 231      if self.driverSeat.characterNode ~= nil then
 232          -- set the parent of the character to 0 and apply position
 233          setParent(self.currentCharacter, 0);
 234          setPosition(self.currentCharacter, 0,0,0);
 235      end;
 236  
 237      if isLocalPlayer and self.driverSeat ~= nil and self.driverSeat.seatActive then
 238          self.driverSeat:onLeave(player, isLocalPlayer);
 239      end;
 240  end;

Seats:onGUI()

Render nicknames in multiplayer.

 245  function Seats:onGUI()
 246      if g_isMultiplayer and not GameplaySettings.hideMultiplayerNicknames then
 247          if self.playerNameLabel and self.currentUser ~= nil and self.currentUser ~= g_scenario.player and self.currentUser.playerName ~= nil and not g_GUI:getAnyGuiActive() then
 248              local wx,wy,wz          = getWorldPosition(self.playerNameLabel);
 249              local x,y,z             = Camera.worldToScreenPoint(wx,wy,wz);
 250              local sqrDist           = GameControl.getCameraSqrDistance(wx,wy,wz);
 251  
 252              -- only render nicknames of players closer than 100m
 253              if z > 0 and sqrDist < 100*100 then
 254                  local width, height = Screen.getSize();
 255                  
 256                  IMGUI.setAlignment("MiddleCenter");
 257                  IMGUI.setColor(self.currentUser:unpackHexColor());
 258  
 259                  -- adjust font size depending on distance
 260                  local fontSize      = mapClamped(0, 100*100, 18, 10, sqrDist);
 261                  local labelWidth, labelHeight   = 400, 2*fontSize;
 262                  local px, py        = x - labelWidth*0.5, height-y - labelHeight * 0.5;
 263                  
 264                  if px > 0 and py > 0 and px < width and py < height then
 265                      IMGUI.setFontSize(fontSize);
 266                      IMGUI.renderLabel(px, py, labelWidth, labelHeight, self.currentUser.playerName);
 267                  end;
 268              end;
 269          end;
 270      end;
 271  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.