meta data for this page
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 awayenableRwTimescale
(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, nil, true); 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, self.savegameKey); 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 if g_scenario ~= nil then 109 g_scenario:removeObject(self, self.savegameKey); 110 end; 111 112 ControlElement.destroy(self.buttonId); 113 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.
117 function DoorController:saveToTable(savegame) 118 if savegame[self.savegameKey] ~= nil then 119 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."); 120 return; 121 end; 122 savegame[self.savegameKey] = self.state; 123 end;
DoorController:loadFromTable(savegame)
Retrieves the information stored in the savegame and applies it to the door.
127 function DoorController:loadFromTable(savegame) 128 if savegame == nil then return end; 129 130 local state = savegame[self.savegameKey]; 131 if state ~= nil then 132 self:setState(state, true, true); 133 end; 134 end;
DoorController:setState(state, jump, noEvent)
Sets the state of the door controller.
state
(bool):true
if the door shall be open, otherwisefalse
.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)
).
143 function DoorController:setState(state, jump, noEvent) 144 self.state = state; 145 self.targetPosition = self.state and self.animLength or 0; 146 147 -- jump there 148 if jump then 149 self.position = self.targetPosition; 150 Animation.sampleTime(self.doorId, self.position); 151 end; 152 153 ControlElement.setName(self.buttonId, self.state and self.textOff or self.textOn); 154 155 g_scenario:resumeUpdatingObject(self); 156 157 if self.soundConfiguration ~= nil then 158 for k, v in pairs(self.soundConfiguration) do 159 if v.triggerOnPress then 160 AudioSource.play(v.id); 161 end; 162 end; 163 end; 164 165 if not noEvent then 166 EventDoorController:send(self, state, jump); 167 end; 168 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)
).
172 function DoorController:update(dt) 173 if g_isMaster and self.doorCloser and GameplaySettings.autoCloseDoors and self.state then 174 local closeDoor = true; 175 local doorPosition = VectorUtils.getWorldPosition(self.doorId); 176 177 -- if any player is close the door, we shall not close it 178 if g_isServer then 179 for k, player in pairs (g_networkGame.players) do 180 local isNear = player:getIsActive() and player:getSqrDistanceToVector(doorPosition) < 25; 181 if isNear then 182 closeDoor = false; 183 break; 184 end; 185 end; 186 187 elseif g_scenario.player ~= nil then 188 -- must be singleplayer, here we only have one player 189 closeDoor = g_scenario.player:getSqrDistanceToVector(doorPosition) >= 25; 190 end; 191 192 if closeDoor then 193 self:setState(false); 194 end; 195 end; 196 197 if self.position == self.targetPosition then 198 if g_isClient or not (self.doorCloser and GameplaySettings.autoCloseDoors and self.state) then 199 g_scenario:pauseUpdatingObject(self); 200 end; 201 return; 202 end; 203 204 -- we need to move 205 if self.enableRwTimescale then 206 dt = dt * g_scenario.environment.activeRwTimescale; 207 end; 208 local oldPosition = self.position; 209 self.position = Utils.moveTowards(self.position, self.targetPosition, dt); 210 211 -- update sounds 212 if self.soundConfiguration ~= nil then 213 local direction = oldPosition < self.position and 1 or 2; 214 for k, v in pairs(self.soundConfiguration) do 215 216 if v.triggerTime ~= nil and v.direction == direction then 217 if (oldPosition <= v.triggerTime and self.position >= v.triggerTime) or (oldPosition >= v.triggerTime and self.position <= v.triggerTime) then 218 AudioSource.play(v.id); 219 end; 220 end; 221 end; 222 end; 223 224 225 Animation.sampleTime(self.doorId, self.position); 226 end; 227
DoorController:writeResync()
Resynchronizes all variables when a new player joins the game. The data sent by writeResync
will be received by readResync
.
231 function DoorController:writeResync() 232 streamWriteBool(self.state); 233 end; 234
DoorController:readResync()
Resynchronizes all variables when a new player joins the game. The data sent by writeResync
will be received by readResync
.
238 function DoorController:readResync() 239 local state = streamReadBool(); 240 self:setState(state, true, true); 241 end;
Copyright
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.