Objects/DoorController.lua

This script is used for all static in-game doors (i.e. all doors except vehicle or ropeway carrier doors). In theory, you can also use the script on vehicles, but we recommend to use AnimatedParts instead in that case.

  24  DoorController                      = DoorController or {};
  25  local DoorControllerClass           = Class(DoorController);

DoorController:load(collisionId, doorId, textOn, textOff, doorCloser, enableRwTimescale, soundConfiguration)

Gets called for each new DoorController, i.e. by the onCreate event.

  • collisionId (transform id): Object id of the door collision. This will be the control element of the door (which can be clicked by the player).
  • doorId (transform id): Object id of the Animation component. Make sure this is not the same object as the collision, i.e. collision and Animation must be separated.
  • textOn (string): Text that will be shown when the player hovers the collision and the door is closed (animation position = 0 %).
  • textOff (string): Text that will be shown when the player hovers the collision and the door is opened (animation position = 100 %).
  • doorCloser (optional bool): true if the door should close itself automatically if the player is more than 2 metres away
  • enableRwTimescale (optional bool): true if the door should be accelerated by ropeway timescale (will not be accelerated otherwise)
  • soundConfiguration (optional datatable): Configuration of sounds that should be played if the player interacts with the door. This is usually a lot of work and not necessary for mods.
  37  function DoorController:load(collisionId, doorId, textOn, textOff, doorCloser, enableRwTimescale, soundConfiguration)
  38      -- first store the main id
  39      self.collisionId                = collisionId;
  40      self.doorId                     = doorId;
  41      self.animLength                 = Animation.getLength(self.doorId);
  42      Animation.setAutoPlay(self.doorId, false);
  43  
  44      local x,y,z                     = getWorldPosition(doorId);
  45      self.savegameKey                = "doorController" .. string.format(":%s @ (%.4f, %.4f, %.4f)", getName(self.doorId), x,y,z);
  46      
  47      self.textOn                     = l10n.getDollar(textOn or "");
  48      self.textOff                    = l10n.getDollar(textOff or textOn);
  49      
  50      self.state                      = false;
  51      self.position                   = 0;
  52      self.enableRwTimescale          = enableRwTimescale; -- defines whether the door is influenced by the ropeway timescale (false or nil: real time only, not depending on timescale)
  53      self.targetPosition             = self.state and self.animLength or 0;
  54      self.doorCloser                 = getNoNil(doorCloser, true); -- closes the door automatically if player is more than 2 metres away
  55  
  56      if soundConfiguration ~= nil then
  57          self.soundConfiguration     = {};
  58  
  59          for n, v in pairs(soundConfiguration) do
  60              -- get all audio source lengths
  61              if
  62                  v.id ~= nil and v.id ~= 0 and
  63                  (v.triggerTime ~= nil or v.finishTime ~= nil)
  64              then
  65                  local tbl           = {};
  66                  tbl.id              = v.id;
  67                  tbl.direction       = getNoNil(v.direction,     1);     -- 1: state 0=>1, 2: state 1=>0
  68  
  69                  if v.triggerOnPress then
  70                      tbl.triggerOnPress  = true;
  71  
  72                  elseif v.triggerTime ~= nil then
  73                      tbl.triggerTime     = v.triggerTime;    -- time in seconds!
  74  
  75                  else
  76                      tbl.triggerTime     = (v.finishTime - AudioSource.getLength(tbl.id) * (tbl.direction == 1 and 1 or -1));
  77                  end;
  78                  
  79                  if tbl.triggerTime ~= nil then
  80                      tbl.triggerTime     =   clamp(tbl.triggerTime, 0, self.animLength);
  81                  end;
  82  
  83                  AudioSource.stop(tbl.id);
  84                  table.insert(self.soundConfiguration, tbl);
  85              end;
  86          end;
  87      end;
  88      
  89      Animation.sampleTime(self.doorId, self.position);
  90      
  91      if self.collisionId == 0 then
  92          print("Error while loading Door " .. tostring(getName(self.doorId)) .. ". Collision index is invalid.");
  93      end;
  94      self.buttonId                   = ControlElement.new(self.collisionId);
  95      ControlElement.setCallback(self.buttonId, 1, function() self:setState(not self.state); end);
  96      
  97      self:setState(false);
  98  
  99      -- load the state from savegame
 100      -- we will also be registered to a destroy listener
 101      -- BUT as always: we will have to deregister the object ourselves
 102      g_scenario:addObjectAndLoad(self, self.doorId);
 103  end;

DoorController:destroy()

Is called if the door is destroyed (e.g. if the ropeway or prefab containing the door is deleted).

 107  function DoorController:destroy()
 108      g_scenario:removeObject(self);
 109  end;

DoorController:saveToTable(savegame)

Saves the door state to the savegame. Note that this method is designed for static prefabs (used in in-game editor prefabs or ropeways), but not for physics-dependent objects (e.g. vehicles, carriers). This is also the reason why we recommend not to use DoorController inside vehicles.

 113  function DoorController:saveToTable(savegame)
 114      if savegame[self.savegameKey] ~= nil then
 115          print("Warning while saving to table: Multiple DoorControllers are using the key " .. tostring(self.savegameKey) .. ". All of them will have the same state when loading the savegame. Please avoid DoorControllers that are named the same and placed at the same spot.");
 116          return;
 117      end;
 118      savegame[self.savegameKey]      = self.state;
 119  end;

DoorController:loadFromTable(savegame)

Retrieves the information stored in the savegame and applies it to the door.

 123  function DoorController:loadFromTable(savegame)
 124      if savegame == nil then return end;
 125      
 126      local state                     = savegame[self.savegameKey];
 127      if state ~= nil then
 128          self:setState(state, true);
 129      end;
 130  end;

DoorController:setState(state, jump)

Sets the state of the door controller.

  • state (bool): true if the door shall be open, otherwise false.
  • jump (optional bool): true if you want the door to jump to the new position.

If necessary, updating the object is resumed (g_scenario:resumeUpdatingObject(self)).

 138  function DoorController:setState(state, jump)
 139      self.state                      = state;
 140      self.targetPosition             = self.state and self.animLength or 0;
 141  
 142      -- jump there
 143      if jump then
 144          self.position               = self.targetPosition;
 145          Animation.sampleTime(self.doorId, self.position);
 146      end;
 147  
 148      ControlElement.setName(self.buttonId, self.state and self.textOff or self.textOn);
 149  
 150      g_scenario:resumeUpdatingObject(self);
 151  
 152      if self.soundConfiguration ~= nil then
 153          for k, v in pairs(self.soundConfiguration) do
 154              if v.triggerOnPress then
 155                  AudioSource.play(v.id);
 156              end;
 157          end;
 158      end;
 159  end;

DoorController:update(dt)

Update function for updating the animation and handling the door closer (depending on self.doorCloser and the gameplay settings). If the call is no longer necessary (e.g. if no animation is taking place any more), the object will no longer be updated (g_scenario:pauseUpdatingObject(self)).

 163  function DoorController:update(dt)
 164      if self.doorCloser and GameplaySettings.autoCloseDoors and self.state then
 165          -- close door if player is too far away
 166          if (VectorUtils.getWorldPosition(g_scenario.player.transformId) - VectorUtils.getWorldPosition(self.doorId)):sqrMagnitude() > 25 then
 167              self:setState(false);
 168          end;
 169      end;
 170      
 171      if self.position == self.targetPosition then
 172          
 173          if not (self.doorCloser and GameplaySettings.autoCloseDoors and self.state) then
 174              g_scenario:pauseUpdatingObject(self);
 175          end;
 176          return;
 177      end;
 178      
 179      -- we need to move
 180      if self.enableRwTimescale then
 181          dt                          = dt * g_scenario.environment.activeRwTimescale;
 182      end;
 183      local oldPosition               = self.position;
 184      self.position                   = Utils.moveTowards(self.position, self.targetPosition, dt);
 185  
 186      -- update sounds
 187      if self.soundConfiguration ~= nil then
 188          local direction             = oldPosition < self.position and 1 or 2;
 189          for k, v in pairs(self.soundConfiguration) do
 190              
 191              if v.triggerTime ~= nil and v.direction == direction then
 192                  if (oldPosition <= v.triggerTime and self.position >= v.triggerTime) or (oldPosition >= v.triggerTime and self.position <= v.triggerTime) then
 193                      AudioSource.play(v.id);
 194                  end;
 195              end;
 196          end;
 197      end;
 198  
 199  
 200      Animation.sampleTime(self.doorId, self.position);
 201  end;

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

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