Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1 | -- Train class |
2 | -- |
3 | -- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved. |
4 | |
5 | Train = {} |
6 | |
7 | local Train_mt = Class(Train, Object); |
8 | |
9 | InitStaticObjectClass(Train, "Train", ObjectIds.OBJECT_TRAIN); |
10 | |
11 | function Train:onCreate(id) |
12 | local train = Train:new(g_server ~= nil, g_client ~= nil); |
13 | if train:load(id) then |
14 | g_currentMission:addOnCreateLoadedObject(train); |
15 | train:register(true); |
16 | else |
17 | train:delete(); |
18 | end; |
19 | end; |
20 | |
21 | function Train:new(isServer, isClient, mt) |
22 | local mt = customMt; |
23 | if mt == nil then |
24 | mt = Train_mt; |
25 | end; |
26 | |
27 | local self = Object:new(isServer, isClient, mt); |
28 | |
29 | return self; |
30 | end; |
31 | |
32 | function Train:load(id) |
33 | self.nodeId = id; |
34 | self.splineId = id; |
35 | |
36 | local xmlFileName = getUserAttribute(id, "xmlFilename"); |
37 | if xmlFileName == nil then |
38 | print("Warning: No Train 'xmlFilename' specified!"); |
39 | return nil; |
40 | end; |
41 | |
42 | xmlFileName = Utils.getFilename(xmlFileName, g_currentMission.loadingMapBaseDirectory); |
43 | local xmlFile = loadXMLFile("TrainConfigFile", xmlFileName); |
44 | if xmlFile == nil then |
45 | print("Warning: Could not open Train config file!"); |
46 | return nil; |
47 | end; |
48 | |
49 | local trainType = Utils.getNoNil(getUserAttribute(id, "trainType"), "grainTrain"); |
50 | local i=0; |
51 | local trainTypeKey = nil; |
52 | while true do |
53 | local key = string.format("trainSystem.train(%d)", i); |
54 | if (not hasXMLProperty(xmlFile, key)) then |
55 | break; |
56 | end; |
57 | |
58 | local currentTrainType = getXMLString(xmlFile, key .. "#type"); |
59 | if currentTrainType == trainType then |
60 | trainTypeKey = key; |
61 | break; |
62 | end; |
63 | i = i + 1; |
64 | end; |
65 | |
66 | if trainTypeKey == nil then |
67 | print("Warning: Traintype '"..trainType.."' not found in '"..xmlFileName.."'!"); |
68 | return nil; |
69 | end; |
70 | |
71 | self.isTrainStarted = false; |
72 | |
73 | self.fruitToVehicle = {}; |
74 | self.trainLength = 0; |
75 | self.train = {}; |
76 | self.trainTransform = createTransformGroup("trainRoot"); |
77 | link(getRootNode(), self.trainTransform); |
78 | local i = 0; |
79 | while true do |
80 | local key = string.format(trainTypeKey..".asset(%d)", i); |
81 | if (not hasXMLProperty(xmlFile, key)) then |
82 | break; |
83 | end; |
84 | local filename = getXMLString(xmlFile, key .. "#filename"); |
85 | |
86 | local root = Utils.loadSharedI3DFile(filename, g_currentMission.loadingMapBaseDirectory, false, true, false); |
87 | local vehicle = {}; |
88 | vehicle.filename = filename; |
89 | vehicle.id = getChildAt(root, 0); |
90 | link(self.trainTransform, vehicle.id); |
91 | delete(root); |
92 | vehicle.dir = Utils.getNoNil(getXMLInt(xmlFile, key.."#direction"), 1); |
93 | vehicle.length = Utils.getNoNil(getXMLFloat(xmlFile, key.."#length"), 2); |
94 | vehicle.wheels = {}; |
95 | vehicle.radius = getXMLFloat(xmlFile, key.."#wheelRadius"); |
96 | local numWheels = Utils.getNoNil(getXMLInt(xmlFile, key.."#numWheels"), 0); |
97 | for i=0, numWheels-1 do |
98 | if vehicle.radius == nil then |
99 | local _,y,_ = getTranslation(getChildAt(vehicle.id, i)); |
100 | vehicle.radius = y; |
101 | end; |
102 | table.insert(vehicle.wheels, getChildAt(vehicle.id, i)); |
103 | end; |
104 | |
105 | -- wood sell trigger directly on the train |
106 | local trainWoodSellTriggerIndex = getXMLString(xmlFile, key.."#woodSellTriggerIndex"); |
107 | if trainWoodSellTriggerIndex ~= nil then |
108 | local trainWoodSellTriggerNode = Utils.indexToObject(vehicle.id, trainWoodSellTriggerIndex); |
109 | self.trainWoodSellTrigger = WoodSellTrigger:new(trainWoodSellTriggerNode); |
110 | g_currentMission:addNonUpdateable(self.trainWoodSellTrigger); |
111 | self.trainWoodSellTrigger:addUpdateEventListener(self); |
112 | end; |
113 | |
114 | vehicle.fillLevels = {}; |
115 | local fillTypes = getXMLString(xmlFile, key.."#fillTypes"); |
116 | if fillTypes ~= nil then |
117 | local types = Utils.splitString(" ", fillTypes); |
118 | for _,fillTypeName in pairs(types) do |
119 | local desc = Fillable.fillTypeNameToDesc[fillTypeName]; |
120 | if desc ~= nil then |
121 | self.fruitToVehicle[desc.index] = vehicle; |
122 | vehicle.fillLevels[desc.index] = 0; |
123 | end; |
124 | end; |
125 | end; |
126 | |
127 | self.woodFillLevel = 0; -- for lumber trains which don't have a tip trigger |
128 | |
129 | setTranslation(vehicle.id, 0, 0, self.trainLength + (vehicle.length / 2)); |
130 | if vehicle.dir == -1 then |
131 | setRotation(vehicle.id, 0, math.pi, 0); |
132 | end; |
133 | self.trainLength = self.trainLength + vehicle.length; |
134 | table.insert(self.train, vehicle); |
135 | |
136 | i = i + 1; |
137 | end; |
138 | |
139 | -- attach sound to the last train wagon |
140 | self.trainSoundId = createAudioSource("train", "data/maps/sounds/train.wav", 160, 10, 1, 0); |
141 | local soundAttacherNode = self.trainTransform; |
142 | if getNumOfChildren(self.trainTransform) > 0 then |
143 | soundAttacherNode = getChildAt(self.trainTransform, getNumOfChildren(self.trainTransform) - 1); |
144 | end; |
145 | link(soundAttacherNode, self.trainSoundId); |
146 | setVisibility(self.trainSoundId, false); |
147 | |
148 | self.maxSpeed = Utils.getNoNil(getXMLFloat(xmlFile, trainTypeKey .. "#maxSpeed"), 20) / 3600; |
149 | self.maxAcceleration = Utils.getNoNil(getXMLFloat(xmlFile, trainTypeKey .. "#maxAcc"), 5) * 1000; |
150 | |
151 | self.endTime = 0; |
152 | self.endTimeOffset = Utils.getNoNil(getUserAttribute(id, "unloadingWaitTime"), 10) * 1000; |
153 | self.lastSpeed = 0; |
154 | self.startTimeOffset = 2000; |
155 | self.startTime = 0; |
156 | |
157 | self.doBrake = false; |
158 | self.direction = 1; |
159 | |
160 | self.currentTime = 0; |
161 | self.splineLength = getSplineLength(self.splineId); |
162 | self.startOffsetTime = self.trainLength/self.splineLength; |
163 | self.brakeTime = self.startOffsetTime / table.getn(self.train); |
164 | self:updateTrainPosition(self.startOffsetTime); |
165 | |
166 | local tipTriggerIndex = getUserAttribute(id, "tipTriggerIndex"); |
167 | if tipTriggerIndex ~= nil then |
168 | local tipTriggerNode = Utils.indexToObject(id, tipTriggerIndex); |
169 | self.tipTrigger = TipTrigger:new(self.isServer, self.isClient); |
170 | self.tipTrigger:load(tipTriggerNode); |
171 | g_currentMission:addOnCreateLoadedObject(self.tipTrigger); |
172 | self.tipTrigger:register(true); |
173 | self.tipTrigger:addUpdateEventListener(self); |
174 | end; |
175 | |
176 | -- wood sell trigger on the ground |
177 | local woodSellTriggerIndex = getUserAttribute(id, "woodSellTriggerIndex"); |
178 | if woodSellTriggerIndex ~= nil then |
179 | local woodSellTriggerNode = Utils.indexToObject(id, woodSellTriggerIndex); |
180 | self.woodSellTrigger = WoodSellTrigger:new(woodSellTriggerNode); |
181 | g_currentMission:addNonUpdateable(self.woodSellTrigger); |
182 | self.woodSellTrigger:addUpdateEventListener(self); |
183 | end; |
184 | |
185 | local triggerIndex = getUserAttribute(id, "triggerIndex"); |
186 | if triggerIndex ~= nil then |
187 | self.triggerId = Utils.indexToObject(id, triggerIndex); |
188 | if g_currentMission:getIsClient() then |
189 | addTrigger(self.triggerId, "triggerCallback", self); |
190 | end; |
191 | self.leverId = getChildAt(getChildAt(self.triggerId, 0), 0); |
192 | |
193 | self.leverSoundId = createAudioSource("lever", "data/maps/sounds/lever.wav", 8, 1, 1, 1); |
194 | link(self.leverId, self.leverSoundId); |
195 | setVisibility(self.leverSoundId, false); |
196 | |
197 | self.activateText = g_i18n:getText("SendOffTrain"); |
198 | self.isEnabled = true; |
199 | self.objectActivated = false; |
200 | end; |
201 | self.leverStarted = false; |
202 | self.leverTimer = 0; |
203 | |
204 | self.leverRotCurve = AnimCurve:new(linearInterpolator1); |
205 | self.leverRotCurve:addKeyframe({v=Utils.degToRad(0), time = 0}); |
206 | self.leverRotCurve:addKeyframe({v=Utils.degToRad(12), time = 250}); |
207 | self.leverRotCurve:addKeyframe({v=Utils.degToRad(20), time = 500}); |
208 | self.leverRotCurve:addKeyframe({v=Utils.degToRad(26), time = 750}); |
209 | self.leverRotCurve:addKeyframe({v=Utils.degToRad(30), time = 1000}); |
210 | self.leverRotCurve:addKeyframe({v=Utils.degToRad(10), time = 1500}); |
211 | self.leverRotCurve:addKeyframe({v=Utils.degToRad(0), time = 2000}); |
212 | |
213 | g_currentMission:addNodeObject(self.nodeId, self); |
214 | |
215 | g_currentMission:addOnCreateLoadedObjectToSave(self); |
216 | |
217 | return true; |
218 | end; |
219 | |
220 | function Train:delete() |
221 | g_currentMission:removeOnCreateLoadedObjectToSave(self); |
222 | |
223 | if g_currentMission:getIsClient() then |
224 | for _, vehicle in pairs(self.train) do |
225 | Utils.deleteParticleSystem(vehicle.exhaustParticleSystems); |
226 | Utils.releaseSharedI3DFile(vehicle.filename, g_currentMission.loadingMapBaseDirectory, true); |
227 | end; |
228 | if self.triggerId ~= nil then |
229 | removeTrigger(self.triggerId); |
230 | end; |
231 | if self.trainWoodSellTrigger ~= nil then |
232 | self.trainWoodSellTrigger:delete(); |
233 | end; |
234 | end; |
235 | |
236 | if (self.leverSoundId) then |
237 | stopSample(self.leverSoundId); |
238 | delete(self.leverSoundId); |
239 | self.leverSoundId = nil; |
240 | end; |
241 | |
242 | if (self.trainSoundId) then |
243 | stopSample(self.trainSoundId); |
244 | delete(self.trainSoundId); |
245 | self.trainSoundId = nil; |
246 | end; |
247 | |
248 | if self.trainTransform ~= nil then |
249 | delete(self.trainTransform); |
250 | end |
251 | |
252 | if self.nodeId ~= 0 then |
253 | g_currentMission:removeNodeObject(self.nodeId); |
254 | end; |
255 | g_currentMission:removeActivatableObject(self); |
256 | Train:superClass().delete(self); |
257 | end; |
258 | |
259 | function Train:readStream(streamId, connection) |
260 | Train:superClass().readStream(self, streamId, connection); |
261 | if connection:getIsServer() then |
262 | local isTrainStarted = streamReadBool(streamId); |
263 | if isTrainStarted then |
264 | self:startTrain(true); |
265 | self.lastSpeed = Utils.getNoNil(streamReadFloat32(streamId), 0); |
266 | self.currentTime = Utils.getNoNil(streamReadFloat32(streamId), self.currentTime); |
267 | self:updateTrainPosition(self.currentTime); |
268 | self.startTime = self.startTimeOffset + 1; -- make sure that train is driving |
269 | end; |
270 | end; |
271 | end; |
272 | |
273 | function Train:writeStream(streamId, connection) |
274 | Train:superClass().writeStream(self, streamId, connection); |
275 | if not connection:getIsServer() then |
276 | streamWriteBool(streamId, self.isTrainStarted) |
277 | if self.isTrainStarted then |
278 | streamWriteFloat32(streamId, self.lastSpeed); |
279 | streamWriteFloat32(streamId, self.currentTime); |
280 | end; |
281 | end; |
282 | end; |
283 | |
284 | function Train:update(dt) |
285 | if g_currentMission ~= nil and (self.startTime > self.startTimeOffset or self.endTime > self.endTimeOffset) then |
286 | -- handle braking and acceleration |
287 | if not self.doBrake then |
288 | self.lastSpeed = math.min(math.max(self.lastSpeed - dt/self.maxAcceleration, -1), 1); |
289 | else |
290 | if self.direction == 1 then |
291 | self.lastSpeed = self.startBrakeSpeed * math.max(0.1, (((1 - self.currentTime)/self.brakeTime)*0.8)); |
292 | else |
293 | self.lastSpeed = self.startBrakeSpeed * math.max(0.1, (((self.currentTime-self.startOffsetTime)/self.brakeTime)*0.8)); |
294 | end; |
295 | end; |
296 | |
297 | -- update train |
298 | local lastTime = Utils.clamp(self.currentTime + (self.maxSpeed/self.splineLength)*-self.lastSpeed*self.direction*dt, self.startOffsetTime, 1); |
299 | if lastTime <= 1 then |
300 | if lastTime ~= self.currentTime then |
301 | self:updateTrainPosition(lastTime); |
302 | end; |
303 | end; |
304 | else |
305 | if self.isTrainStarted then |
306 | if self.direction == 1 then |
307 | self.startTime = self.startTime + dt; |
308 | else |
309 | self.endTime = self.endTime + dt; |
310 | end; |
311 | end; |
312 | end; |
313 | |
314 | if g_currentMission ~= nil and self.leverStarted and self.leverId ~= nil then |
315 | local rx = self.leverRotCurve:get(self.leverTimer); |
316 | setRotation(self.leverId, rx, 0, 0); |
317 | self.leverTimer = self.leverTimer + dt; |
318 | if self.leverTimer > 2000 then |
319 | self.leverTimer = 0; |
320 | self.leverStarted = false; |
321 | setVisibility(self.leverSoundId, false); |
322 | end; |
323 | end; |
324 | |
325 | if g_currentMission ~= nil and self.endTime > self.endTimeOffset and self.isTrainStarted then |
326 | if not getVisibility(self.trainSoundId) then |
327 | setVisibility(self.trainSoundId, true); |
328 | end; |
329 | end; |
330 | |
331 | end; |
332 | |
333 | function Train:startTrain(noEventSend) |
334 | if not self.isTrainStarted then |
335 | TrainStartEvent.sendEvent(self, noEventSend); |
336 | self.startTime = 0; |
337 | self.doBrake = false; |
338 | self.isTrainStarted = true; |
339 | self.leverStarted = true; |
340 | setVisibility(self.leverSoundId, true); |
341 | setVisibility(self.trainSoundId, true); |
342 | self.leverTimer = 0; |
343 | self:setTriggersEnabled(false); |
344 | end; |
345 | end; |
346 | |
347 | function Train:updateTrainPosition(t) |
348 | local dt = self.currentTime - t; |
349 | local x, y, z = getSplinePosition(self.splineId, t); |
350 | local rx, ry, rz = getSplineOrientation(self.splineId, t, 0, -1, 0); |
351 | setTranslation(self.trainTransform, x, y, z); |
352 | setRotation(self.trainTransform, rx, ry, rz); |
353 | |
354 | local distance = dt * self.splineLength; |
355 | for _, vehicle in pairs(self.train) do |
356 | for _, wheel in pairs(vehicle.wheels) do |
357 | rotate(wheel, (1/vehicle.radius) * distance * vehicle.dir, 0, 0); |
358 | end; |
359 | end; |
360 | |
361 | self.currentTime = t; |
362 | |
363 | if self.direction == 1 then |
364 | if self.currentTime >= (1-self.brakeTime) then |
365 | if not self.doBrake then |
366 | self.startBrakeSpeed = self.lastSpeed; |
367 | end; |
368 | self.doBrake = true; |
369 | end; |
370 | if self.currentTime == 1 then |
371 | self.doBrake = false; |
372 | self.endTime = 0; |
373 | self.startTime = 0; |
374 | self.direction = self.direction * -1; |
375 | self:unloadTrain(); |
376 | setVisibility(self.trainSoundId, false); |
377 | end; |
378 | else |
379 | if self.currentTime <= (self.startOffsetTime+self.brakeTime) then |
380 | if not self.doBrake then |
381 | self.startBrakeSpeed = self.lastSpeed; |
382 | end; |
383 | self.doBrake = true; |
384 | end; |
385 | if self.currentTime == self.startOffsetTime then |
386 | if self.isTrainStarted then |
387 | self.doBrake = false; |
388 | self.endTime = 0; |
389 | self.startTime = 0; |
390 | self.direction = self.direction * -1; |
391 | setVisibility(self.trainSoundId, false); |
392 | end; |
393 | self.isTrainStarted = false; |
394 | self:setTriggersEnabled(true); |
395 | end; |
396 | end; |
397 | end; |
398 | |
399 | function Train:onUpdateEvent(trigger, fillDelta, fillType, trailer) |
400 | local vehicle = self.fruitToVehicle[fillType]; |
401 | if vehicle ~= nil then |
402 | if vehicle.fillLevels[fillType] ~= nil then |
403 | vehicle.fillLevels[fillType] = vehicle.fillLevels[fillType] - fillDelta; |
404 | end; |
405 | end; |
406 | end; |
407 | |
408 | function Train:onWoodSellingUpdateEvent(trigger, sellValue) |
409 | self.woodFillLevel = self.woodFillLevel + sellValue; |
410 | end; |
411 | |
412 | function Train:setTriggersEnabled(isEnabled) |
413 | if self.tipTrigger ~= nil then |
414 | self.tipTrigger.isEnabled = isEnabled; |
415 | end; |
416 | if self.woodSellTrigger ~= nil then |
417 | self.woodSellTrigger.isEnabled = isEnabled; |
418 | end; |
419 | if self.trainWoodSellTrigger ~= nil then |
420 | self.trainWoodSellTrigger.isEnabled = isEnabled; |
421 | end; |
422 | end; |
423 | |
424 | function Train:unloadTrain() |
425 | |
426 | local soldSomething = false; |
427 | |
428 | for _, vehicle in pairs(self.train) do |
429 | if vehicle.fillLevels ~= nil then |
430 | for fillType, fillLevel in pairs(vehicle.fillLevels) do |
431 | -- update total amount of this fill type |
432 | local desc = Fillable.fillTypeIndexToDesc[fillType]; |
433 | desc.totalAmount = desc.totalAmount + fillLevel; |
434 | |
435 | -- increase money according to price of current fill type |
436 | local priceMultiplier = 1; |
437 | local greatDemandMultiplier = 1; |
438 | local difficultyMultiplier = math.max(2 * (3 - g_currentMission.missionStats.difficulty), 1); -- 1 2 4 |
439 | |
440 | if vehicle.fillTrigger ~= nil then |
441 | priceMultiplier = vehicle.fillTrigger.priceMultipliers[fillType]; |
442 | -- check if a great demand pertaining to this fill type / station is currently running |
443 | local greatDemand = g_currentMission.economyManager:getCurrentGreatDemand(vehicle.fillTrigger.stationName, fillType); |
444 | if greatDemand ~= nil then |
445 | greatDemandMultiplier = greatDemand.demandMultiplier; |
446 | end; |
447 | end; |
448 | |
449 | local money = Fillable.fillTypeIndexToDesc[fillType].pricePerLiter * priceMultiplier * difficultyMultiplier * greatDemandMultiplier * fillLevel; |
450 | if self.isServer then |
451 | g_currentMission:addSharedMoney(money, "harvestIncome"); |
452 | g_currentMission:addMoneyChange(money, FSBaseMission.MONEY_TYPE_SINGLE, true); |
453 | end; |
454 | |
455 | vehicle.fillLevels[fillType] = 0; |
456 | |
457 | if money > 0 then soldSomething = true; end; |
458 | |
459 | end; |
460 | end; |
461 | end; |
462 | |
463 | if self.woodFillLevel > 0 then |
464 | if self.isServer then |
465 | g_currentMission:addSharedMoney(self.woodFillLevel, "harvestIncome"); |
466 | g_currentMission:addMoneyChange(self.woodFillLevel, FSBaseMission.MONEY_TYPE_SINGLE, true); |
467 | end; |
468 | self.woodFillLevel = 0; |
469 | soldSomething = true; |
470 | end; |
471 | |
472 | if soldSomething then |
473 | playSample(g_currentMission.cashRegistrySound, 1, 1, 0); |
474 | end; |
475 | |
476 | end; |
477 | |
478 | function Train:getIsActivatable() |
479 | return self.isEnabled and g_currentMission.controlPlayer and self.currentTime == self.startOffsetTime and not self.isTrainStarted; |
480 | end; |
481 | |
482 | function Train:drawActivate() |
483 | return; |
484 | end; |
485 | |
486 | function Train:onActivateObject() |
487 | self.objectActivated = true; |
488 | g_currentMission:addActivatableObject(self); |
489 | self:startTrain(); |
490 | end; |
491 | |
492 | function Train:loadFromAttributesAndNodes(xmlFile, key) |
493 | local isTrainStarted = Utils.getNoNil(getXMLBool(xmlFile, key .."#isTrainStarted"), false); |
494 | if isTrainStarted then |
495 | self:startTrain(true); |
496 | self.lastSpeed = Utils.getNoNil(getXMLFloat(xmlFile, key.."#lastSpeed"), 0); |
497 | self.currentTime = Utils.getNoNil(getXMLFloat(xmlFile, key.."#currentTime"), self.currentTime); |
498 | self.direction = Utils.getNoNil(getXMLInt(xmlFile, key.."#direction"), self.direction); |
499 | self:updateTrainPosition(self.currentTime); |
500 | self.startTime = self.startTimeOffset + 1; -- make sure that train is driving |
501 | end; |
502 | |
503 | for i, vehicle in pairs(self.train) do |
504 | if vehicle.fillLevels ~= nil then |
505 | local vehicleKey = key..string.format(".vehicle%d", i); |
506 | local fillLevels = getXMLString(xmlFile, vehicleKey .. "#fillLevels"); |
507 | if fillLevels ~= nil then |
508 | local levels = Utils.splitString(" ", fillLevels); |
509 | local i = 1; |
510 | for fillType, level in pairs(vehicle.fillLevels) do |
511 | vehicle.fillLevels[fillType] = levels[i]; |
512 | i = i + 1; |
513 | end; |
514 | end; |
515 | end; |
516 | end; |
517 | |
518 | self.woodFillLevel = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".wood#fillLevel"), 0); |
519 | |
520 | return true; |
521 | end; |
522 | |
523 | function Train:getSaveAttributesAndNodes(nodeIdent) |
524 | local attributes = 'isTrainStarted="'..tostring(self.isTrainStarted)..'" currentTime="'..self.currentTime..'" direction="'..self.direction..'" lastSpeed="'..self.lastSpeed..'"'; |
525 | local nodes = ""; |
526 | for i, vehicle in pairs(self.train) do |
527 | if i>1 then |
528 | nodes = nodes.."\n"; |
529 | end; |
530 | local fillLevels = ""; |
531 | if vehicle.fillLevels ~= nil then |
532 | local j = 0; |
533 | for _, level in pairs(vehicle.fillLevels) do |
534 | if j > 0 then |
535 | fillLevels = fillLevels .. " "; |
536 | end; |
537 | fillLevels = fillLevels .. level; |
538 | j = j + 1; |
539 | end; |
540 | fillLevels = 'fillLevels="'..fillLevels..'"'; |
541 | end; |
542 | nodes = nodes.. nodeIdent..'<vehicle'..i..' '..fillLevels..' />'; |
543 | end; |
544 | |
545 | nodes = nodes .. '\n' .. nodeIdent .. '<wood fillLevel="' .. self.woodFillLevel .. '" />'; |
546 | |
547 | return attributes, nodes; |
548 | end; |
549 | |
550 | function Train:triggerCallback(triggerId, otherId, onEnter, onLeave, onStay) |
551 | if self.isEnabled then |
552 | if onEnter or onLeave then |
553 | if g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then |
554 | if onEnter then |
555 | if not self.objectActivated then |
556 | g_currentMission:addActivatableObject(self); |
557 | self.objectActivated = true; |
558 | end |
559 | else |
560 | if self.objectActivated then |
561 | g_currentMission:removeActivatableObject(self); |
562 | self.objectActivated = false; |
563 | end |
564 | end; |
565 | end; |
566 | end; |
567 | end; |
568 | end;
|
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de