Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1 | -- |
2 | -- Overloading |
3 | -- |
4 | -- |
5 | -- @author Manuel Leithner |
6 | -- @date 26/09/13 |
7 | -- |
8 | -- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved. |
9 | |
10 | Overloading = {}; |
11 | source("dataS/scripts/vehicles/specializations/OverloadingSetPipeStateEvent.lua"); |
12 | source("dataS/scripts/vehicles/specializations/OverloadingToggleUnloadEvent.lua"); |
13 | |
14 | function Overloading.prerequisitesPresent(specializations) |
15 | return SpecializationUtil.hasSpecialization(Fillable, specializations); |
16 | end; |
17 | |
18 | function Overloading:load(xmlFile) |
19 | self.getIsFoldAllowed = Utils.overwrittenFunction(self.getIsFoldAllowed, Overloading.getIsFoldAllowed); |
20 | self.setPipeState = SpecializationUtil.callSpecializationsFunction("setPipeState"); |
21 | self.getOverloadingTrailerInRangePipeState = Overloading.getOverloadingTrailerInRangePipeState; |
22 | self.getIsPipeStateChangeAllowed = Overloading.getIsPipeStateChangeAllowed; |
23 | self.getIsPipeUnloadingAllowed = Overloading.getIsPipeUnloadingAllowed; |
24 | self.findAutoAimTrailerToUnload = Overloading.findAutoAimTrailerToUnload; |
25 | self.findTrailerToUnload = Overloading.findTrailerToUnload; |
26 | self.findTrailerRaycastCallback = Overloading.findTrailerRaycastCallback; |
27 | self.onOverloadingTrailerTrigger = Overloading.onOverloadingTrailerTrigger; |
28 | self.setOverloadingActive = Overloading.setOverloadingActive; |
29 | self.activatePipeUnloadingEffects = Overloading.activatePipeUnloadingEffects; |
30 | |
31 | if hasXMLProperty(xmlFile, string.format("vehicle.combineTrailerTriggers.combineTrailerTrigger(%d)", 0)) then |
32 | print("Warning: combineTrailerTriggers are no longer supported. Use vehicle.trailerTriggers.trailerTrigger instead"); |
33 | end |
34 | |
35 | self.trailerTriggers = {}; |
36 | local i = 0; |
37 | while true do |
38 | local key = string.format("vehicle.trailerTriggers.trailerTrigger(%d)", i); |
39 | if not hasXMLProperty(xmlFile, key) then |
40 | key = string.format("vehicle.combineTrailerTriggers.combineTrailerTrigger(%d)", i); |
41 | if not hasXMLProperty(xmlFile, key) then |
42 | break; |
43 | end; |
44 | end; |
45 | local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index")); |
46 | if node ~= nil then |
47 | local pipeState = Utils.getNoNil(getXMLInt(xmlFile, key.."#pipeState"), 2); |
48 | self.trailerTriggers[node] = {node=node, pipeState=pipeState}; |
49 | end; |
50 | i = i + 1; |
51 | end; |
52 | for _, trigger in pairs(self.trailerTriggers) do |
53 | addTrigger(trigger.node, "onOverloadingTrailerTrigger", self); |
54 | end; |
55 | |
56 | self.overloadingTrailersInRange = {}; |
57 | self.overloadingTriggersTrailers = {}; |
58 | |
59 | self.foldMaxPipeState = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.pipe#foldMaxState"), 999); |
60 | self.foldMinPipeState = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.pipe#foldMinState"), 0); |
61 | self.pipeNodes = {}; |
62 | self.numPipeStates = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.pipe#numStates"), 0); |
63 | self.currentPipeState = 1; |
64 | self.targetPipeState = 1; |
65 | self.pipeStateIsUnloading = {}; |
66 | self.pipeStateIsAutoAiming = {}; |
67 | local unloadingPipeStates = Utils.getVectorNFromString(getXMLString(xmlFile, "vehicle.pipe#unloadingStates")); |
68 | if unloadingPipeStates ~= nil then |
69 | for i=1, table.getn(unloadingPipeStates) do |
70 | if unloadingPipeStates[i] ~= nil then |
71 | self.pipeStateIsUnloading[unloadingPipeStates[i] ] = true; |
72 | end; |
73 | end; |
74 | end; |
75 | local autoAimPipeStates = Utils.getVectorNFromString(getXMLString(xmlFile, "vehicle.pipe#autoAimStates")); |
76 | if autoAimPipeStates ~= nil then |
77 | for i=1, table.getn(autoAimPipeStates) do |
78 | if autoAimPipeStates[i] ~= nil then |
79 | self.pipeStateIsAutoAiming[autoAimPipeStates[i] ] = true; |
80 | end; |
81 | end; |
82 | end; |
83 | local i = 0; |
84 | while true do |
85 | local key = string.format("vehicle.pipe.node(%d)", i); |
86 | if not hasXMLProperty(xmlFile, key) then |
87 | break; |
88 | end; |
89 | local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index")); |
90 | if node ~= nil then |
91 | local entry = {}; |
92 | entry.node = node; |
93 | entry.autoAimXRotation = Utils.getNoNil(getXMLBool(xmlFile, key.."#autoAimXRotation"), false); |
94 | entry.autoAimYRotation = Utils.getNoNil(getXMLBool(xmlFile, key.."#autoAimYRotation"), false); |
95 | entry.autoAimInvertZ = Utils.getNoNil(getXMLBool(xmlFile, key.."#autoAimInvertZ"), false); |
96 | entry.states = {}; |
97 | for state=1,self.numPipeStates do |
98 | local stateKey = key..string.format(".state%d", state); |
99 | entry.states[state] = {}; |
100 | local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, stateKey.."#translation")); |
101 | if x == nil or y == nil or z == nil then |
102 | x,y,z = getTranslation(node); |
103 | else |
104 | if state == 1 then |
105 | setTranslation(node, x,y,z); |
106 | end; |
107 | end; |
108 | entry.states[state].translation = {x,y,z}; |
109 | local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, stateKey.."#rotation")); |
110 | if x == nil or y == nil or z == nil then |
111 | x,y,z = getRotation(node); |
112 | else |
113 | x,y,z = math.rad(x),math.rad(y),math.rad(z); |
114 | if state == 1 then |
115 | setRotation(node, x,y,z); |
116 | end; |
117 | end; |
118 | entry.states[state].rotation = {x,y,z}; |
119 | end; |
120 | local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#translationSpeeds")); |
121 | if x ~= nil and y ~= nil and z ~= nil then |
122 | x,y,z = x*0.001,y*0.001,z*0.001; |
123 | if x ~= 0 or y ~= 0 or z ~= 0 then |
124 | entry.translationSpeeds = {x,y,z}; |
125 | end; |
126 | end; |
127 | local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotationSpeeds")); |
128 | if x ~= nil and y ~= nil and z ~= nil then |
129 | x,y,z = math.rad(x)*0.001,math.rad(y)*0.001,math.rad(z)*0.001; |
130 | if x ~= 0 or y ~= 0 or z ~= 0 then |
131 | entry.rotationSpeeds = {x,y,z}; |
132 | end; |
133 | end; |
134 | |
135 | local x,y,z = getTranslation(node); |
136 | entry.curTranslation = {x,y,z}; |
137 | local x,y,z = getRotation(node); |
138 | entry.curRotation = {x,y,z}; |
139 | table.insert(self.pipeNodes, entry); |
140 | end; |
141 | i = i + 1; |
142 | end; |
143 | |
144 | self.pipeAnimation = getXMLString(xmlFile, "vehicle.pipe#animName"); |
145 | self.pipeAnimSpeedScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipe#animSpeedScale"), 1); |
146 | self.pipeRaycastNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.pipe#raycastNodeIndex")); |
147 | self.pipeRaycastDistance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipe#raycastDistance"), 7); |
148 | self.pipeUnloadingDistance = 0; |
149 | self.pipeParticleSystemExtraDistance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipeParticleSystems#extraDistance"), 1.5); |
150 | self.hasPipe = table.getn(self.pipeNodes) ~= 0 or self.pipeAnimation ~= nil; |
151 | self.doAutoAiming = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.pipe#doAutoAiming"), self.pipeRaycastNode == nil); |
152 | |
153 | if self.isClient then |
154 | local defaultPipePSNode = self.components[1].node; |
155 | if table.getn(self.pipeNodes) > 0 then |
156 | defaultPipePSNode = self.pipeNodes[1].node; |
157 | end |
158 | |
159 | self.pipeParticleSystems = {}; |
160 | -- load the pipe particle system for each fruit type |
161 | local i = 0; |
162 | while true do |
163 | local key = string.format("vehicle.pipeParticleSystems.pipeParticleSystem(%d)", i); |
164 | local t = getXMLString(xmlFile, key .. "#type"); |
165 | if t == nil then |
166 | break; |
167 | end; |
168 | |
169 | local desc = FruitUtil.fruitTypes[t]; |
170 | if desc ~= nil then |
171 | local currentPS = Utils.getNoNil(self.pipeParticleSystems[desc.index], {}); |
172 | |
173 | local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, key, self.components, false, nil, self.baseDirectory, defaultPipePSNode); |
174 | |
175 | for _, v in ipairs(currentPS) do |
176 | local normalSpeed,tangentSpeed = getParticleSystemAverageSpeed(v.geometry); |
177 | v.speed = math.sqrt(normalSpeed*normalSpeed + tangentSpeed*tangentSpeed); |
178 | v.originalLifespan = getParticleSystemLifespan(v.geometry); |
179 | end |
180 | self.pipeParticleSystems[desc.index] = currentPS; |
181 | if self.defaultPipeParticleSystem == nil then |
182 | self.defaultPipeParticleSystem = currentPS; |
183 | end; |
184 | |
185 | if self.pipeRaycastNode == nil then |
186 | self.pipeRaycastNode = particleNode; |
187 | end; |
188 | end; |
189 | i = i + 1; |
190 | end; |
191 | |
192 | self.pipeEffect = EffectManager:loadEffect(xmlFile, "vehicle.pipeEffect", self.components, self); |
193 | |
194 | self.overloadingTurnedOnRotationNodes = Utils.loadRotationNodes(xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "overloading", self.components); |
195 | |
196 | self.pipeScrollers = Utils.loadScrollers(self.components, xmlFile, "vehicle.pipeScrollers.pipeScroller", {}, true); |
197 | |
198 | self.samplePipe = Utils.loadSample(xmlFile, {}, "vehicle.pipeSound", nil, self.baseDirectory); |
199 | |
200 | local linkNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(xmlFile, "vehicle.fillSound#linkNode"), "0>")); |
201 | self.sampleFill = Utils.loadSample(xmlFile, {}, "vehicle.fillSound", nil, self.baseDirectory, linkNode); |
202 | Utils.stop3DSample(self.sampleFill); |
203 | self.sampleFillEnabled = false; |
204 | self.sampleFillStopTime = -1; |
205 | self.lastFillLevel = -1; |
206 | self.sampleFillUseOnDischarge = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.fillSound#useOnDischarge"), false); |
207 | self.sampleFillUseOnCharge = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.fillSound#useOnCharge"), false); |
208 | end; |
209 | |
210 | if self.pipeRaycastNode == nil then |
211 | self.pipeRaycastNode = self.components[1].node; |
212 | end; |
213 | |
214 | self.pipeUnloadEffectStopTime = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipe#unloadingEffectStopTime"), 0) * 1000; |
215 | self.currentUnloadEffectStopTime = 0; |
216 | |
217 | self.overloadingCapacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.overloadingCapacity"), 10); |
218 | self.pipeIsUnloading = false; |
219 | self.pipeParticleDeactivateTime = -1; |
220 | |
221 | self.doAutoUnloadIfHired = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.pipe#doAutoUnloadIfHired"), false); |
222 | self.allowFoldWhileUnloading = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.threshingFold#allowFoldWhileUnloading"), false); |
223 | self.pipeFoldMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipe#foldMinLimit"), 0); |
224 | self.pipeFoldMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipe#foldMaxLimit"), 1); |
225 | |
226 | self.overloadingDirtyFlag = self:getNextDirtyFlag(); |
227 | |
228 | self.isOverloadingActive = false; |
229 | self.isSelectable = true; |
230 | self:addConflictCheckedInput(InputBinding.EMPTY_GRAIN); |
231 | end; |
232 | |
233 | function Overloading:delete() |
234 | for _, trailerTrigger in pairs(self.trailerTriggers) do |
235 | removeTrigger(trailerTrigger.node); |
236 | end; |
237 | |
238 | if self.isClient then |
239 | EffectManager:deleteEffect(self.pipeEffect); |
240 | |
241 | for _,v in pairs(self.pipeParticleSystems) do |
242 | Utils.deleteParticleSystem(v); |
243 | end; |
244 | Utils.deleteSample(self.samplePipe); |
245 | end; |
246 | |
247 | if self.isClient then |
248 | Utils.deleteSample(self.sampleFill); |
249 | end; |
250 | end; |
251 | |
252 | function Overloading:loadFromAttributesAndNodes(xmlFile, key, resetVehicles) |
253 | if not resetVehicles then |
254 | local pipeState = Utils.getNoNil(getXMLInt(xmlFile, key.."#pipeState"), 1); |
255 | self:setPipeState(pipeState, true); |
256 | end |
257 | return BaseMission.VEHICLE_LOAD_OK; |
258 | end |
259 | |
260 | function Overloading:getSaveAttributesAndNodes(nodeIdent) |
261 | local attributes = 'pipeState="'..self.currentPipeState..'"'; |
262 | return attributes, nil; |
263 | end |
264 | |
265 | function Overloading:readStream(streamId, connection) |
266 | if self.hasPipe then |
267 | local pipeState = streamReadUIntN(streamId, 3); |
268 | local pipeUnloadingDistance = streamReadUIntN(streamId, 5); |
269 | if pipeUnloadingDistance == 0 then |
270 | self.pipeIsUnloading = false; |
271 | else |
272 | self.pipeIsUnloading = true; |
273 | self.pipeUnloadingDistance = pipeUnloadingDistance*self.pipeRaycastDistance / 31; |
274 | end |
275 | self:setPipeState(pipeState, true); |
276 | else |
277 | self:setOverloadingActive(streamReadBool(streamId), true); |
278 | end; |
279 | end; |
280 | |
281 | function Overloading:writeStream(streamId, connection) |
282 | if self.hasPipe then |
283 | streamWriteUIntN(streamId, self.targetPipeState, 3); |
284 | if self.pipeIsUnloading then |
285 | streamWriteUIntN(streamId, Utils.clamp(math.floor(self.pipeUnloadingDistance/self.pipeRaycastDistance*31), 1, 31), 5); |
286 | else |
287 | streamWriteUIntN(streamId, 0, 5); |
288 | end; |
289 | else |
290 | streamWriteBool(streamId, self.isOverloadingActive); |
291 | end; |
292 | end; |
293 | |
294 | function Overloading:readUpdateStream(streamId, timestamp, connection) |
295 | if connection:getIsServer() then |
296 | --if self.hasPipe then |
297 | if streamReadBool(streamId) then |
298 | local pipeUnloadingDistance = streamReadUIntN(streamId, 5); |
299 | if pipeUnloadingDistance == 0 then |
300 | self.pipeIsUnloading = false; |
301 | else |
302 | self.pipeIsUnloading = true; |
303 | self.pipeUnloadingDistance = pipeUnloadingDistance*self.pipeRaycastDistance / 31; |
304 | end |
305 | end; |
306 | --end; |
307 | end; |
308 | end; |
309 | |
310 | function Overloading:writeUpdateStream(streamId, connection, dirtyMask) |
311 | if not connection:getIsServer() then |
312 | --if self.hasPipe then |
313 | if streamWriteBool(streamId, bitAND(dirtyMask, self.overloadingDirtyFlag) ~= 0) then |
314 | if self.pipeIsUnloading then |
315 | streamWriteUIntN(streamId, Utils.clamp(math.floor(self.pipeUnloadingDistance/self.pipeRaycastDistance*31), 1, 31), 5); |
316 | else |
317 | streamWriteUIntN(streamId, 0, 5); |
318 | end |
319 | end; |
320 | --end; |
321 | end; |
322 | end; |
323 | |
324 | function Overloading:mouseEvent(posX, posY, isDown, isUp, button) |
325 | end; |
326 | |
327 | function Overloading:keyEvent(unicode, sym, modifier, isDown) |
328 | end; |
329 | |
330 | function Overloading:update(dt) |
331 | if self:getIsActive() then |
332 | if self.isClient and self:getIsActiveForInput(true) and not self:hasInputConflictWithSelection() then |
333 | if InputBinding.hasEvent(InputBinding.EMPTY_GRAIN) then |
334 | if self.hasPipe then |
335 | local nextState = self.targetPipeState+1; |
336 | if nextState > self.numPipeStates then |
337 | nextState = 1; |
338 | end; |
339 | if self:getIsPipeStateChangeAllowed(nextState) then |
340 | self:setPipeState(nextState); |
341 | elseif nextState ~= 1 and self:getIsPipeStateChangeAllowed(1) then |
342 | -- also try to close the pipe if other states are not allowed |
343 | self:setPipeState(1); |
344 | end |
345 | else |
346 | self:setOverloadingActive(not self.isOverloadingActive); |
347 | end; |
348 | end; |
349 | end; |
350 | |
351 | if not self.hasPipe and self.doAutoUnloadIfHired then |
352 | local rootAttacher = self:getRootAttacherVehicle(); |
353 | if self:findTrailerToUnload(self.currentFillType) ~= nil and self.fillLevel > 0 and rootAttacher.isHired then |
354 | self:setOverloadingActive(true); |
355 | end; |
356 | end; |
357 | |
358 | if self.hasPipe then |
359 | local doAutoAiming = self.pipeStateIsAutoAiming[self.currentPipeState]; |
360 | local targetTrailer = nil; |
361 | if doAutoAiming then |
362 | targetTrailer = self:findAutoAimTrailerToUnload(self.lastValidFillType); |
363 | |
364 | if targetTrailer == nil then |
365 | doAutoAiming = false; |
366 | end; |
367 | end; |
368 | if (self.currentPipeState ~= self.targetPipeState or doAutoAiming) and self.targetPipeState <= self.numPipeStates then |
369 | local autoAimX, autoAimY, autoAimZ; |
370 | if doAutoAiming then |
371 | autoAimX, autoAimY, autoAimZ = getWorldTranslation(targetTrailer.fillAutoAimTargetNode); |
372 | end; |
373 | |
374 | local moved = false; |
375 | for i=1, table.getn(self.pipeNodes) do |
376 | local nodeMoved = false; |
377 | local pipeNode = self.pipeNodes[i]; |
378 | |
379 | local state = pipeNode.states[self.targetPipeState]; |
380 | if pipeNode.translationSpeeds ~= nil then |
381 | for i=1, 3 do |
382 | if math.abs(pipeNode.curTranslation[i] - state.translation[i]) > 0.000001 then |
383 | nodeMoved = true; |
384 | if pipeNode.curTranslation[i] < state.translation[i] then |
385 | pipeNode.curTranslation[i] = math.min(pipeNode.curTranslation[i] + dt*pipeNode.translationSpeeds[i], state.translation[i]); |
386 | else |
387 | pipeNode.curTranslation[i] = math.max(pipeNode.curTranslation[i] - dt*pipeNode.translationSpeeds[i], state.translation[i]); |
388 | end; |
389 | end; |
390 | end; |
391 | setTranslation(pipeNode.node, pipeNode.curTranslation[1],pipeNode.curTranslation[2],pipeNode.curTranslation[3]) |
392 | end; |
393 | if pipeNode.rotationSpeeds ~= nil then |
394 | for i=1, 3 do |
395 | local targetRotation = state.rotation[i]; |
396 | if doAutoAiming then |
397 | if pipeNode.autoAimXRotation and i == 1 then |
398 | local x,y,z = getWorldTranslation(pipeNode.node); |
399 | local x,y,z = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, autoAimY-y, autoAimZ-z); |
400 | targetRotation = -math.atan2(y,z); |
401 | if pipeNode.autoAimInvertZ then |
402 | targetRotation = targetRotation+math.pi; |
403 | end; |
404 | targetRotation = Utils.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[i]); |
405 | elseif pipeNode.autoAimYRotation and i == 2 then |
406 | local x,y,z = getWorldTranslation(pipeNode.node); |
407 | local x,y,z = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, autoAimY-y, autoAimZ-z); |
408 | targetRotation = math.atan2(x,z); |
409 | if pipeNode.autoAimInvertZ then |
410 | targetRotation = targetRotation+math.pi; |
411 | end; |
412 | targetRotation = Utils.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[i]); |
413 | end; |
414 | end; |
415 | if math.abs(pipeNode.curRotation[i] - targetRotation) > 0.000001 then |
416 | nodeMoved = true; |
417 | if pipeNode.curRotation[i] < targetRotation then |
418 | pipeNode.curRotation[i] = math.min(pipeNode.curRotation[i] + dt*pipeNode.rotationSpeeds[i], targetRotation); |
419 | else |
420 | pipeNode.curRotation[i] = math.max(pipeNode.curRotation[i] - dt*pipeNode.rotationSpeeds[i], targetRotation); |
421 | end; |
422 | end; |
423 | end; |
424 | setRotation(pipeNode.node, pipeNode.curRotation[1],pipeNode.curRotation[2],pipeNode.curRotation[3]) |
425 | end; |
426 | moved = moved or nodeMoved; |
427 | |
428 | if nodeMoved and self.setMovingToolDirty ~= nil then |
429 | self:setMovingToolDirty(pipeNode.node); |
430 | end; |
431 | end; |
432 | if table.getn(self.pipeNodes) == 0 and self.pipeAnimation ~= nil then |
433 | if self:getIsAnimationPlaying(self.pipeAnimation) then |
434 | moved = true; |
435 | end; |
436 | end; |
437 | if not moved then |
438 | self.currentPipeState = self.targetPipeState; |
439 | end; |
440 | end; |
441 | |
442 | if self.isClient then |
443 | if self:getIsActiveForSound() and self.currentPipeState ~= self.targetPipeState then |
444 | Utils.playSample(self.samplePipe, 0, 0, nil); |
445 | else |
446 | Utils.stopSample(self.samplePipe); |
447 | end; |
448 | end; |
449 | end; |
450 | end; |
451 | |
452 | if self.isClient then |
453 | |
454 | Utils.updateRotationNodes(self, self.overloadingTurnedOnRotationNodes, dt, self.pipeIsUnloading); |
455 | |
456 | if self.pipeIsUnloading then |
457 | local currentPipeScrollers = self.pipeScrollers[self.lastValidFillType]; |
458 | if currentPipeScrollers ~= self.currentPipeScrollers and self.currentPipeScrollers ~= nil then |
459 | self.lastPipeScrollers = self.currentPipeScrollers; |
460 | end |
461 | self.currentPipeScrollers = currentPipeScrollers; |
462 | if self.currentPipeScrollers ~= nil then |
463 | Utils.updateScrollers(self.currentPipeScrollers, dt, true, true); |
464 | end |
465 | else |
466 | if self.currentPipeScrollers ~= nil then |
467 | if self.currentPipeScrollers.isRunning == true then |
468 | Utils.updateScrollers(self.currentPipeScrollers, dt, false, true); |
469 | else |
470 | Utils.updateScrollers(self.currentPipeScrollers, dt, false, false); |
471 | self.currentPipeScrollers = nil; |
472 | end; |
473 | end |
474 | end; |
475 | if self.lastPipeScrollers ~= nil then |
476 | Utils.updateScrollers(self.lastPipeScrollers, dt, false, false); |
477 | self.lastPipeScrollers = nil; |
478 | end; |
479 | end; |
480 | end; |
481 | |
482 | function Overloading:updateTick(dt) |
483 | if self.isServer then |
484 | if self.pipeIsUnloading then |
485 | self.currentUnloadEffectStopTime = self.currentUnloadEffectStopTime - dt; |
486 | if self.currentUnloadEffectStopTime <= 0 then |
487 | self.pipeIsUnloading = false; |
488 | end; |
489 | end; |
490 | --self.pipeIsUnloading = false; |
491 | if (self.hasPipe and (self.pipeStateIsUnloading[self.currentPipeState] or self.numPipeStates == 0) and self:getIsPipeUnloadingAllowed()) or (not self.hasPipe and self.isOverloadingActive) then |
492 | if self.fillLevel > 0 then |
493 | -- test if we should drain the grain tank |
494 | local trailer, trailerDistance; |
495 | local doAutoAiming = false; |
496 | if self.hasPipe then |
497 | doAutoAiming = self.pipeStateIsAutoAiming[self.currentPipeState]; |
498 | else |
499 | doAutoAiming = self.doAutoAiming; |
500 | end; |
501 | |
502 | if doAutoAiming then |
503 | trailer, _ = self:findAutoAimTrailerToUnload(self.currentFillType); |
504 | trailerDistance = 1; |
505 | else |
506 | trailer, trailerDistance = self:findTrailerToUnload(self.currentFillType); |
507 | end; |
508 | |
509 | if trailer == nil then |
510 | if self:getCapacity() == 0 then |
511 | self:activatePipeUnloadingEffects(); -- show particle if capacity is 0 |
512 | end; |
513 | --self.pipeIsUnloading = self:getCapacity() == 0; |
514 | if not self.hasPipe then |
515 | self:setOverloadingActive(false); |
516 | end; |
517 | else |
518 | trailer:resetFillLevelIfNeeded(self.currentFillType); |
519 | |
520 | local deltaLevel = self.fillLevel; |
521 | if self:getCapacity() > 0 then |
522 | deltaLevel = math.min(self.fillLevel, self.overloadingCapacity*dt/1000.0); |
523 | end; |
524 | deltaLevel = math.min(deltaLevel, trailer:getCapacity() - trailer.fillLevel); |
525 | if deltaLevel > 0 then |
526 | self:activatePipeUnloadingEffects(); |
527 | --self.pipeIsUnloading = true; |
528 | self.pipeUnloadingDistance = trailerDistance; |
529 | |
530 | local x,y,z = getWorldTranslation(self.fillVolumeDischargeInfo.node); |
531 | local d1x,d1y,d1z = localDirectionToWorld(self.fillVolumeDischargeInfo.node, self.fillVolumeDischargeInfo.width,0,0); |
532 | local d2x,d2y,d2z = localDirectionToWorld(self.fillVolumeDischargeInfo.node, 0,0,self.fillVolumeDischargeInfo.length); |
533 | local fillSourceStruct = {x=x,y=y,z=z, d1x=d1x,d1y=d1y,d1z=d1z, d2x=d2x,d2y=d2y,d2z=d2z}; |
534 | trailer:setFillLevel(trailer.fillLevel+deltaLevel, self.currentFillType, false, fillSourceStruct); |
535 | |
536 | |
537 | local x,y,z = getWorldTranslation(self.fillVolumeUnloadInfo.node); |
538 | local d1x,d1y,d1z = localDirectionToWorld(self.fillVolumeUnloadInfo.node, self.fillVolumeUnloadInfo.width,0,0); |
539 | local d2x,d2y,d2z = localDirectionToWorld(self.fillVolumeUnloadInfo.node, 0,0,self.fillVolumeUnloadInfo.length); |
540 | local fillSourceStruct = {x=x,y=y,z=z, d1x=d1x,d1y=d1y,d1z=d1z, d2x=d2x,d2y=d2y,d2z=d2z}; |
541 | self:setFillLevel(self.fillLevel-deltaLevel, self.currentFillType, false, fillSourceStruct); |
542 | end |
543 | end; |
544 | else |
545 | self:setOverloadingActive(false); |
546 | end; |
547 | end; |
548 | |
549 | if self.pipeIsUnloading ~= self.sentPipeIsUnloading or self.pipeUnloadingDistance ~= self.sentPipeUnloadingDistance then |
550 | self:raiseDirtyFlags(self.overloadingDirtyFlag); |
551 | self.sentPipeIsUnloading = self.pipeIsUnloading; |
552 | self.sentPipeUnloadingDistance = self.pipeUnloadingDistance; |
553 | end; |
554 | end; |
555 | |
556 | if self.isClient then |
557 | if self.pipeIsUnloading then |
558 | self.pipeParticleDeactivateTime = g_currentMission.time + 200; |
559 | local currentPipeParticleSystem = self.pipeParticleSystems[self.lastValidFillType]; |
560 | if currentPipeParticleSystem == nil then |
561 | currentPipeParticleSystem = self.defaultPipeParticleSystem; |
562 | end; |
563 | if currentPipeParticleSystem ~= self.currentPipeParticleSystem then |
564 | Utils.setEmittingState(self.currentPipeParticleSystem, false); |
565 | |
566 | self.currentPipeParticleSystem = currentPipeParticleSystem; |
567 | Utils.setEmittingState(self.currentPipeParticleSystem, true); |
568 | end |
569 | |
570 | if self.currentPipeParticleSystem ~= nil then |
571 | for _, v in ipairs(self.currentPipeParticleSystem) do |
572 | if not v.forceFullLifespan then |
573 | local lifespan = math.min(v.originalLifespan, (self.pipeUnloadingDistance+self.pipeParticleSystemExtraDistance)/v.speed); |
574 | setParticleSystemLifespan(v.geometry, lifespan, true); |
575 | end; |
576 | end |
577 | end |
578 | |
579 | if self.pipeEffect ~= nil then |
580 | self.pipeEffect:setFillType(self.lastValidFillType); |
581 | EffectManager:startEffect(self.pipeEffect); |
582 | end; |
583 | else |
584 | if self.pipeParticleDeactivateTime >= 0 and self.pipeParticleDeactivateTime <= g_currentMission.time then |
585 | self.pipeParticleDeactivateTime = -1; |
586 | if self.currentPipeParticleSystem ~= nil then |
587 | Utils.setEmittingState(self.currentPipeParticleSystem, false); |
588 | self.currentPipeParticleSystem = nil; |
589 | end |
590 | |
591 | if self.pipeEffect ~= nil then |
592 | EffectManager:stopEffect(self.pipeEffect); |
593 | end; |
594 | end |
595 | end; |
596 | end; |
597 | |
598 | if self.isClient then |
599 | if self.lastFillLevel ~= self.fillLevel and self.fillLevel > 0 then |
600 | if ((self.lastFillLevel < self.fillLevel and self.sampleFillUseOnCharge) or (self.sampleFillUseOnDischarge and self.isOverloadingActive)) and self.lastFillLevel ~= -1 then |
601 | self.sampleFillStopTime = g_currentMission.time + 150; |
602 | end; |
603 | self.lastFillLevel = self.fillLevel; |
604 | end; |
605 | |
606 | if self.sampleFillStopTime > g_currentMission.time then |
607 | if self:getIsActiveForSound(true) then |
608 | Utils.playSample(self.sampleFill, 0, 0, nil); |
609 | Utils.stop3DSample(self.sampleFill); |
610 | else |
611 | Utils.stopSample(self.sampleFill); |
612 | Utils.play3DSample(self.sampleFill); |
613 | end; |
614 | else |
615 | Utils.stopSample(self.sampleFill); |
616 | Utils.stop3DSample(self.sampleFill); |
617 | end; |
618 | end; |
619 | end; |
620 | |
621 | function Overloading:draw() |
622 | if self.isClient and self:getIsActiveForInput(true) and not self:hasInputConflictWithSelection() then |
623 | if self.hasPipe then |
624 | if self.numPipeStates == 2 then |
625 | if self.targetPipeState == 2 then |
626 | if self:getIsPipeStateChangeAllowed(1) then |
627 | g_currentMission:addHelpButtonText(g_i18n:getText("Pipe_in"), InputBinding.EMPTY_GRAIN); |
628 | end |
629 | else |
630 | if self:getIsPipeStateChangeAllowed(2) then |
631 | g_currentMission:addHelpButtonText(g_i18n:getText("Dump_corn"), InputBinding.EMPTY_GRAIN); |
632 | end |
633 | end |
634 | end; |
635 | else |
636 | if self:findAutoAimTrailerToUnload(self.currentFillType) ~= nil then |
637 | if self.isOverloadingActive then |
638 | g_currentMission:addHelpButtonText(g_i18n:getText("Stop_overloading"), InputBinding.EMPTY_GRAIN); |
639 | else |
640 | g_currentMission:addHelpButtonText(g_i18n:getText("Start_overloading"), InputBinding.EMPTY_GRAIN); |
641 | end; |
642 | end; |
643 | end; |
644 | end; |
645 | end; |
646 | |
647 | function Overloading:activatePipeUnloadingEffects() |
648 | self.currentUnloadEffectStopTime = self.pipeUnloadEffectStopTime; |
649 | self.pipeIsUnloading = true; |
650 | end; |
651 | |
652 | function Overloading:onDeactivateSounds() |
653 | if self.isClient then |
654 | Utils.stopSample(self.samplePipe, true); |
655 | end; |
656 | end; |
657 | |
658 | function Overloading:getIsPipeStateChangeAllowed(pipeState) |
659 | if pipeState ~= 1 and self.foldAnimTime ~= nil and (self.foldAnimTime > self.pipeFoldMaxLimit or self.foldAnimTime < self.pipeFoldMinLimit) then |
660 | return false; |
661 | end |
662 | return true; |
663 | end |
664 | |
665 | function Overloading:getIsPipeUnloadingAllowed() |
666 | if self.foldAnimTime ~= nil and (self.foldAnimTime > self.pipeFoldMaxLimit or self.foldAnimTime < self.pipeFoldMinLimit) then |
667 | return false; |
668 | end |
669 | return true; |
670 | end |
671 | |
672 | function Overloading:setOverloadingActive(isActive, noEventSend) |
673 | if isActive ~= self.isOverloadingActive then |
674 | OverloadingToggleUnloadEvent.sendEvent(self, isActive, noEventSend); |
675 | self.isOverloadingActive = isActive; |
676 | end; |
677 | end; |
678 | |
679 | function Overloading:setPipeState(pipeState, noEventSend) |
680 | pipeState = math.min(pipeState, self.numPipeStates); |
681 | if self.targetPipeState ~= pipeState then |
682 | if noEventSend == nil or noEventSend == false then |
683 | if g_server ~= nil then |
684 | g_server:broadcastEvent(OverloadingSetPipeStateEvent:new(self, pipeState)); |
685 | else |
686 | g_client:getServerConnection():sendEvent(OverloadingSetPipeStateEvent:new(self, pipeState), nil, nil, self); |
687 | end; |
688 | end; |
689 | self.targetPipeState = pipeState; |
690 | self.currentPipeState = 0; |
691 | if self.pipeAnimation ~= nil then |
692 | if pipeState == 1 then |
693 | self:playAnimation(self.pipeAnimation, -self.pipeAnimSpeedScale, self:getAnimationTime(self.pipeAnimation), true); |
694 | else |
695 | self:playAnimation(self.pipeAnimation, self.pipeAnimSpeedScale, self:getAnimationTime(self.pipeAnimation), true); |
696 | end; |
697 | end; |
698 | end; |
699 | end; |
700 | |
701 | function Overloading:getIsFoldAllowed(superFunc) |
702 | if not self.allowFoldWhileUnloading and self.pipeIsUnloading then |
703 | return false; |
704 | end |
705 | if self.currentPipeState > self.foldMaxPipeState or self.currentPipeState < self.foldMinPipeState then |
706 | return false; |
707 | end |
708 | |
709 | if superFunc ~= nil then |
710 | return superFunc(self); |
711 | end |
712 | return true; |
713 | end |
714 | |
715 | function Overloading:findAutoAimTrailerToUnload(fillType) |
716 | local trailer = nil; |
717 | local smallestTrailerId = nil; |
718 | local trailerIsAttached = false; |
719 | for trailerInRange, pipeStage in pairs(self.overloadingTrailersInRange) do |
720 | if trailerInRange.isDeleted then |
721 | self.overloadingTrailersInRange[trailerInRange] = nil; |
722 | else |
723 | if trailerInRange:allowFillType(fillType) and trailerInRange.getAllowFillFromAir ~= nil and trailerInRange:getAllowFillFromAir() and trailerInRange.fillLevel < trailerInRange:getCapacity() then |
724 | local id = networkGetObjectId(trailerInRange); |
725 | -- always take the trailer with the smallest network id which is attached if possible |
726 | -- This is deterministic and is the same on the client |
727 | local isAttached = trailerInRange:getIsAttachedTo(self) |
728 | if trailer == nil or (isAttached and not trailerIsAttached) or (isAttached == trailerIsAttached and id < smallestTrailerId) then |
729 | trailer = trailerInRange; |
730 | smallestTrailerId = id; |
731 | trailerIsAttached = isAttached |
732 | end; |
733 | end; |
734 | end |
735 | end; |
736 | return trailer; |
737 | end; |
738 | |
739 | function Overloading:findTrailerToUnload(fillType) |
740 | local x,y,z = getWorldTranslation(self.pipeRaycastNode); |
741 | local dx,dy,dz = localDirectionToWorld(self.pipeRaycastNode, 0,-1,0); |
742 | self.trailerFound = 0; |
743 | self.trailerFoundDistance = 0; |
744 | raycastAll(x, y, z, dx,dy,dz, "findTrailerRaycastCallback", self.pipeRaycastDistance, self); |
745 | |
746 | local trailer = g_currentMission.nodeToVehicle[self.trailerFound]; |
747 | if trailer == nil or not trailer:allowFillType(fillType) or trailer.getAllowFillFromAir == nil or not trailer:getAllowFillFromAir() or trailer.fillLevel >= trailer:getCapacity() then |
748 | return nil; |
749 | end; |
750 | return trailer, self.trailerFoundDistance; |
751 | end; |
752 | |
753 | function Overloading:findTrailerRaycastCallback(transformId, x, y, z, distance) |
754 | local vehicle = g_currentMission.nodeToVehicle[transformId]; |
755 | if vehicle ~= nil then |
756 | if vehicle.exactFillRootNode == transformId then |
757 | self.trailerFound = transformId; |
758 | self.trailerFoundDistance = distance; |
759 | return false; |
760 | end; |
761 | end; |
762 | |
763 | return true; |
764 | end; |
765 | |
766 | function Overloading:getOverloadingTrailerInRangePipeState() |
767 | local maxPipeState = 0; |
768 | for trailer, pipeState in pairs(self.overloadingTrailersInRange) do |
769 | if trailer.isDeleted then |
770 | self.overloadingTrailersInRange[trailer] = nil; |
771 | else |
772 | maxPipeState = math.max(maxPipeState, pipeState); |
773 | end |
774 | end; |
775 | return maxPipeState; |
776 | end |
777 | |
778 | function Overloading:onOverloadingTrailerTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId) |
779 | if onEnter or onLeave then |
780 | local trailer = g_currentMission.nodeToVehicle[otherId]; |
781 | if trailer ~= nil and trailer.fillRootNode ~= nil and trailer ~= self then |
782 | if onEnter then |
783 | self.overloadingTriggersTrailers[trailer] = Utils.getNoNil(self.overloadingTriggersTrailers[trailer], 0) + 1; |
784 | else |
785 | self.overloadingTriggersTrailers[trailer] = math.max(Utils.getNoNil(self.overloadingTriggersTrailers[trailer], 0) - 1, 0); |
786 | end; |
787 | if self.overloadingTriggersTrailers[trailer] > 0 then |
788 | self.overloadingTrailersInRange[trailer] = self.trailerTriggers[triggerId].pipeState; |
789 | else |
790 | self.overloadingTrailersInRange[trailer] = nil; |
791 | end; |
792 | end; |
793 | end; |
794 | end;
|
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de