Vehicles/VehicleSeat.lua

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).

Regarding the implementation in vehicles, have a look at the Seats vehicle script. Some functions of it are also in use for ropeway carriers.

  26  g_currentVehicleSeat                = g_currentVehicleSeat or nil;
  27  
  28  VehicleSeat                         = VehicleSeat or {};
  29  local VehicleSeatClass              = Class(VehicleSeat);
  30  
  31  VehicleSeat.staticSeatKeysBySeat    = VehicleSeat.staticSeatKeysBySeat  or {};
  32  VehicleSeat.staticSeatsByKey        = VehicleSeat.staticSeatsByKey      or {};
  33  

VehicleSeat.controlElementActive()

Returns whether the seat's control element shall be active. Only active control elements can be clicked.

  37  function VehicleSeat.controlElementActive()
  38      return (g_scenario.player ~= nil and g_scenario.player:getIsLocalPlayerEntered()) and g_currentVehicleSeat == nil;
  39  end;
  40  

VehicleSeat.leaveActiveSeat(isEnteringOtherVehicle)

This will make the player leave any active seat.

  44  function VehicleSeat.leaveActiveSeat(isEnteringOtherVehicle)
  45      if g_currentVehicleSeat == nil then return end;
  46  
  47      -- leave that seat
  48      g_currentVehicleSeat:localLeaveRequest(isEnteringOtherVehicle);
  49  end;
  50  

VehicleSeat.registerStaticSeat(seat, savegameKey)

Function to register static seats.

  53  function VehicleSeat.registerStaticSeat(seat, savegameKey)
  54      VehicleSeat.staticSeatKeysBySeat[seat]      = savegameKey;
  55      VehicleSeat.staticSeatsByKey[savegameKey]   = seat;
  56  
  57      seat:assignSeatId(savegameKey);
  58  end;
  59  

VehicleSeat.unregisterStaticSeat(seat)

Function to unregister static keys.

  62  function VehicleSeat.unregisterStaticSeat(seat)
  63      local key                       = VehicleSeat.staticSeatKeysBySeat[seat];
  64  
  65      if key == nil then
  66          return false;
  67      end;
  68  
  69      VehicleSeat.staticSeatsByKey[key]       = nil;
  70      VehicleSeat.staticSeatKeysBySeat[seat]  = nil;
  71      return true;
  72  end;
  73  

VehicleSeat.getStaticSeatByKey(key)

Returns a static seat with the given key (if existing, otherwise nil).

  76  function VehicleSeat.getStaticSeatByKey(key)
  77      return VehicleSeat.staticSeatsByKey[key];
  78  end;
  79  

VehicleSeat:onCreateStaticSeat(id, cameraId, leaveNode, ...)

This function can be called for static objects (such as the chair in a command room) using following arguments:

  • id (int): id of the seat's control element.
  • cameraId (int): id of the transform which the camera shall be placed at.
  • leaveNode (int): id of the transform where the player will be placed at upon leaving the seat.
  86  function VehicleSeat:onCreateStaticSeat(id, cameraId, leaveNode, ...)
  87      cameraId                        = cameraId  or getChildAt(id, 0);
  88      leaveNode                       = leaveNode or getChildAt(id, 1);
  89  
  90      -- create a new seat which handles all updateable stuff itself
  91      local seat                      = VehicleSeat:new(id, cameraId, leaveNode, ...);
  92      seat.savegameKey                = string.format("seat:%s @ (%.4f, %.4f, %.4f)", getName(id), getWorldPosition(id));
  93      seat.isStaticSeat               = true;
  94  
  95      -- assign the savegame key as id to the seat
  96      VehicleSeat.registerStaticSeat(seat, seat.savegameKey);
  97  
  98      g_scenario:addObjectAndLoad(seat, id);
  99      return seat;
 100  end;
 101  

VehicleSeat:load(id, cameraId, leaveNode, characterNode, characterPose, footIk, handIk, ...)

Loads a newly created instance using the following parameters:

  • id (int): id of the seat's control element.
  • cameraId (int): id of the transform which the camera shall be placed at.
  • leaveNode (int): id of the transform where the player will be placed at upon leaving the seat.
  • : Arguments passed on to VehicleCamera.
 109  function VehicleSeat:load(id, cameraId, leaveNode, characterNode, characterPose, footIk, handIk, ...)
 110      self.id                         = id;
 111      
 112      ControlElement.new(self.id);
 113      ControlElement.setCallback(self.id, 1, self, "localEnterRequest");
 114      ControlElement.setActiveCallback(self.id, VehicleSeat.controlElementActive);
 115      ControlElement.setName(self.id, l10n.get("EnterSeat"));
 116  
 117      local firstCamera               = VehicleCamera:new(cameraId, nil,nil, ...);
 118      firstCamera.isInterieur         = true;
 119      
 120      self.mainCamera                 = firstCamera;
 121      self.cameraSlots                = {};
 122      self.cameraSlots[1]             = { firstCamera };
 123      self.activeCamera               = self.cameraSlots[1][1];
 124  
 125      self.camerasToDestroy           = { firstCamera };
 126      
 127      self.selectedSlot               = 1;
 128      self.selectedIndex              = 1;
 129      
 130      self.seatActive                 = false;
 131      self.leaveNode                  = leaveNode;
 132      self.characterNode              = characterNode;
 133      self.characterPose              = characterPose;
 134      self.footIk                     = footIk;
 135      self.handIk                     = handIk;
 136      self.enteredOnSkis              = false;
 137      self.isInterieurCamera          = true;
 138  
 139      self.currentPlayerCharacter     = nil;
 140  end;
 141  
 142  --[[
 143  Assigns the given parameters as seat id for multiplayer synchronisation. Internal use only.
 
 144  function VehicleSeat:assignSeatId(...)
 145      self.seatId                     = { ... };
 146  end;
 147  
 148  --[[
 149  Assigns the parent vehicle as required for multiplayer synchronisation. Internal use only.
 
 150  function VehicleSeat:setParentVehicle(vehicle, isDriverSeat)
 151      self.vehicle                    = vehicle;
 152      self.isDriverSeat               = isDriverSeat;
 153  end;
 154  

VehicleSeat:saveToTable(parentTable, withoutCameras)

Saves all relevant variables to the savegames.

 159  function VehicleSeat:saveToTable(parentTable, withoutCameras)
 160      local tbl                       = {
 161          seatActive                  = self.seatActive,
 162          selectedSlot                = self.selectedSlot,
 163          selectedIndex               = self.selectedIndex,
 164          enteredOnSkis               = self.enteredOnSkis,
 165      };
 166      -- safety layer
 167      local ignoreCamera              = false;
 168      if self.cameraSlots ~= nil then
 169          for slotNo, slot in pairs(self.cameraSlots) do
 170              for cameraNo, v in pairs(slot) do
 171                  if not ignoreCamera then
 172                      tbl["camera" .. slotNo .. "_" .. cameraNo] = v:saveToTable();
 173                  end;
 174                  ignoreCamera        = withoutCameras;
 175              end;
 176          end;
 177      end;
 178  
 179      if self.savegameKey ~= nil and parentTable ~= nil then
 180          -- static instance
 181          parentTable[self.savegameKey]   = tbl;
 182      else
 183          return tbl;
 184      end;
 185  end;
 186  

VehicleSeat:loadFromTable(tbl)

Restore all relevant variables from the savegame, and if necessary, enter the seat.

 190  function VehicleSeat:loadFromTable(tbl)
 191      if tbl == nil then return end;
 192  
 193      if self.savegameKey ~= nil then
 194          tbl                         = tbl[self.savegameKey];
 195  
 196          if tbl == nil then return end;
 197      end;
 198  
 199      self.seatActive                 = getNoNil(tbl.seatActive,      self.seatActive);
 200  
 201      if self.seatActive then
 202          self:localEnterRequest();
 203      end;
 204  
 205      self.selectedSlot               = getNoNil(tbl.selectedSlot,    self.selectedSlot);
 206      self.selectedIndex              = getNoNil(tbl.selectedIndex,   self.selectedIndex);
 207      self.enteredOnSkis              = getNoNil(tbl.enteredOnSkis,   self.enteredOnSkis);
 208  
 209      if self.cameraSlots ~= nil then
 210          for slotNo, slot in pairs(self.cameraSlots) do
 211              for cameraNo, v in pairs(slot) do
 212                  local cameraTbl     = tbl["camera" .. slotNo .. "_" .. cameraNo];
 213                  
 214                  if cameraTbl ~= nil then
 215                      v:loadFromTable(cameraTbl);
 216  
 217                      if cameraTbl.isActive then
 218                          self.activeCamera   = v;
 219                      end;
 220                  end;
 221              end;
 222          end;
 223      end;
 224  
 225      -- refresh active camera
 226      if self.seatActive then
 227          self:selectCamera(self.activeCamera);
 228          self:onEnter(g_scenario.player, g_scenario.player.isLocalPlayer);
 229      end;
 230  end;

VehicleSeat:destroy()

 232  function VehicleSeat:destroy()
 233      ControlElement.destroy(self.id);
 234  
 235      for k, v in pairs(self.camerasToDestroy) do
 236          v:destroy();
 237      end;
 238  
 239      if self.isStaticSeat then
 240          VehicleSeat.unregisterStaticSeat(self);
 241  
 242          if g_scenario ~= nil then
 243              g_scenario:removeObject(self);
 244          end;
 245      end;
 246  end;

VehicleSeat:addCamera(slotNo, camera)

Adds the VehicleCamera camera to the slot number slotNo (int, range 1-4).

 250  function VehicleSeat:addCamera(slotNo, camera)
 251      local slot                      = self.cameraSlots[slotNo];
 252      if slot == nil then
 253          slot                        = {};
 254          self.cameraSlots[slotNo]    = slot;
 255      end;
 256      
 257      table.insert(slot, camera);
 258  end;

VehicleSeat:getMayEnter(player)

Returns whether the player player may enter this seat.

 261  function VehicleSeat:getMayEnter(player)
 262      -- vehicle must have a driver seat and noone else can sit in there
 263      return (self.currentUser == nil or self.currentUser == player);
 264  end;

VehicleSeat:getIsLocalPlayerEntered()

Returns whether the local player (of your local game instance) is entered in this seat.

 267  function VehicleSeat:getIsLocalPlayerEntered()
 268      return self.currentUser == g_scenario.player;
 269  end;

VehicleSeat:getMinimapPositionAndRotation()

Returns the current position and rotation of the vehicle seat on the minimap (called by MinimapHUD).

 272  function VehicleSeat:getMinimapPositionAndRotation()
 273      local referenceId               = self.cameraSlots[1][1].cameraId;
 274  
 275      -- sanity check to make sure this seat has not been deleted
 276      if not getIsTransformValid(referenceId) then
 277          return 0,0,0,0;
 278      end;
 279  
 280      local x,y,z                     = getWorldPosition(referenceId);
 281      local _a, ry, _b                = getWorldRotation(referenceId);
 282      return x,y,z, ry;
 283  end;

VehicleSeat:localEnterRequest()

Is called if the player clicks the seat's control element.

 288  function VehicleSeat:localEnterRequest()
 289      -- if we are in multiplayer, this will be handled by the server!
 290      if g_isClient then
 291          EventRequestEnterVehicleSeat:send(unpack(self.seatId));
 292      else
 293          self:enterRequest(g_scenario.player);
 294      end;
 295  end;

VehicleSeat:enterRequest(player)

Is called whenever a player (table, reference to the PlayerController) is trying to enter the seat.

 299  function VehicleSeat:enterRequest(player)
 300      assert(g_isMaster, "Not allowed on MP clients");
 301  
 302      if self.vehicle ~= nil and self.isDriverSeat then
 303          -- different story for driver seats
 304          self.vehicle:handleEnterRequest(player);
 305      else
 306          self:setCurrentUser(player);
 307      end;
 308  end;

VehicleSeat:localLeaveRequest(isEnteringOtherVehicle)

Is called when the local player (of your local game instance) wants to leave the seat.

 312  function VehicleSeat:localLeaveRequest(isEnteringOtherVehicle)
 313      if g_isClient then
 314          EventRequestLeaveVehicleSeat:send(isEnteringOtherVehicle or false, unpack(self.seatId));
 315      else
 316          self:leaveRequest(g_scenario.player, isEnteringOtherVehicle);
 317      end;
 318  end;

VehicleSeat:leaveRequest(player, isEnteringOtherVehicle)

Leave request on servers (as triggered by the event sent in localLeaveRequest())

 322  function VehicleSeat:leaveRequest(player, isEnteringOtherVehicle)
 323      assert(g_isMaster, "Not allowed on MP clients");
 324      assert(player, "Must be called with a valid player on it");
 325  
 326      if self.vehicle ~= nil and self.isDriverSeat then
 327          self.vehicle:handleLeave(player);
 328      else
 329          if not isEnteringOtherVehicle then
 330              player:setCurrentUser(player);
 331          end;
 332      end;
 333  end;
 334  

VehicleSeat:setCurrentUser(newPlayer, noEvent)

Implements some features for seats that are similar to network entities, actually also utilising a part of the network entities.

 338  function VehicleSeat:setCurrentUser(newPlayer, noEvent)
 339      assert(not self.isDriverSeat, "Not allowed for driver seats");
 340      local oldPlayer                 = self.currentUser;
 341      
 342      if oldPlayer == nil and newPlayer == nil then
 343          return;
 344      end;
 345      
 346  
 347      if oldPlayer ~= nil and newPlayer ~= nil then
 348          if oldPlayer == newPlayer then
 349              -- same player => don't do anything
 350              return;
 351          end;
 352  
 353          -- first kick out the old player if this is on a client
 354          -- on a server its not allowed though
 355          if g_isClient then
 356              self:setCurrentUser(nil, true);
 357  
 358          else
 359              self:setCurrentUser(nil);
 360              error("currentUser must be nil before assigning a new user on a server");
 361          end;
 362      end;
 363  
 364      if g_isClient and self.currentUser == newPlayer then
 365          -- we already have the correct state (i.e. when leaving the vehicle)
 366          return;
 367      end;
 368  
 369      -- note: this code block is from NetworkEntity:setCurrentUser!
 370      NetworkEntity.setCurrentUser(self, newPlayer, noEvent, EventSetVehicleSeatUser, self.seatId);
 371  
 372      if oldPlayer ~= nil then
 373          -- !!TODO!! correct?
 374          self:onLeave(oldPlayer, oldPlayer:getIsLocalPlayer());
 375          oldPlayer:quitUsingEntity(self);
 376      end;
 377  
 378      if newPlayer ~= nil then
 379          newPlayer:startUsingEntity(self);
 380          self:onEnter(newPlayer, newPlayer:getIsLocalPlayer());
 381      end;
 382  end;

VehicleSeat:resyncCurrentUser()

Resynchronizes the current user of this seat to all clients.

 386  function VehicleSeat:resyncCurrentUser()
 387      assert(g_isServer, "Only allowed on server");
 388  
 389      NetworkEntity.resyncCurrentUser(self, EventSetVehicleSeatUser, self.seatId);
 390  end;
 391  

VehicleSeat:onEnter(player, isLocalPlayer)

Is called when player enters this vehicle seat. Do not call this to let the player enter the seat!

 395  function VehicleSeat:onEnter(player, isLocalPlayer)
 396      self.currentUser                = player;
 397  
 398      -- enable player
 399      if self.currentUser.playerCharacterSit ~= nil then
 400          setActive(self.currentUser.playerCharacterSit, not (self.isInterieurCamera and isLocalPlayer));
 401      end;
 402  
 403      if self.characterNode ~= nil and self.characterNode ~= "" then
 404          -- set parent and bind player to seat
 405          setParent(self.currentUser.playerCharacterSit, self.characterNode);
 406          setPosition(self.currentUser.playerCharacterSit, 0,0,0);
 407          setRotation(self.currentUser.playerCharacterSit, 0,0,0);
 408  
 409          if self.footIk ~= nil then
 410              self.currentUser.footIkTargetLeft       = self.footIk.footIkLeft;
 411              self.currentUser.footIkTargetRight      = self.footIk.footIkRight;
 412          else
 413              self.currentUser.footIkTargetLeft       = nil;
 414              self.currentUser.footIkTargetRight      = nil;
 415          end;
 416  
 417          if not self.isDriverSeat then 
 418              if self.handIk ~= nil then
 419                  self.currentUser.handIkTargetLeft   = self.handIk.handIkLeft;
 420                  self.currentUser.handIkTargetRight  = self.handIk.handIkRight;
 421              else
 422                  -- set player IK hand targetss
 423                  self.currentUser.handIkTargetLeft   = self.currentUser.passengerHandIkTargetLeft;
 424                  self.currentUser.handIkTargetRight  = self.currentUser.passengerHandIkTargetRight;
 425              end;
 426          end;
 427  
 428      else
 429          setActive(self.currentUser.playerCharacterSit, false);
 430      end;
 431  
 432      self.currentUser.playerSpatialBlend     = 0;
 433  
 434      if not isLocalPlayer then
 435          return;
 436      end;
 437      
 438      if g_currentVehicleSeat ~= nil then
 439          --g_currentVehicleSeat:onLeave();
 440          return;
 441      end;
 442  
 443      g_currentVehicleSeat            = self;
 444  
 445      self.seatActive                 = true;
 446      self.enteredOnSkis              = false;--g_scenario.player.skierController.isActive;
 447      
 448      self.activeCamera:activate();
 449  end;
 450  

VehicleSeat:onLeave(player, isLocalPlayer)

Is called when the player leave this particular seat. Do not call this to let the player leave the seat!

 453  function VehicleSeat:onLeave(player, isLocalPlayer)
 454      setActive(player.playerCharacterSit, false);
 455      
 456      -- set parent and bind player to seat
 457      setParent(player.playerCharacterSit, 0);
 458      setPosition(player.playerCharacterSit, 0,0,0);
 459      setRotation(player.playerCharacterSit, 0,0,0);
 460      
 461      player.footIkTargetLeft         = nil;
 462      player.footIkTargetRight        = nil;
 463      
 464      player.playerSpatialBlend       = 1;
 465      
 466      self.currentUser                = nil;
 467      
 468  
 469      if not isLocalPlayer then
 470          return;
 471      end;
 472  
 473      self.seatActive                 = false;
 474  
 475      if g_currentVehicleSeat ~= self then
 476          return;
 477      end;
 478      g_currentVehicleSeat            = nil;
 479      
 480      -- teleport player to our leave position
 481      local x,y,z                     = getWorldPosition(self.leaveNode);
 482  
 483      --[[if self.enteredOnSkis then
 484          g_scenario.player.skierController:moveToFeet(x,y,z);    
 485          g_scenario.player.skierController:setIsActive(true);
 486      else
 
 487          g_scenario.player:moveToFeet(x,y,z);
 488      --end;
 489  end;

VehicleSeat:selectCamera(slotNo)

Activates the specified camera slot slotNo (int, range 1-4).

 493  function VehicleSeat:selectCamera(slotNo)
 494      if self.selectedSlot == slotNo then
 495          -- turn one further
 496          local slot                  = self.cameraSlots[slotNo];
 497          self.selectedIndex          = self.selectedIndex + 1;
 498          self.selectedIndex          = self.selectedIndex > #slot and 1 or self.selectedIndex;
 499          self.activeCamera           = slot[self.selectedIndex];
 500          self.activeCamera:activate();
 501  
 502          
 503      elseif self.cameraSlots[slotNo] ~= nil then
 504          -- switch to that one
 505          local slot                  = self.cameraSlots[slotNo];
 506          self.selectedSlot           = slotNo;
 507          self.selectedIndex          = 1;
 508          self.activeCamera           = slot[self.selectedIndex];
 509          self.activeCamera:activate();
 510      end;
 511  
 512      self.isInterieurCamera          = self.activeCamera.isInterieur;
 513      
 514      -- change player character depending on the camera
 515      if self.currentUser ~= nil then
 516          setActive(self.currentUser.playerCharacterSit, not self.isInterieurCamera);
 517          
 518          Animator.setTrigger(self.currentUser.playerCharacterSit, self.characterPose);
 519      end;
 520  end;

VehicleSeat:update(dt)

Called every frame to update the seat and the active camera.

 524  function VehicleSeat:update(dt)
 525      if self.seatActive then
 526          
 527          self.activeCamera:update(dt);
 528          self.isInterieurCamera      = self.activeCamera.isInterieur;
 529  
 530          -- save the information about interior camera in player
 531          if self.currentUser ~= nil then
 532              self.currentUser.isInterieurCamera      = self.isInterieurCamera;
 533          end;
 534          
 535          if not g_GUI:getAnyGuiActive() then
 536              if      InputMapper:getKeyDown(InputMapper.InterieurCamera)     then        self:selectCamera(1);
 537              elseif  InputMapper:getKeyDown(InputMapper.ExterieurCamera)     then        self:selectCamera(2);
 538              elseif  InputMapper:getKeyDown(InputMapper.CustomCamera1)       then        self:selectCamera(3);
 539              elseif  InputMapper:getKeyDown(InputMapper.CustomCamera2)       then        self:selectCamera(4);
 540              end;
 541              
 542              -- finally check whether we're going to leave
 543              if InputMapper:getKeyDown(InputMapper.EnterSeat) then
 544                  self:localLeaveRequest(false);
 545              end;
 546  
 547              if self.updateCallback ~= nil then
 548                  self.updateCallback(self.updateCallbackObject, dt);
 549              end;
 550          end;
 551      end;
 552  end;

VehicleSeat:fixedUpdate(dt)

Called upon physics update.

 556  function VehicleSeat:fixedUpdate(dt)
 557      if self.seatActive then
 558          self.activeCamera:fixedUpdate(dt);
 559      end;
 560  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.