35 | function Pipe:load(savegame) |
36 | self.getIsTurnedOnAllowed = Utils.overwrittenFunction(self.getIsTurnedOnAllowed, Pipe.getIsTurnedOnAllowed); |
37 | self.getTurnedOnNotAllowedWarning = Utils.overwrittenFunction(self.getTurnedOnNotAllowedWarning, Pipe.getTurnedOnNotAllowedWarning); |
38 | self.getAutomaticOverloadingState = Utils.overwrittenFunction(self.getAutomaticOverloadingState, Pipe.getAutomaticOverloadingState); |
39 | |
40 | self.getCanTipToGround = Pipe.getCanTipToGround; |
41 | self.setDischargeToGround = SpecializationUtil.callSpecializationsFunction("setDischargeToGround"); |
42 | |
43 | self.doOverload = Utils.overwrittenFunction(self.doOverload, Pipe.doOverload); |
44 | |
45 | self.getIsFoldAllowed = Utils.overwrittenFunction(self.getIsFoldAllowed, Pipe.getIsFoldAllowed); |
46 | self.getIsOverloadingAllowed = Utils.overwrittenFunction(self.getIsOverloadingAllowed, Pipe.getIsOverloadingAllowed); |
47 | self.findValidTrailer = Utils.overwrittenFunction(self.findValidTrailer, Pipe.findValidTrailer); |
48 | |
49 | self.getIsPipeStateChangeAllowed = Pipe.getIsPipeStateChangeAllowed; |
50 | self.setPipeState = SpecializationUtil.callSpecializationsFunction("setPipeState"); |
51 | self.findTrailerRaycastCallback = Pipe.findTrailerRaycastCallback; |
52 | self.updatePipe = Pipe.updatePipe; |
53 | |
54 | self.setActiveControlGroup = Utils.overwrittenFunction(self.setActiveControlGroup, Pipe.setActiveControlGroup); |
55 | self.getNextValidControlGroupIndex = Utils.overwrittenFunction(self.getNextValidControlGroupIndex, Pipe.getNextValidControlGroupIndex); |
56 | self.getIsControlGroupChangeAllowed = Utils.overwrittenFunction(self.getIsControlGroupChangeAllowed, Pipe.getIsControlGroupChangeAllowed); |
57 | |
58 | self.pipeFoldMinTime = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.pipe#foldMinTime"), 0); |
59 | self.pipeFoldMaxTime = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.pipe#foldMaxTime"), 1); |
60 | |
61 | self.pipeFoldMinState = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.pipe#foldMinState"), 0); |
62 | self.pipeFoldMaxState = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.pipe#foldMaxState"), 7); |
63 | if self.pipeFoldMaxState > 7 then |
64 | print("Warning: pipe#foldMaxState must have a value between 0 and 7"); |
65 | end |
66 | |
67 | self.pipeNodes = {}; |
68 | self.pipeNumStates = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.pipe#numStates"), 0); |
69 | self.pipeCurrentState = 1; |
70 | self.pipeTargetState = 1; |
71 | self.pipeStateIsUnloading = {}; |
72 | self.pipeStateIsAutoAiming = {}; |
73 | local unloadingPipeStates = Utils.getVectorNFromString(getXMLString(self.xmlFile, "vehicle.pipe#unloadingStates")); |
74 | if unloadingPipeStates ~= nil then |
75 | for i=1, table.getn(unloadingPipeStates) do |
76 | if unloadingPipeStates[i] ~= nil then |
77 | self.pipeStateIsUnloading[unloadingPipeStates[i] ] = true; |
78 | end |
79 | end |
80 | end |
81 | local autoAimPipeStates = Utils.getVectorNFromString(getXMLString(self.xmlFile, "vehicle.pipe#autoAimStates")); |
82 | if autoAimPipeStates ~= nil then |
83 | for i=1, table.getn(autoAimPipeStates) do |
84 | if autoAimPipeStates[i] ~= nil then |
85 | self.pipeStateIsAutoAiming[autoAimPipeStates[i] ] = true; |
86 | end |
87 | end |
88 | end |
89 | local i = 0; |
90 | while true do |
91 | local key = string.format("vehicle.pipe.node(%d)", i); |
92 | if not hasXMLProperty(self.xmlFile, key) then |
93 | break; |
94 | end |
95 | local node = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#index")); |
96 | if node ~= nil then |
97 | local entry = {}; |
98 | entry.node = node; |
99 | entry.autoAimXRotation = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#autoAimXRotation"), false); |
100 | entry.autoAimYRotation = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#autoAimYRotation"), false); |
101 | entry.autoAimInvertZ = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#autoAimInvertZ"), false); |
102 | entry.states = {}; |
103 | for state=1,self.pipeNumStates do |
104 | local stateKey = key..string.format(".state%d", state); |
105 | entry.states[state] = {}; |
106 | local x,y,z = Utils.getVectorFromString(getXMLString(self.xmlFile, stateKey.."#translation")); |
107 | if x == nil or y == nil or z == nil then |
108 | x,y,z = getTranslation(node); |
109 | else |
110 | if state == 1 then |
111 | setTranslation(node, x,y,z); |
112 | end |
113 | end |
114 | entry.states[state].translation = {x,y,z}; |
115 | local x,y,z = Utils.getVectorFromString(getXMLString(self.xmlFile, stateKey.."#rotation")); |
116 | if x == nil or y == nil or z == nil then |
117 | x,y,z = getRotation(node); |
118 | else |
119 | x,y,z = math.rad(x),math.rad(y),math.rad(z); |
120 | if state == 1 then |
121 | setRotation(node, x,y,z); |
122 | end |
123 | end |
124 | entry.states[state].rotation = {x,y,z}; |
125 | end |
126 | local x,y,z = Utils.getVectorFromString(getXMLString(self.xmlFile, key.."#translationSpeeds")); |
127 | if x ~= nil and y ~= nil and z ~= nil then |
128 | x,y,z = x*0.001,y*0.001,z*0.001; |
129 | if x ~= 0 or y ~= 0 or z ~= 0 then |
130 | entry.translationSpeeds = {x,y,z}; |
131 | end |
132 | end |
133 | local x,y,z = Utils.getVectorFromString(getXMLString(self.xmlFile, key.."#rotationSpeeds")); |
134 | if x ~= nil and y ~= nil and z ~= nil then |
135 | x,y,z = math.rad(x)*0.001,math.rad(y)*0.001,math.rad(z)*0.001; |
136 | if x ~= 0 or y ~= 0 or z ~= 0 then |
137 | entry.rotationSpeeds = {x,y,z}; |
138 | end |
139 | end |
140 | |
141 | local x,y,z = getTranslation(node); |
142 | entry.curTranslation = {x,y,z}; |
143 | local x,y,z = getRotation(node); |
144 | entry.curRotation = {x,y,z}; |
145 | table.insert(self.pipeNodes, entry); |
146 | end |
147 | i = i + 1; |
148 | end |
149 | |
150 | self.pipeAnimation = getXMLString(self.xmlFile, "vehicle.pipe#animName"); |
151 | self.pipeAnimSpeedScale = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.pipe#animSpeedScale"), 1); |
152 | if self.pipeAnimation ~= nil then |
153 | local targetTime = 0; |
154 | if self.pipeAnimSpeedScale < 0 then |
155 | targetTime = 1; |
156 | end |
157 | self:playAnimation(self.pipeAnimation, -self.pipeAnimSpeedScale, nil, true); |
158 | self:setAnimationTime(self.pipeAnimation, targetTime); |
159 | end |
160 | |
161 | self.pipeRaycastNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.pipe#raycastNodeIndex")); |
162 | self.pipeRaycastDistance = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.pipe#raycastDistance"), 7); |
163 | self.pipeUnloadingDistance = 0; |
164 | self.pipeParticleSystemExtraDistance = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.pipe#effectExtraDistance"), 1); |
165 | self.pipeParticleSystemExtraDistanceOnTrailer = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.pipe#effectExtraDistanceOnTrailer"), 0); |
166 | |
167 | self.pipeDischargeInfoIndex = getXMLInt(self.xmlFile, "vehicle.pipe#dischargeInfoIndex"); |
168 | |
169 | self.trailerFound = 0; |
170 | self.pipeFoundTrailer = false; |
171 | self.sentPipeFoundTrailer = false; |
172 | self.trailerFoundDistance = 0; |
173 | |
174 | self.hasPipe = self.pipeRaycastNode ~= nil; |
175 | |
176 | |
177 | if self.isClient then |
178 | self.pipeParticleSystems = {}; |
179 | local i=0; |
180 | while true do |
181 | local key = string.format("vehicle.pipeParticleSystems.emitterShape(%d)", i); |
182 | if not hasXMLProperty(self.xmlFile, key) then |
183 | break |
184 | end |
185 | |
186 | local emitterShape = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#node")); |
187 | local particleType = getXMLString(self.xmlFile, key.."#particleType") |
188 | if emitterShape ~= nil then |
189 | for _,fillUnit in pairs(self.fillUnits) do |
190 | for fillType,_ in pairs(fillUnit.fillTypes) do |
191 | local particleSystem = MaterialUtil.getParticleSystem(fillType, particleType) |
192 | if particleSystem ~= nil then |
193 | if self.pipeParticleSystems[fillType] == nil then |
194 | self.pipeParticleSystems[fillType] = {} |
195 | end |
196 | |
197 | local currentPS = ParticleUtil.copyParticleSystem(self.xmlFile, key, particleSystem, emitterShape) |
198 | local ps = currentPS |
199 | local normalSpeed,tangentSpeed = ParticleUtil.getParticleSystemAverageSpeed(ps); |
200 | ps.speed = math.sqrt(normalSpeed*normalSpeed + tangentSpeed*tangentSpeed); |
201 | |
202 | table.insert(self.pipeParticleSystems[fillType], currentPS) |
203 | end |
204 | end |
205 | end |
206 | end |
207 | |
208 | i=i+1; |
209 | end |
210 | |
211 | self.pipeEffects = EffectManager:loadEffect(self.xmlFile, "vehicle.pipeEffect", self.components, self); |
212 | self.pipeTurnedOnRotationNodes = Utils.loadRotationNodes(self.xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "pipe", self.components); |
213 | self.pipeScrollers = Utils.loadScrollers(self.components, self.xmlFile, "vehicle.pipeScrollers.pipeScroller", {}, true); |
214 | |
215 | local i = 0 |
216 | while true do |
217 | local key = string.format("vehicle.pipe.offset(%d)", i); |
218 | if not hasXMLProperty(self.xmlFile, key) then |
219 | break |
220 | end |
221 | |
222 | local movingToolNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#movingToolNode")) |
223 | if movingToolNode ~= nil and self.nodesToMovingTools[movingToolNode] ~= nil then |
224 | if self.pipeOffsets == nil then |
225 | self.pipeOffsets = {} |
226 | end |
227 | |
228 | local offset = {} |
229 | offset.movingTool = self.nodesToMovingTools[movingToolNode] |
230 | offset.effects = {} |
231 | local j = 0 |
232 | while true do |
233 | local effectKey = string.format(key..".effect(%d)", j); |
234 | if not hasXMLProperty(self.xmlFile, effectKey) then |
235 | break |
236 | end |
237 | |
238 | local effectIndex = Utils.getNoNil(getXMLInt(self.xmlFile, effectKey.."#index"), 0) |
239 | if self.pipeEffects[effectIndex] ~= nil and self.pipeEffects[effectIndex].setOffset ~= nil and self.pipeEffects[effectIndex].setDelays ~= nil then |
240 | local effect = {} |
241 | effect.effect = self.pipeEffects[effectIndex] |
242 | effect.minValue = Utils.getNoNil(getXMLFloat(self.xmlFile, effectKey.."#minValue"), 0) |
243 | effect.maxValue = Utils.getNoNil(getXMLFloat(self.xmlFile, effectKey.."#maxValue"), 1) |
244 | local minDelay = getXMLFloat(self.xmlFile, effectKey.."#minDelay") |
245 | local maxDelay = getXMLFloat(self.xmlFile, effectKey.."#maxDelay") |
246 | effect.minDelay = Utils.getNoNil(minDelay, effect.effect.startDelay)*1000 |
247 | effect.maxDelay = Utils.getNoNil(maxDelay, effect.effect.startDelay)*1000 |
248 | effect.adjustDelay = minDelay ~= nil and maxDelay ~= nil |
249 | effect.inverted = Utils.getNoNil(getXMLBool(self.xmlFile, effectKey.."#inverted"), false) |
250 | table.insert(offset.effects, effect) |
251 | end |
252 | j = j + 1 |
253 | end |
254 | |
255 | table.insert(self.pipeOffsets, offset) |
256 | end |
257 | i = i + 1 |
258 | end |
259 | end |
260 | |
261 | local effectIndex = getXMLInt(self.xmlFile, "vehicle.pipe#delayEffectIndex") |
262 | if effectIndex ~= nil and self.pipeEffects[effectIndex] ~= nil then |
263 | self.delayEffect = self.pipeEffects[effectIndex] |
264 | end |
265 | |
266 | |
267 | self.pipeBaseDelay = self.overloading.delay.time; |
268 | self.pipeUnloadingGroundStartTime = -1; |
269 | self.pipeUnloadingStartTime = -1; |
270 | self.pipeScrollerEndTime = -1; |
271 | |
272 | self.pipeParticleDeactivateTime = -1; |
273 | self.pipeUnloadEffectStopTime = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.pipe#unloadingEffectStopTime"), 0.25) * 1000; |
274 | |
275 | self.allowDischargeToGround = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.pipe#allowDischargeToGround"), true); |
276 | self.dischargeToGround = false; |
277 | self.remainingFillLevelToGround = 0; |
278 | self.limitDischargeToPipeHeight = false; |
279 | |
280 | self.isSelectable = true; |
281 | |
282 | self.pipeTurnOnAllowedStates = { Utils.getVectorFromString(getXMLString(self.xmlFile, "vehicle.pipe#turnOnAllowedStates")) }; |
283 | self.pipeTurnOnStateWarning = string.format(g_i18n:getText(Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.pipe#unfoldWarning"), "warning_firstSetPipeState")), self.typeDesc); |
284 | |
285 | self.pipeDisableManualMovement = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.pipe#disableManualMovement"), true); |
286 | self.pipeControlGroupName = Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.pipe#controlGroup"), "pipe"); |
287 | |
288 | self.pipeAutomaticOverload = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.pipe#automaticOverload"), true); |
289 | if self.pipeAutomaticOverload then |
290 | self.overloading.canToggleOverloading = false; |
291 | end |
292 | |
293 | self.pipeDirtyFlag = self:getNextDirtyFlag(); |
294 | self.pipeTargetDirtyFlag = self:getNextDirtyFlag(); |
295 | |
296 | self:addConflictCheckedInput(InputBinding.TOGGLE_PIPE); |
297 | |
298 | self.groundUnloadingPosition = {0,0,0}; |
299 | self.groundUnloadingPipeEffect = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.pipe#groundUnloadingPipeEffect"), 1); |
300 | end |
473 | function Pipe:updateTick(dt) |
474 | -- if a trailer was found, check (and adjust) control group of cylindered |
475 | if self.isServer and self.hasPipe then --and self:getIsActive() then |
476 | |
477 | if self.pipeStateIsUnloading[self.pipeCurrentState] and self.trailerFound ~= 0 and self.pipeDisableManualMovement then |
478 | |
479 | if self.numControlGroups ~= nil and self.numControlGroups > 1 then |
480 | |
481 | local activeGroup = self.controlGroups[self.activeControlGroupIndex]; |
482 | if activeGroup.groupName == self.pipeControlGroupName then |
483 | |
484 | local nextIndex = self:getNextValidControlGroupIndex(); |
485 | if nextIndex ~= self.activeControlGroupIndex then |
486 | self:setActiveControlGroup(nextIndex); |
487 | end |
488 | end |
489 | end |
490 | end |
491 | |
492 | self.pipeFoundTrailer = false; |
493 | |
494 | if not self:getOverloadingActive() then |
495 | self:stopOverloadingDelay(); |
496 | end; |
497 | end |
498 | |
499 | if self.isServer then |
500 | if (self:getUnitFillLevel(self.overloading.fillUnitIndex) > 0 or self:getUnitCapacity(self.overloading.fillUnitIndex) == 0) and self.pipeStateIsUnloading[self.pipeCurrentState] then |
501 | |
502 | if self.pipeEffects ~= nil then |
503 | if self.pipeEffects[self.groundUnloadingPipeEffect] ~= nil then |
504 | local controlPointY = self.pipeEffects[self.groundUnloadingPipeEffect].controlPointY; |
505 | local distance = self.pipeEffects[self.groundUnloadingPipeEffect].distance; |
506 | |
507 | if controlPointY ~= nil and distance ~= nil and controlPointY ~= 0 then |
508 | local mCos = math.cos(controlPointY); |
509 | local mSin = math.sin(controlPointY); |
510 | |
511 | local y = Utils.dotProduct(0, 0, distance, 0.0, mCos, -mSin); |
512 | local z = Utils.dotProduct(0, 0, distance, 0.0, mSin, mCos); |
513 | |
514 | if self.pipeStateIsUnloading[self.pipeTargetState] then |
515 | local x, y, z = localToWorld(self.pipeEffects[self.groundUnloadingPipeEffect].node, 0, y, z); |
516 | self.groundUnloadingPosition = {x, y, z}; |
517 | end; |
518 | end; |
519 | end; |
520 | end; |
521 | |
522 | -- do raycast |
523 | self.trailerFound = 0; |
524 | self.shovelTargetFound = nil; |
525 | self.trailerFoundDistance = 0; |
526 | if self.pipeRaycastNode ~= nil then |
527 | local doRaycast = self.pipeStateIsUnloading[self.pipeTargetState]; |
528 | |
529 | if doRaycast then |
530 | local x,y,z = getWorldTranslation(self.pipeRaycastNode); |
531 | local dx,dy,dz = localDirectionToWorld(self.pipeRaycastNode, 0,-1,0); |
532 | raycastAll(x, y, z, dx,dy,dz, "findTrailerRaycastCallback", self.pipeRaycastDistance, self); |
533 | end |
534 | |
535 | if self.trailerFoundDistance == 0 then |
536 | self.trailerFound = 0; |
537 | end; |
538 | |
539 | if self.targetTrailer ~= nil then |
540 | if self.targetTrailer.coverAnimation ~= nil then |
541 | if not self.targetTrailer.isCoverOpen then |
542 | self.trailerFound = 0; |
543 | end; |
544 | end; |
545 | end; |
546 | end |
547 | |
548 | if self.trailerFound ~= 0 or self.shovelTargetFound ~= nil then |
549 | if self.dischargeToGround then |
550 | self:setDischargeToGround(false); |
551 | end |
552 | else |
553 | if self.dischargeToGround then |
554 | if not self:getCanTipToGround() or (self.overloading.stopOverloadIfEmpty and (self:getUnitLastValidFillType(self.overloading.fillUnitIndex) == FillUtil.FILLTYPE_UNKNOWN or self:getUnitFillLevel(self.overloading.fillUnitIndex) == 0)) then |
555 | self:setDischargeToGround(false); |
556 | end |
557 | end |
558 | end |
559 | |
560 | if self.dischargeToGround then |
561 | if self:getUnitFillLevel(self.overloading.fillUnitIndex) > 0 and not self:getOverloadingDelayIsActive() then |
562 | self:startOverloadingDelay(); |
563 | end; |
564 | |
565 | local node = self.pipeRaycastNode; |
566 | if self.pipeDischargeInfoIndex ~= nil then |
567 | node = self.fillVolumeDischargeInfos[self.pipeDischargeInfoIndex].nodes[1].node; |
568 | end; |
569 | |
570 | local speed = 10; |
571 | local x,y,z = Utils.getIntersectionOfLinearMovementAndTerrain(node, speed); |
572 | local x0,y0,z0 = getWorldTranslation(node); |
573 | self.pipeUnloadingDistance = Utils.vector3Length(x0-x, y0-y, z0-z); |
574 | |
575 | if self.groundUnloadingPosition[1] ~= 0 then |
576 | x,y,z = unpack(self.groundUnloadingPosition); |
577 | end; |
578 | |
579 | if self:getAllowDelayedUnloading() then |
580 | local fillType = self:getUnitLastValidFillType(self.overloading.fillUnitIndex); |
581 | local fillLevel = self:getUnitFillLevel(self.overloading.fillUnitIndex); |
582 | |
583 | local deltaFill = fillLevel; |
584 | if self.lastLostFillLevel ~= nil then |
585 | deltaFill = math.max(fillLevel, self.lastLostFillLevel); |
586 | end |
587 | |
588 | if self:getUnitCapacity(self.overloading.fillUnitIndex) > 0 then |
589 | deltaFill = math.min(deltaFill, self.overloading.capacity*dt/1000.0); |
590 | end |
591 | |
592 | self.remainingFillLevelToGround = math.min(self.remainingFillLevelToGround + deltaFill, math.max(self.overloading.capacity*dt/1000.0, TipUtil.getMinValidLiterValue(fillType))); |
593 | |
594 | if self.remainingFillLevelToGround > 0 then |
595 | local infos = self.fillVolumeDischargeInfos[self.overloading.dischargeInfoIndex]; |
596 | local dx,dy,dz; |
597 | if infos ~= nil then |
598 | dx,dy,dz = localDirectionToWorld(infos.nodes[1].node, infos.nodes[1].width,0,0); |
599 | else |
600 | dx,dy,dz = localDirectionToWorld(self.components[1].node, 0,0,0.25); |
601 | end |
602 | |
603 | local sx, sy, sz = x+dx, y+dy, z+dz; |
604 | local ex, ey, ez = x-dx, y-dy, z-dz; |
605 | |
606 | if self.limitDischargeToPipeHeight then |
607 | if infos ~= nil then |
608 | local _,y,_ = localToWorld(infos.nodes[1].node, infos.nodes[1].width,0,0); |
609 | sy = y; |
610 | local _,y,_ = localToWorld(infos.nodes[1].node, -infos.nodes[1].width,0,0); |
611 | ey = y; |
612 | else |
613 | local _,y,_ = getWorldTranslation(self.pipeRaycastNode); |
614 | sy = y; |
615 | ey = y; |
616 | end |
617 | else |
618 | end |
619 | |
620 | local dropped, lineOffset = TipUtil.tipToGroundAroundLine(self, self.remainingFillLevelToGround, fillType, sx,sy,sz, ex,ey,ez, 0.1, nil, self.tipToGroundLineOffset, self.limitDischargeToPipeHeight, self.tipOcclusionAreas); |
621 | |
622 | self.tipToGroundLineOffset = lineOffset; |
623 | |
624 | self.remainingFillLevelToGround = self.remainingFillLevelToGround - dropped; |
625 | self:setUnitFillLevel(self.overloading.fillUnitIndex, fillLevel - dropped, fillType, false, self.fillVolumeUnloadInfos[self.overloading.unloadInfoIndex]); |
626 | self.overloading.didOverload = dropped > 0; |
627 | end |
628 | end; |
629 | |
630 | if not self:getCanTipToGround() or (self.overloading.stopOverloadIfEmpty and (self:getUnitLastValidFillType(self.overloading.fillUnitIndex) == FillUtil.FILLTYPE_UNKNOWN or self:getUnitFillLevel(self.overloading.fillUnitIndex) == 0)) then |
631 | self:setDischargeToGround(false); |
632 | end |
633 | elseif not self.dischargeToGround and self.overloading.isActive then |
634 | self.pipeUnloadingDistance = self.trailerFoundDistance; |
635 | end |
636 | else |
637 | self.trailerFound = 0; |
638 | self.shovelTargetFound = nil; |
639 | |
640 | -- stop discharge to ground if pipe gets folden |
641 | if self.dischargeToGround and (not self.pipeStateIsUnloading[self.pipeCurrentState] or (self.overloading.stopOverloadIfEmpty and (self:getUnitLastValidFillType(self.overloading.fillUnitIndex) == FillUtil.FILLTYPE_UNKNOWN or self:getUnitFillLevel(self.overloading.fillUnitIndex) == 0))) then |
642 | self:setDischargeToGround(false); |
643 | end |
644 | end |
645 | end; |
646 | |
647 | if self.isServer then |
648 | if self.pipeUnloadingDistance ~= self.sentPipeUnloadingDistance or self.sentPipeFoundTrailer ~= self.pipeFoundTrailer then |
649 | self:raiseDirtyFlags(self.pipeDirtyFlag); |
650 | |
651 | self.sentPipeUnloadingDistance = self.pipeUnloadingDistance; |
652 | self.sentPipeFoundTrailer = self.pipeFoundTrailer; |
653 | end |
654 | end |
655 | |
656 | if self.isClient then |
657 | self.overloading.delay.time = self.pipeBaseDelay |
658 | if self.delayEffect ~= nil then |
659 | self.overloading.delay.time = self.delayEffect.startDelay + (1-self.delayEffect.offset)*self.delayEffect.fadeInTime |
660 | end |
661 | if self:getIsActiveForInput(self) then |
662 | if self.pipeOffsets ~= nil then |
663 | for _, offset in pairs(self.pipeOffsets) do |
664 | local movingTool = offset.movingTool |
665 | local state = Cylindered.getMovingToolState(self, movingTool); |
666 | |
667 | for _, effect in pairs(offset.effects) do |
668 | local effectState = state |
669 | if effect.inverted then |
670 | effectState = 1 - effectState |
671 | end |
672 | effect.effect:setOffset(Utils.lerp(effect.minValue, effect.maxValue, effectState)) |
673 | if effect.adjustDelay then |
674 | local delay = Utils.lerp(effect.minDelay, effect.maxDelay, effectState) |
675 | effect.effect:setDelays(delay, delay) |
676 | end |
677 | end |
678 | end |
679 | end |
680 | end |
681 | |
682 | if self:getAllowDelayEffects() and (self.pipeFoundTrailer or self.dischargeToGround or self.shovelTargetFound ~= nil) then |
683 | self.pipeParticleDeactivateTime = g_currentMission.time + self.pipeUnloadEffectStopTime; |
684 | |
685 | local currentPipeParticleSystems = self.pipeParticleSystems[self:getUnitLastValidFillType(self.overloading.fillUnitIndex)]; |
686 | if currentPipeParticleSystems ~= self.currentPipeParticleSystems then |
687 | if self.currentPipeParticleSystems ~= nil then |
688 | for _, ps in pairs(self.currentPipeParticleSystems) do |
689 | ParticleUtil.setEmittingState(ps, false) |
690 | end |
691 | end |
692 | self.currentPipeParticleSystems = currentPipeParticleSystems |
693 | if self.currentPipeParticleSystems ~= nil then |
694 | for _, ps in pairs(self.currentPipeParticleSystems) do |
695 | ParticleUtil.setEmittingState(ps, true) |
696 | end |
697 | end |
698 | end |
699 | |
700 | if self.currentPipeParticleSystems ~= nil then |
701 | for _, currentPS in pairs(self.currentPipeParticleSystems) do |
702 | local ps = currentPS |
703 | if not ps.forceFullLifespan then |
704 | local factor = 1+((8-self.pipeUnloadingDistance-self.pipeParticleSystemExtraDistance)/15); |
705 | local lifespan = ps.originalLifespan * (self.pipeUnloadingDistance+self.pipeParticleSystemExtraDistance) * factor; |
706 | ParticleUtil.setParticleLifespan(ps, lifespan) |
707 | end |
708 | end |
709 | end |
710 | |
711 | if self.pipeEffects ~= nil then |
712 | EffectManager:setFillType(self.pipeEffects, self:getUnitLastValidFillType(self.overloading.fillUnitIndex)) |
713 | EffectManager:startEffects(self.pipeEffects) |
714 | end |
715 | end |
716 | |
717 | if self.pipeEffects ~= nil then |
718 | for _, effect in pairs(self.pipeEffects) do |
719 | if effect.setUnloadingDistance ~= nil then |
720 | effect:setUnloadingDistance(self.pipeUnloadingDistance+self.pipeParticleSystemExtraDistance, g_currentMission.terrainRootNode) |
721 | end |
722 | end; |
723 | end |
724 | |
725 | if self.pipeParticleDeactivateTime >= 0 and self.pipeParticleDeactivateTime <= g_currentMission.time then |
726 | self.pipeParticleDeactivateTime = -1; |
727 | if self.currentPipeParticleSystems ~= nil then |
728 | for _, ps in pairs(self.currentPipeParticleSystems) do |
729 | ParticleUtil.setEmittingState(ps, false) |
730 | end |
731 | self.currentPipeParticleSystems = nil; |
732 | end |
733 | |
734 | if self.pipeEffects ~= nil then |
735 | EffectManager:stopEffects(self.pipeEffects); |
736 | end |
737 | end |
738 | end |
739 | end |
1117 | function Pipe:updatePipe(dt, trailer) |
1118 | if (self.pipeCurrentState ~= self.pipeTargetState or (trailer ~= nil and trailer.getAllowFillFromAir ~= nil and trailer:getAllowFillFromAir())) and self.pipeTargetState <= self.pipeNumStates then |
1119 | local doAutoAiming = trailer ~= nil and entityExists(trailer.components[1].node) and self.pipeStateIsAutoAiming[self.pipeCurrentState]; |
1120 | local autoAimX, autoAimY, autoAimZ; |
1121 | if doAutoAiming then |
1122 | autoAimX, autoAimY, autoAimZ = getWorldTranslation(trailer.fillAutoAimTarget.node); |
1123 | end |
1124 | |
1125 | local moved = false; |
1126 | for i=1, table.getn(self.pipeNodes) do |
1127 | local nodeMoved = false; |
1128 | local pipeNode = self.pipeNodes[i]; |
1129 | |
1130 | local state = pipeNode.states[self.pipeTargetState]; |
1131 | if pipeNode.translationSpeeds ~= nil then |
1132 | for i=1, 3 do |
1133 | if math.abs(pipeNode.curTranslation[i] - state.translation[i]) > 0.000001 then |
1134 | nodeMoved = true; |
1135 | if pipeNode.curTranslation[i] < state.translation[i] then |
1136 | pipeNode.curTranslation[i] = math.min(pipeNode.curTranslation[i] + dt*pipeNode.translationSpeeds[i], state.translation[i]); |
1137 | else |
1138 | pipeNode.curTranslation[i] = math.max(pipeNode.curTranslation[i] - dt*pipeNode.translationSpeeds[i], state.translation[i]); |
1139 | end |
1140 | end |
1141 | end |
1142 | setTranslation(pipeNode.node, pipeNode.curTranslation[1],pipeNode.curTranslation[2],pipeNode.curTranslation[3]) |
1143 | end |
1144 | if pipeNode.rotationSpeeds ~= nil then |
1145 | for i=1, 3 do |
1146 | local targetRotation = state.rotation[i]; |
1147 | if doAutoAiming then |
1148 | if pipeNode.autoAimXRotation and i == 1 then |
1149 | local x,y,z = getWorldTranslation(pipeNode.node); |
1150 | local _,y,z = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, autoAimY-y, autoAimZ-z); |
1151 | targetRotation = -math.atan2(y,z); |
1152 | if pipeNode.autoAimInvertZ then |
1153 | targetRotation = targetRotation+math.pi; |
1154 | end |
1155 | targetRotation = Utils.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[i]); |
1156 | elseif pipeNode.autoAimYRotation and i == 2 then |
1157 | local x,y,z = getWorldTranslation(pipeNode.node); |
1158 | local x,_,z = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, autoAimY-y, autoAimZ-z); |
1159 | targetRotation = math.atan2(x,z); |
1160 | if pipeNode.autoAimInvertZ then |
1161 | targetRotation = targetRotation+math.pi; |
1162 | end |
1163 | targetRotation = Utils.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[i]); |
1164 | end |
1165 | end |
1166 | if math.abs(pipeNode.curRotation[i] - targetRotation) > 0.000001 then |
1167 | nodeMoved = true; |
1168 | if pipeNode.curRotation[i] < targetRotation then |
1169 | pipeNode.curRotation[i] = math.min(pipeNode.curRotation[i] + dt*pipeNode.rotationSpeeds[i], targetRotation); |
1170 | else |
1171 | pipeNode.curRotation[i] = math.max(pipeNode.curRotation[i] - dt*pipeNode.rotationSpeeds[i], targetRotation); |
1172 | end |
1173 | if pipeNode.curRotation[i] > 2*math.pi then |
1174 | pipeNode.curRotation[i] = pipeNode.curRotation[i] - 2*math.pi; |
1175 | elseif pipeNode.curRotation[i] < -2*math.pi then |
1176 | pipeNode.curRotation[i] = pipeNode.curRotation[i] + 2*math.pi; |
1177 | end |
1178 | end |
1179 | end |
1180 | setRotation(pipeNode.node, pipeNode.curRotation[1],pipeNode.curRotation[2],pipeNode.curRotation[3]) |
1181 | end |
1182 | moved = moved or nodeMoved; |
1183 | |
1184 | if nodeMoved and self.setMovingToolDirty ~= nil then |
1185 | self:setMovingToolDirty(pipeNode.node); |
1186 | end |
1187 | end |
1188 | if table.getn(self.pipeNodes) == 0 and self.pipeAnimation ~= nil then |
1189 | if self:getIsAnimationPlaying(self.pipeAnimation) then |
1190 | moved = true; |
1191 | end |
1192 | end |
1193 | if not moved then |
1194 | self.pipeCurrentState = self.pipeTargetState; |
1195 | end |
1196 | end |
1197 | end |