336 | function Trailer:endTipping(noEventSend) |
337 | local spec = self.spec_trailer |
338 | |
339 | local tipSide = spec.tipSides[spec.currentTipSideIndex] |
340 | if tipSide ~= nil then |
341 | if tipSide.doorAnimation.name ~= nil then |
342 | if tipSide.doorAnimation.delayedClosing then |
343 | local animTime = self:getAnimationTime(tipSide.doorAnimation.name) |
344 | self:playAnimation(tipSide.doorAnimation.name, -tipSide.doorAnimation.speedScale, animTime, true) |
345 | end |
346 | end |
347 | end |
348 | |
349 | spec.tipState = Trailer.TIPSTATE_CLOSED |
350 | spec.currentTipSideIndex = nil |
351 | |
352 | SpecializationUtil.raiseEvent(self, "onEndTipping") |
353 | end |
363 | function Trailer:getDischargeNodeEmptyFactor(superFunc, dischargeNode) |
364 | local spec = self.spec_trailer |
365 | local tipSide = spec.dischargeNodeIndexToTipSide[dischargeNode.index] |
366 | |
367 | if tipSide ~= nil then |
368 | if tipSide.animation.name ~= nil and tipSide.animation.startTipTime ~= 0 then |
369 | -- log(self:getAnimationTime(tipSide.animation.name), tipSide.animation.startTipTime ) |
370 | if self:getAnimationTime(tipSide.animation.name) < tipSide.animation.startTipTime then |
371 | return 0 |
372 | end |
373 | end |
374 | |
375 | if tipSide.doorAnimation.name ~= nil and tipSide.doorAnimation.startTipTime ~= 0 then |
376 | if self:getAnimationTime(tipSide.doorAnimation.name) < tipSide.doorAnimation.startTipTime then |
377 | return 0 |
378 | end |
379 | end |
380 | |
381 | return tipSide.currentEmptyFactor |
382 | end |
383 | |
384 | return superFunc(self, dischargeNode) |
385 | end |
504 | function Trailer:getIsNextCoverStateAllowed(superFunc, nextState) |
505 | local spec = self.spec_trailer |
506 | |
507 | if spec.currentTipSideIndex ~= nil then |
508 | local tipSide = spec.tipSides[spec.currentTipSideIndex] |
509 | local dischargeNode = self:getDischargeNodeByIndex(tipSide.dischargeNodeIndex) |
510 | |
511 | local cover = self:getCoverByFillUnitIndex(dischargeNode.fillUnitIndex) |
512 | if cover ~= nil then |
513 | if nextState ~= cover.index then |
514 | return false |
515 | end |
516 | end |
517 | end |
518 | |
519 | return superFunc(self, nextState) |
520 | end |
407 | function Trailer:initializeAnimationPart(superFunc, animation, part, i, numParts) |
408 | |
409 | superFunc(self, animation, part, i, numParts) |
410 | |
411 | -- find the next tipSideEmptyFactor part |
412 | if part.endTipSideEmptyFactor ~= nil then |
413 | for j=i+1, numParts do |
414 | local part2 = animation.parts[j] |
415 | if part.node == part2.node and part2.endTipSideEmptyFactor ~= nil then |
416 | if part.startTime + part.duration > part2.startTime+0.001 then |
417 | g_logManager:xmlWarning(self.configFileName, "Overlapping tipSideEmptyFactor parts for node '%s' in animation '%s'", getName(part.node), animation.name) |
418 | end |
419 | part.nextTipSideEmptyFactorPart = part2 |
420 | part2.prevTipSideEmptyFactorPart = part |
421 | if part2.startTipSideEmptyFactor == nil then |
422 | part2.startTipSideEmptyFactor = {part.endTipSideEmptyFactor[1], part.endTipSideEmptyFactor[2], part.endTipSideEmptyFactor[3]} |
423 | end |
424 | break |
425 | end |
426 | end |
427 | end |
428 | end |
389 | function Trailer:loadAnimationPart(superFunc, xmlFile, partKey, part) |
390 | if not superFunc(self, xmlFile, partKey, part) then |
391 | return false |
392 | end |
393 | |
394 | local startTipSideEmptyFactor = getXMLFloat(xmlFile, partKey.."#startTipSideEmptyFactor") |
395 | local endTipSideEmptyFactor = getXMLFloat(xmlFile, partKey.."#endTipSideEmptyFactor") |
396 | |
397 | if startTipSideEmptyFactor ~= nil and endTipSideEmptyFactor ~= nil then |
398 | part.startTipSideEmptyFactor = startTipSideEmptyFactor |
399 | part.endTipSideEmptyFactor = endTipSideEmptyFactor |
400 | end |
401 | |
402 | return true |
403 | end |
205 | function Trailer:loadTipSide(xmlFile, key, entry) |
206 | local name = getXMLString(xmlFile, key .. "#name") |
207 | entry.name = g_i18n:convertText(name, self.customEnvironment) |
208 | if entry.name == nil then |
209 | g_logManager:xmlWarning(self.configFileName, "Given tipSide name '%s' not found for '%s'!", tostring(name), key) |
210 | return false |
211 | end |
212 | |
213 | entry.dischargeNodeIndex = Utils.getNoNil(getXMLInt(xmlFile, key .. "#dischargeNodeIndex"), 1) |
214 | entry.canTipIfEmpty = Utils.getNoNil(getXMLBool(xmlFile, key .. "#canTipIfEmpty"), true) |
215 | |
216 | entry.animation = {} |
217 | entry.animation.name = getXMLString(xmlFile, key .. ".animation#name") |
218 | if entry.animation.name == nil then |
219 | g_logManager:xmlWarning(self.configFileName, "Missing animation name for '%s'!", key) |
220 | return false |
221 | end |
222 | entry.animation.speedScale = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".animation#speedScale"), 1.0) |
223 | entry.animation.startTipTime = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".animation#startTipTime"), 0) |
224 | |
225 | entry.doorAnimation = {} |
226 | entry.doorAnimation.name = getXMLString(xmlFile, key .. ".doorAnimation#name") |
227 | entry.doorAnimation.speedScale = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".doorAnimation#speedScale"), 1.0) |
228 | entry.doorAnimation.startTipTime = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".doorAnimation#startTipTime"), 0) |
229 | entry.doorAnimation.delayedClosing = Utils.getNoNil(getXMLBool(xmlFile, key .. ".doorAnimation#delayedClosing"), false) |
230 | |
231 | if self.isClient then |
232 | entry.animationNodes = g_animationManager:loadAnimations(self.xmlFile, key..".animationNodes", self.components, self, self.i3dMappings) |
233 | end |
234 | |
235 | entry.currentEmptyFactor = 1 |
236 | |
237 | return true |
238 | end |
84 | function Trailer:onLoad(savegame) |
85 | local spec = self.spec_trailer |
86 | |
87 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.tipScrollerNodes.tipScrollerNode", "vehicle.trailer.trailerConfigurations.trailerConfiguration.trailer.tipSide.animationNodes.animationNode") --FS17 to FS19 |
88 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.tipRotationNodes.tipRotationNode", "vehicle.trailer.trailerConfigurations.trailerConfiguration.trailer.tipSide.animationNodes.animationNode") --FS17 to FS19 |
89 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.tipAnimations.tipAnimation", "vehicle.trailer.trailerConfigurations.trailerConfiguration.trailer.tipSide") --FS17 to FS19 |
90 | |
91 | |
92 | local trailerConfigurationId = Utils.getNoNil(self.configurations["trailer"], 1) |
93 | local configKey = string.format("vehicle.trailer.trailerConfigurations.trailerConfiguration(%d).trailer", trailerConfigurationId -1) |
94 | ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.trailer.trailerConfigurations.trailerConfiguration", trailerConfigurationId , self.components, self) |
95 | |
96 | spec.tipSides = {} |
97 | spec.dischargeNodeIndexToTipSide = {} |
98 | local i = 0 |
99 | while true do |
100 | local key = string.format("%s.tipSide(%d)", configKey, i) |
101 | if not hasXMLProperty(self.xmlFile, key) then |
102 | break |
103 | end |
104 | |
105 | local entry = {} |
106 | if self:loadTipSide(self.xmlFile, key, entry) then |
107 | table.insert(spec.tipSides, entry) |
108 | spec.dischargeNodeIndexToTipSide[entry.dischargeNodeIndex] = entry |
109 | end |
110 | i = i + 1 |
111 | end |
112 | |
113 | spec.tipSideCount = table.getn(spec.tipSides) |
114 | spec.preferedTipSideIndex = 1 |
115 | spec.currentTipSideIndex = nil |
116 | |
117 | spec.tipState = Trailer.TIPSTATE_CLOSED |
118 | |
119 | spec.remainingFillDelta = 0 |
120 | |
121 | if spec.tipSideCount > 1 and savegame ~= nil then |
122 | local tipSideIndex = getXMLInt(savegame.xmlFile, savegame.key..".trailer#tipSideIndex") |
123 | if tipSideIndex ~= nil then |
124 | self:setPreferedTipSide(tipSideIndex, true) |
125 | end |
126 | end |
127 | end |
530 | function Trailer:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
531 | if self.isClient then |
532 | local spec = self.spec_trailer |
533 | if spec.tipSideCount < 2 then |
534 | return |
535 | end |
536 | |
537 | self:clearActionEventsTable(spec.actionEvents) |
538 | |
539 | if isActiveForInputIgnoreSelection then |
540 | local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_TIPSIDE, self, Trailer.actionEventToggleTipSide, false, true, false, true, nil) |
541 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL) |
542 | end |
543 | end |
544 | end |
166 | function Trailer:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
167 | local spec = self.spec_trailer |
168 | |
169 | if spec.tipSideCount > 1 then |
170 | local actionEvent = spec.actionEvents[InputAction.TOGGLE_TIPSIDE] |
171 | if actionEvent ~= nil then |
172 | local state = self:getCanTogglePreferdTipSide() |
173 | g_inputBinding:setActionEventActive(actionEvent.actionEventId, state) |
174 | |
175 | if state then |
176 | local text = string.format( g_i18n:getText("action_toggleTipSide"), spec.tipSides[spec.preferedTipSideIndex].name ) |
177 | g_inputBinding:setActionEventText(actionEvent.actionEventId, text) |
178 | end |
179 | end |
180 | end |
181 | |
182 | -- update tipState |
183 | if spec.tipState == Trailer.TIPSTATE_OPENING then |
184 | local tipSide = spec.tipSides[spec.currentTipSideIndex] |
185 | if tipSide ~= nil then |
186 | local animTime = self:getAnimationTime(tipSide.animation.name) |
187 | if animTime >= 1.0 then |
188 | spec.tipState = Trailer.TIPSTATE_OPEN |
189 | end |
190 | end |
191 | elseif spec.tipState == Trailer.TIPSTATE_CLOSING then |
192 | local tipSide = spec.tipSides[spec.currentTipSideIndex] |
193 | if tipSide ~= nil then |
194 | local animTime = self:getAnimationTime(tipSide.animation.name) |
195 | if animTime <= 0.0 then |
196 | spec.tipState = Trailer.TIPSTATE_CLOSED |
197 | self:endTipping() |
198 | end |
199 | end |
200 | end |
201 | end |
66 | function Trailer.registerEventListeners(vehicleType) |
67 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Trailer) |
68 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", Trailer) |
69 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Trailer) |
70 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Trailer) |
71 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Trailer) |
72 | SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Trailer) |
73 | SpecializationUtil.registerEventListener(vehicleType, "onDischargeStateChanged", Trailer) |
74 | end |
40 | function Trailer.registerFunctions(vehicleType) |
41 | SpecializationUtil.registerFunction(vehicleType, "loadTipSide", Trailer.loadTipSide) |
42 | SpecializationUtil.registerFunction(vehicleType, "getCanTogglePreferdTipSide", Trailer.getCanTogglePreferdTipSide) |
43 | SpecializationUtil.registerFunction(vehicleType, "setPreferedTipSide", Trailer.setPreferedTipSide) |
44 | SpecializationUtil.registerFunction(vehicleType, "startTipping", Trailer.startTipping) |
45 | SpecializationUtil.registerFunction(vehicleType, "stopTipping", Trailer.stopTipping) |
46 | SpecializationUtil.registerFunction(vehicleType, "endTipping", Trailer.endTipping) |
47 | SpecializationUtil.registerFunction(vehicleType, "getTipState", Trailer.getTipState) |
48 | end |
52 | function Trailer.registerOverwrittenFunctions(vehicleType) |
53 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDischargeNodeEmptyFactor", Trailer.getDischargeNodeEmptyFactor) |
54 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadAnimationPart", Trailer.loadAnimationPart) |
55 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "initializeAnimationPart", Trailer.initializeAnimationPart) |
56 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "postInitializeAnimationPart", Trailer.postInitializeAnimationPart) |
57 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "updateAnimationPart", Trailer.updateAnimationPart) |
58 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "resetAnimationPartValues", Trailer.resetAnimationPartValues) |
59 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanDischargeToGround", Trailer.getCanDischargeToGround) |
60 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsNextCoverStateAllowed", Trailer.getIsNextCoverStateAllowed) |
61 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", Trailer.getCanBeSelected) |
62 | end |
259 | function Trailer:setPreferedTipSide(index, noEventSend) |
260 | local spec = self.spec_trailer |
261 | index = math.max(1, math.min(spec.tipSideCount, index)) |
262 | |
263 | if index ~= spec.preferedTipSideIndex then |
264 | if spec.tipSideCount > 1 then |
265 | if noEventSend == nil or noEventSend == false then |
266 | if g_server ~= nil then |
267 | g_server:broadcastEvent(TrailerToggleTipSideEvent:new(self, index), nil, nil, self) |
268 | else |
269 | g_client:getServerConnection():sendEvent(TrailerToggleTipSideEvent:new(self, index)) |
270 | end |
271 | end |
272 | end |
273 | end |
274 | |
275 | spec.preferedTipSideIndex = index |
276 | local tipSide = spec.tipSides[index] |
277 | self:setCurrentDischargeNodeIndex(tipSide.dischargeNodeIndex) |
278 | end |
282 | function Trailer:startTipping(tipSideIndex, noEventSend) |
283 | local spec = self.spec_trailer |
284 | local tipSide = spec.tipSides[tipSideIndex] |
285 | if tipSide ~= nil then |
286 | local animTime = self:getAnimationTime(tipSide.animation.name) |
287 | |
288 | self:playAnimation(tipSide.animation.name, tipSide.animation.speedScale, animTime, true) |
289 | |
290 | if tipSide.doorAnimation.name ~= nil then |
291 | local animTime = self:getAnimationTime(tipSide.doorAnimation.name) |
292 | self:playAnimation(tipSide.doorAnimation.name, tipSide.doorAnimation.speedScale, animTime, true) |
293 | end |
294 | |
295 | g_animationManager:startAnimations(tipSide.animationNodes) |
296 | |
297 | spec.tipState = Trailer.TIPSTATE_OPENING |
298 | spec.currentTipSideIndex = tipSideIndex |
299 | |
300 | self:setCurrentDischargeNodeIndex(tipSide.dischargeNodeIndex) |
301 | |
302 | spec.remainingFillDelta = 0 |
303 | |
304 | SpecializationUtil.raiseEvent(self, "onStartTipping", tipSideIndex) |
305 | end |
306 | end |
310 | function Trailer:stopTipping(noEventSend) |
311 | local spec = self.spec_trailer |
312 | local tipSide = spec.tipSides[spec.currentTipSideIndex] |
313 | if tipSide ~= nil then |
314 | local animTime = self:getAnimationTime(tipSide.animation.name) |
315 | self:playAnimation(tipSide.animation.name, -tipSide.animation.speedScale, animTime, true) |
316 | |
317 | if tipSide.doorAnimation.name ~= nil then |
318 | if not tipSide.doorAnimation.delayedClosing then |
319 | local animTime = self:getAnimationTime(tipSide.doorAnimation.name) |
320 | self:playAnimation(tipSide.doorAnimation.name, -tipSide.doorAnimation.speedScale, animTime, true) |
321 | end |
322 | end |
323 | |
324 | g_animationManager:stopAnimations(tipSide.animationNodes) |
325 | |
326 | spec.tipState = Trailer.TIPSTATE_CLOSING |
327 | |
328 | spec.remainingFillDelta = 0 |
329 | |
330 | SpecializationUtil.raiseEvent(self, "onStopTipping") |
331 | end |
332 | end |
443 | function Trailer:updateAnimationPart(superFunc, animation, part, durationToEnd, dtToUse, realDt) |
444 | local spec = self.spec_trailer |
445 | |
446 | local hasPartChanged = superFunc(self, animation, part, durationToEnd, dtToUse, realDt) |
447 | |
448 | if part.startTipSideEmptyFactor ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextTipSideEmptyFactorPart, part.prevTipSideEmptyFactorPart, animation, true)) then |
449 | local destFactor = part.endTipSideEmptyFactor |
450 | if animation.currentSpeed < 0 then |
451 | destFactor = part.startTipSideEmptyFactor |
452 | end |
453 | if part.tipSide == nil then |
454 | local dischargeNode = self:getDischargeNodeByNode(part.node) |
455 | local tipSide = spec.dischargeNodeIndexToTipSide[dischargeNode.index] |
456 | if tipSide == nil then |
457 | g_logManager:xmlWarning(self.configFileName, "Could not update discharge emptyFactor. No tipSide defined for node '%s'!", getName(part.node)) |
458 | part.startTipSideEmptyFactor = nil |
459 | return hasPartChanged |
460 | end |
461 | |
462 | part.tipSide = tipSide |
463 | local invDuration = 1.0/math.max(durationToEnd, 0.001) |
464 | part.speedEmptyFactor = (destFactor-tipSide.currentEmptyFactor)*invDuration |
465 | end |
466 | |
467 | local newValue = AnimatedVehicle.getMovedLimitedValue(part.tipSide.currentEmptyFactor, destFactor, part.speedEmptyFactor, dtToUse) |
468 | if newValue then |
469 | part.tipSide.currentEmptyFactor = newValue |
470 | hasPartChanged = true |
471 | end |
472 | end |
473 | |
474 | return hasPartChanged |
475 | end |