LUADOC - Farming Simulator 17

Printable Version

Script v1.4.4.0

Engine v7.0.0.2

Foundation Reference

Shovel

Description
Class for all shovels
Functions

prerequisitesPresent

Description
Checks if all prerequisite specializations are loaded
Definition
prerequisitesPresent(table specializations)
Arguments
tablespecializationsspecializations
Return Values
booleanhasPrerequisitetrue if all prerequisite specializations are loaded
Code
17function Shovel.prerequisitesPresent(specializations)
18 return SpecializationUtil.hasSpecialization(Fillable, specializations);
19end;

preLoad

Description
Called before loading
Definition
preLoad(table savegame)
Arguments
tablesavegamesavegame
Code
24function Shovel:preLoad(savegame)
25 self.loadAreaFromXML = Shovel.loadAreaFromXML;
26 self.getIsAreaActive = Shovel.getIsAreaActive;
27 self.findTrailerRaycastCallback = Shovel.findTrailerRaycastCallback;
28 self.setFillLevel = Utils.overwrittenFunction(self.setFillLevel, Shovel.setFillLevel);
29 self.getAllowFillShovel = Shovel.getAllowFillShovel;
30 self.getShovelEmptyingSpeed = Shovel.getShovelEmptyingSpeed;
31 self.fillShovelFromGroundValue = Shovel.fillShovelFromGroundValue;
32 self.fillShovelFromTrigger = Shovel.fillShovelFromTrigger;
33 self.updateShovelParticleSystems = Shovel.updateShovelParticleSystems;
34 self.setChangedFillLevelCallback = Shovel.setChangedFillLevelCallback;
35end;

load

Description
Called on loading
Definition
load(table savegame)
Arguments
tablesavegamesavegame
Code
40function Shovel:load(savegame)
41 self.shovelTipReferenceNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.shovel#tipReferenceNode"));
42 self.shovelTipRaycastDistance = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#tipRaycastDistance"), 10);
43 self.shovelOpenNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.shovel#openNode"));
44 self.shovelOpenRotation = math.rad(Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#openRotation"), 0));
45 self.shovelOpenDirection = Utils.sign(Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.shovel#openDirection"), 1));
46 self.shovelEmptyStartCosAngle = math.cos(math.rad(Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#emptyStartAngle"), 110)));
47 self.shovelEmptyFullCosAngle = math.cos(math.rad(Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#emptyFullAngle"), 135)));
48 self.shovelEmptySpeed = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#emptySpeed"), self:getCapacity()/2)*0.001;
49 self.allowFillFromShovelTrigger = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.shovel#allowFillFromShovelTrigger"), true);
50
51 self.shovelShowFillTypeIcon = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.shovel#showFillTypeIcon"), true);
52
53 -- Note: self.shovelFillLitersPerSecond has the wrong naming, it should be called self.shovelFillLitersPerMS)
54 self.shovelFillLitersPerSecond = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#fillLitersPerSecond"), 10000) * 0.001;
55 self.ignoreVehicleDirectionOnLoad = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.shovel#ignoreVehicleDirectionOnLoad"), false);
56
57
58
59 self.pickUp = {};
60 self.pickUp.node = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.shovel#pickUpNode"));
61 self.pickUp.width = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#pickUpWidth"), 1.0);
62 self.pickUp.length = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#pickUpLength"), 0.5);
63 self.pickUp.yOffset = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#pickUpYOffset"), 0.0);
64 self.pickUp.pickUpRequiresMovement = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.shovel#pickUpRequiresMovement"), true);
65 self.pickUp.pickUpNeedsToBeTurnedOn = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.shovel#pickUpNeedsToBeTurnedOn"), false);
66 self.pickUp.pickUpNeedsActiveVehicle = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.shovel#pickUpNeedsActiveVehicle"), true);
67
68 self.pickUp.remainingDelta = 0;
69
70 local hasShovelNodes = false;
71 local shovelNodes = {};
72 local i = 0;
73 while true do
74 local key = string.format("vehicle.shovel.node(%d)", i);
75 if not hasXMLProperty(self.xmlFile, key) then
76 break;
77 end;
78 hasShovelNodes = true;
79 local node = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#index"));
80 if node ~= nil then
81 shovelNodes[node] = true;
82 end;
83 i = i + 1;
84 end;
85 if hasShovelNodes then
86 self.shovelNodes = shovelNodes;
87 end;
88
89
90 if self.isClient then
91 for _, key in pairs({"empty", "fill"}) do
92 self[key.."EmitterShape"] = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle."..key.."ParticleSystems.emitterShape#node"));
93 self[key.."ReferenceParticleSystems"] = {};
94
95 if self[key.."EmitterShape"] ~= nil then
96 for _,fillUnit in pairs(self.fillUnits) do
97 for fillType,state in pairs(fillUnit.fillTypes) do
98 local particleSystems = MaterialUtil.getParticleSystem(fillType, "unloading")
99 if state and particleSystems ~= nil then
100 self[key.."ReferenceParticleSystems"][fillType] = ParticleUtil.copyParticleSystem(self.xmlFile, "vehicle."..key.."ParticleSystems.emitterShape", particleSystems, self[key.."EmitterShape"])
101 end
102 end
103 end
104 end;
105 end;
106
107 self.effectsTimeout = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#effectsTimeout"), 0.1)*1000;
108 self.fillEffectsTimeout = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.shovel#fillEffectsTimeout"), 0.1)*1000;
109
110 self.shovelEmptyEffects = EffectManager:loadEffect(self.xmlFile, "vehicle.shovelEmptyEffect", self.components, self);
111 self.shovelEmptyEffectsRotateNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.shovelEmptyEffect#rotationNode"));
112 self.shovelEmptyEffectsRotateTimeOut = 0;
113
114 self.shovelFillEffects = EffectManager:loadEffect(self.xmlFile, "vehicle.shovelFillEffect", self.components, self);
115 end;
116
117 self.shovel = {};
118 self.shovel.fillUnitIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.shovel#fillUnitIndex"), 1);
119 self.shovel.unloadInfoIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.shovel#unloadInfoIndex"), 1);
120 self.shovel.loadInfoIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.shovel#loadInfoIndex"), 1);
121 self.shovel.dischargeInfoIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.shovel#dischargeInfoIndex"), 1);
122
123 local shovelTipTriggerId = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.shovelTipTrigger#index"));
124 self.shovel.allowPallets = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.shovelTipTrigger#allowPallets"), false);
125
126 if shovelTipTriggerId ~= nil then
127 local shovelTipTrigger = TipTrigger:new(self.isServer, self.isClient);
128 if shovelTipTrigger:load(shovelTipTriggerId) then
129 shovelTipTrigger:addTipTriggerTarget(self);
130 self.shovelTipTrigger = shovelTipTrigger;
131 self.shovelTipTrigger:register(true);
132 else
133 shovelTipTrigger:delete();
134 end
135 end
136
137 self.accumulatedFillDelta = 0;
138 self.accumulatedEmptyDelta = 0;
139
140 self.fillEffectActive = false;
141 self.sentFillEffectActive = false;
142 self.lastFillEffectActiveTime = 0;
143
144 self.emptyEffectActive = false;
145 self.sentEmptyEffectActive = false;
146 self.lastEmptyEffectActiveTime = 0;
147
148 self.curShovelTipRaycastDistance = 0;
149 self.sentCurShovelTipRaycastDistance = 0;
150
151
152 if self.shovelDirtyFlag == nil then
153 self.shovelDirtyFlag = self:getNextDirtyFlag();
154 end
155end;

delete

Description
Called on deleting
Definition
delete()
Code
159function Shovel:delete()
160 if self.isClient then
161 EffectManager:deleteEffects(self.shovelFillEffects);
162 EffectManager:deleteEffects(self.shovelEmptyEffects);
163 ParticleUtil.deleteParticleSystems(self.emptyReferenceParticleSystems)
164 ParticleUtil.deleteParticleSystems(self.fillReferenceParticleSystems)
165 end;
166 if self.shovelTipTrigger ~= nil then
167 self.shovelTipTrigger:unregister(true);
168 self.shovelTipTrigger:delete();
169 end
170end;

addNodeVehicleMapping

Description
Add fillRootNode and exactFillRootNode to 'nodeToVehicle' mapping
Definition
addNodeVehicleMapping(table list)
Arguments
tablelistlist
Code
175function Shovel:addNodeVehicleMapping(list)
176 if self.shovelNodes ~= nil then
177 for node,_ in pairs(self.shovelNodes) do
178 list[node] = self;
179 end
180 end
181end;

removeNodeVehicleMapping

Description
Remove fillRootNode and exactFillRootNode from 'nodeToVehicle' mapping
Definition
removeNodeVehicleMapping(table list)
Arguments
tablelistlist
Code
186function Shovel:removeNodeVehicleMapping(list)
187 if self.shovelNodes ~= nil then
188 for node,_ in pairs(self.shovelNodes) do
189 list[node] = nil;
190 end
191 end
192end;

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
198function Shovel:readStream(streamId, connection)
199 if connection:getIsServer() then
200 if streamReadBool(streamId) then
201 local shovelTipTriggerId = readNetworkNodeObjectId(streamId);
202 g_client:finishRegisterObject(self.shovelTipTrigger, shovelTipTriggerId);
203 end;
204 end;
205end;

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
211function Shovel:writeStream(streamId, connection)
212 if not connection:getIsServer() then
213 local hasShovelTipTrigger = self.shovelTipTrigger ~= nil;
214 streamWriteBool(streamId, hasShovelTipTrigger);
215 if hasShovelTipTrigger then
216 writeNetworkNodeObjectId(streamId, self.shovelTipTrigger.id);
217 end;
218 end;
219end;

readUpdateStream

Description
Called on on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
226function Shovel:readUpdateStream(streamId, timestamp, connection)
227 if connection:getIsServer() then
228 if streamReadBool(streamId) then
229 self.fillEffectActive = streamReadBool(streamId);
230 self.emptyEffectActive = streamReadBool(streamId);
231
232 self:updateShovelParticleSystems(self.emptyEffectActive, self.fillEffectActive);
233
234 self.curShovelTipRaycastDistance = streamReadUIntN(streamId, 7)/128*10;
235 end
236 end
237end;

writeUpdateStream

Description
Called on on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
244function Shovel:writeUpdateStream(streamId, connection, dirtyMask)
245 if not connection:getIsServer() then
246 if streamWriteBool(streamId, bitAND(dirtyMask, self.shovelDirtyFlag) ~= 0) then
247 streamWriteBool(streamId, self.fillEffectActive);
248 streamWriteBool(streamId, self.emptyEffectActive);
249
250 self.sentEmptyEffectActive = self.emptyEffectActive;
251 self.sentFillEffectActive = self.fillEffectActive;
252
253 streamWriteUIntN(streamId, Utils.clamp(self.curShovelTipRaycastDistance/10, 0, 1)*128, 7);
254 self.sentCurShovelTipRaycastDistance = self.curShovelTipRaycastDistance;
255 end
256 end
257end;

update

Description
Called on update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
268function Shovel:update(dt)
269 if self:getIsActive() then
270 if self.shovelEmptyEffectsRotateNode ~= nil then
271 --if self.lastEmptyEffectActiveTime > 0 and self.lastEmptyEffectActiveTime + self.effectsTimeout < g_currentMission.time then
272 --self.shovelEmptyEffectsRotateTimeOut = self.shovelEmptyEffectsRotateTimeOut - dt;
273 --local dx,dy,dz = localDirectionToWorld(getParent(self.shovelEmptyEffectsRotateNode), 0,0,1);
274 --local alpha = math.acos(dy);
275 --setRotation(self.shovelEmptyEffectsRotateNode, -alpha+math.pi/2,0,0);
276
277 local _,dy,dz = worldDirectionToLocal(getParent(self.shovelEmptyEffectsRotateNode), 0,1,0);
278 local alpha = math.atan2(dz, dy);
279 setRotation(self.shovelEmptyEffectsRotateNode, alpha,0,0);
280 --end
281 end
282 end;
283end;

updateTick

Description
Called on update tick
Definition
updateTick(float dt)
Arguments
floatdttime since last call in ms
Code
288function Shovel:updateTick(dt)
289 if self.isServer then
290 --
291 self.emptyEffectActive = false;
292 self.fillEffectActive = false;
293
294 if (self:getIsActive() or not self.pickUp.pickUpNeedsActiveVehicle) then
295 -- calc movement of pickUpNode
296 local pickUpIsAllowed = true;
297 local pickUpSpeed = 0;
298 local pickUp = self.pickUp;
299 if pickUp.node ~= nil then
300 if Vehicle.debugRendering then
301 DebugUtil.drawDebugNode(pickUp.node);
302 end
303
304 if self.pickUpRequiresMovement then
305 if pickUp.lastPos == nil then
306 pickUp.lastPos = {getWorldTranslation(pickUp.node)};
307 end
308 local _,dy,dz = worldDirectionToLocal(getParent(pickUp.node), 0,1,0);
309 local alpha = math.atan2(dz, dy);
310 setRotation(pickUp.node, alpha, 0, 0);
311
312 local x,y,z = worldToLocal(pickUp.node, pickUp.lastPos[1], pickUp.lastPos[2], pickUp.lastPos[3]);
313 pickUpIsAllowed = z < -0.01;
314 pickUpIsAllowed = pickUpIsAllowed and (alpha < math.pi/2) and (alpha > -math.pi/2);
315
316 if pickUpIsAllowed then
317 pickUpSpeed = math.min(1, Utils.vector3Length(x,y,z) / (dt*0.001));
318 end
319
320 pickUp.lastPos[1], pickUp.lastPos[2], pickUp.lastPos[3] = getWorldTranslation(pickUp.node);
321 else
322 pickUpSpeed = 1;
323 end
324
325 if self.pickUp.pickUpNeedsToBeTurnedOn and self.getIsTurnedOn ~= nil and not self:getIsTurnedOn() then
326 pickUpSpeed = 0;
327 end
328
329 end
330
331 -- check openNode
332 if pickUpIsAllowed then
333 if self.shovelOpenNode ~= nil then
334 local x,_,_ = getRotation(self.shovelOpenNode);
335 if self.shovelOpenDirection > 0 then
336 if x < self.shovelOpenRotation then
337 pickUpIsAllowed = false;
338 end;
339 else
340 if x > self.shovelOpenRotation then
341 pickUpIsAllowed = false;
342 end
343 end
344 end
345 end
346
347 --
348 local emptySpeed = self:getShovelEmptyingSpeed();
349 local fillType = self:getUnitFillType(self.shovel.fillUnitIndex);
350 local fillLevel = self:getUnitFillLevel(self.shovel.fillUnitIndex);
351 if emptySpeed > 0 then
352 if fillLevel > 0 or self.accumulatedEmptyDelta > 0 then
353 if self.shovelTipReferenceNode ~= nil then
354 -- do raycast and empty..
355
356 self.trailerFound = nil;
357 self.objectFound = nil;
358 self.curShovelTipRaycastDistance = 0;
359 local x,y,z = getWorldTranslation(self.shovelTipReferenceNode);
360 raycastAll(x, y, z, 0, -1, 0, "findTrailerRaycastCallback", self.shovelTipRaycastDistance, self);
361
362 if math.abs(self.sentCurShovelTipRaycastDistance-self.curShovelTipRaycastDistance) > 0.05 then
363 self:raiseDirtyFlags(self.shovelDirtyFlag);
364 end;
365
366 local delta = math.min(fillLevel, emptySpeed*dt) + self.accumulatedEmptyDelta;
367 self.accumulatedEmptyDelta = 0;
368 if self.trailerFound ~= nil or self.objectFound ~= nil then
369 if self.trailerFound ~= nil and self.trailerFoundSupported then
370 self.trailerFound:resetFillLevelIfNeeded(fillType);
371 local oldFillLevel = self.trailerFound:getFillLevel(fillType);
372
373 local dischargeInfos;
374 if self.fillVolumeDischargeInfos ~= nil and self.fillVolumeDischargeInfos[self.shovel.fillUnitIndex] ~= nil then
375 dischargeInfos = self.fillVolumeDischargeInfos[self.shovel.fillUnitIndex];
376 for _,node in pairs(self.fillVolumeDischargeInfos[self.shovel.fillUnitIndex].nodes) do
377 local _,dy,_ = localDirectionToWorld(getParent(node.node), 0,0,1);
378 local alpha = math.acos(dy);
379 setRotation(node.node, -alpha+math.pi/2,0,0);
380 end
381 end
382 self.trailerFound:setFillLevel(oldFillLevel + delta, fillType, false, dischargeInfos);
383 delta = self.trailerFound:getFillLevel(fillType) - oldFillLevel;
384 elseif self.objectFound ~= nil and self.objectFoundSupported then
385 -- check if feedingThrough has enough space
386 local delta1 = self.objectFound:addShovelFillLevel(self, delta, fillType);
387 if delta1 ~= nil then
388 delta = delta1;
389 end;
390 else
391 if self.objectFound ~= nil and self.objectFound.getShovelNotAllowedText ~= nil then
392 local text = self.objectFound:getShovelNotAllowedText(self);
393
394 if text ~= nil and text ~= "" then
395 self.tipErrorMessageTime = 3000;
396 self.tipErrorMessage = text;
397 end
398 end
399 -- do not empty shovel above unsupported trailer or shovel target
400 delta = 0;
401 end
402 else
403 -- tipAny
404 local minValidFillValue = TipUtil.getMinValidLiterValue(fillType);
405 if delta < minValidFillValue then
406 self.accumulatedEmptyDelta = self.accumulatedEmptyDelta + delta;
407 delta = 0;
408 if fillLevel < minValidFillValue then
409 self:setUnitFillLevel(self.shovel.fillUnitIndex, 0, FillUtil.FILLTYPE_UNKNOWN, true);
410 end
411 else
412 local sx,sy,sz;
413 local ex,ey,ez;
414
415 local infos = self.fillVolumeDischargeInfos[self.shovel.fillUnitIndex];
416 if infos ~= nil then
417 sx,sy,sz = localToWorld(infos.nodes[1].node, infos.nodes[1].width,0,0);
418 ex,ey,ez = localToWorld(infos.nodes[1].node, -infos.nodes[1].width,0,0);
419 else
420 local pickUp = self.pickUp;
421 sx,sy,sz = localToWorld(pickUp.node, pickUp.width, 0, 0);
422 ex,ey,ez = localToWorld(pickUp.node, -pickUp.width, 0, 0);
423 end
424
425 local dropped, lineOffset = TipUtil.tipToGroundAroundLine(self, delta, fillType, sx,sy,sz, ex,ey,ez, 0, nil, self.shovel.lineOffsetDrop, true, nil);
426 self.shovel.lineOffsetDrop = lineOffset;
427
428 if dropped > 0 then
429 if self.changedFillLevelCallback ~= nil then
430 if self.changedFillLevelCallbackTarget ~= nil then
431 self.changedFillLevelCallback(self.changedFillLevelCallbackTarget, self, dropped, fillType)
432 else
433 self.changedFillLevelCallback(self, dropped, fillType)
434 end
435 end
436 end
437
438 delta = dropped;
439 end
440 end;
441 if delta ~= 0 then
442 self:setUnitFillLevel(self.shovel.fillUnitIndex, fillLevel - delta, fillType, false, self.fillVolumeUnloadInfos[self.shovel.unloadInfoIndex]);
443 self.emptyEffectActive = true;
444 end;
445 end;
446 end;
447 end
448
449 -- always try to refill shovel
450 local fillLevel = self:getUnitFillLevel(self.shovel.fillUnitIndex);
451 local capacity = self:getUnitCapacity(self.shovel.fillUnitIndex);
452
453 if self.pickUp.node ~= nil and pickUpIsAllowed and fillLevel < capacity then
454 local pickUp = self.pickUp;
455
456 local length = pickUp.length;
457 local maxRadius = 1.75;
458 local zPos = math.min(pickUp.length/2, maxRadius);
459
460 local foundFillType = false;
461
462 while true do
463 local heapFillType = FillUtil.FILLTYPE_UNKNOWN;
464
465 for i=1, 2 do
466 local width = i * pickUp.width / 2;
467 local x0,y0,z0 = localToWorld(pickUp.node, math.min(-width+zPos, 0), 0, zPos);
468 local x1,y1,z1 = localToWorld(pickUp.node, math.max(width-zPos, 0), 0, zPos);
469
470 heapFillType = TipUtil.getFillTypeAtLine(x0,y0,z0, x1,y1,z1, math.min(length, maxRadius));
471 if heapFillType ~= FillUtil.FILLTYPE_UNKNOWN then
472 break;
473 end;
474 end;
475
476 if heapFillType ~= FillUtil.FILLTYPE_UNKNOWN and self:allowFillType(heapFillType) and self:allowUnitFillType(self.shovel.fillUnitIndex, heapFillType) then
477 local emptyFactor = 1.0 - (emptySpeed / self.shovelEmptySpeed);
478 local fillFactor = pickUpSpeed * emptyFactor; -- * 0.001 * dt;
479
480 local pickUpDelta = math.min(emptyFactor*(capacity - fillLevel), self.shovelFillLitersPerSecond*dt + self.accumulatedFillDelta);
481
482 pickUpDelta = pickUpDelta * math.min(1, fillFactor);
483
484 if length > maxRadius * 2 then
485 pickUpDelta = pickUpDelta / math.floor(self.pickUp.length / (maxRadius * 2));
486 end;
487
488
489 local sx,sy,sz = localToWorld(pickUp.node, -pickUp.width, pickUp.yOffset, zPos);
490 local ex,ey,ez = localToWorld(pickUp.node, pickUp.width, pickUp.yOffset, zPos);
491
492 local sh = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, sx,sy,sz);
493 local eh = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, ex,ey,ez);
494 if sh < 0.1 then
495 sy = sh;
496 end
497 if eh < 0.1 then
498 ey = eh;
499 end
500
501 local innerRadius = math.min(length, maxRadius); --0.05;
502 local radius = nil; --1.0;
503
504 pickUp.remainingDelta = pickUp.remainingDelta + pickUpDelta;
505 if pickUp.remainingDelta > 20 then
506 local fillLevel = self:getUnitFillLevel(self.shovel.fillUnitIndex);
507 local capacity = self:getUnitCapacity(self.shovel.fillUnitIndex);
508 pickUpDelta = math.min(pickUp.remainingDelta, capacity-fillLevel);
509 pickUp.remainingDelta = pickUp.remainingDelta - pickUpDelta;
510 else
511 pickUpDelta = 0;
512 end;
513
514 -- (vehicle, delta, fillType, sx,sy,sz, ex,ey,ez, innerRadius, radius, lineOffset, limitToLineHeight, occlusionAreas)
515 local fillDelta, lineOffset = TipUtil.tipToGroundAroundLine(self, -pickUpDelta, heapFillType, sx,sy,sz, ex,ey,ez, innerRadius, radius, self.shovel.lineOffsetPickUp, true, nil);
516 self.shovel.lineOffsetPickUp = lineOffset;
517
518 self.accumulatedFillDelta = math.min(pickUpDelta + fillDelta, TipUtil.getMinValidLiterValue(heapFillType));
519
520 if fillDelta < 0 then
521 self:setUnitFillLevel(self.shovel.fillUnitIndex, fillLevel - fillDelta, heapFillType, false, self.fillVolumeLoadInfos[self.shovel.unloadInfoIndex]);
522
523 self.fillEffectActive = true;
524
525 if self.changedFillLevelCallback ~= nil then
526 if self.changedFillLevelCallbackTarget ~= nil then
527 self.changedFillLevelCallback(self.changedFillLevelCallbackTarget, self, fillDelta, heapFillType);
528 else
529 self.changedFillLevelCallback(self, fillDelta, heapFillType);
530 end
531 end
532 end
533
534 if foundFillType then
535 break;
536 end;
537 foundFillType = true;
538 else
539 self.accumulatedFillDelta = 0;
540 end
541
542 if length > maxRadius * 2 then
543 length = length - maxRadius * 2;
544 if length > maxRadius * 2 then
545 zPos = zPos + maxRadius * 2;
546 else
547 zPos = zPos + (pickUp.length-zPos+maxRadius)/2;
548 length = pickUp.length-zPos;
549 end;
550 else
551 break;
552 end;
553 end;
554 end
555 end;
556
557 if self.fillEffectActive ~= self.sentFillEffectActive or self.emptyEffectActive ~= self.sentEmptyEffectActive then
558 self:raiseDirtyFlags(self.shovelDirtyFlag);
559 self:updateShovelParticleSystems(self.emptyEffectActive, self.fillEffectActive);
560 end;
561
562 end;
563
564 if self.isClient then
565
566 if not self.fillEffectActive and self.lastFillEffectActiveTime > 0 and self.lastFillEffectActiveTime + self.effectsTimeout < g_currentMission.time then
567 self.lastFillEffectActiveTime = 0;
568 if self.lastFillPS ~= nil then
569 ParticleUtil.setEmittingState(self.lastFillPS, false);
570 end
571 if self.shovelFillEffects ~= nil then
572 EffectManager:stopEffects(self.shovelFillEffects);
573 end
574 end
575
576 if not self.emptyEffectActive and self.lastEmptyEffectActiveTime > 0 and self.lastEmptyEffectActiveTime + self.fillEffectsTimeout < g_currentMission.time then
577 self.lastEmptyEffectActiveTime = 0;
578 if self.lastEmptyPS ~= nil then
579 ParticleUtil.setEmittingState(self.lastEmptyPS, false);
580 end
581 if self.shovelEmptyEffects ~= nil then
582 EffectManager:stopEffects(self.shovelEmptyEffects);
583 end
584 end
585
586 if self.emptyEffectActive then
587 if self.shovelEmptyEffects ~= nil then
588 for _, effect in pairs(self.shovelEmptyEffects) do
589 effect:setUnloadingDistance(self.curShovelTipRaycastDistance);
590 end;
591 end
592
593 if self.lastEmptyPS ~= nil then
594 self.curShovelTipRaycastDistance = self.curShovelTipRaycastDistance - 0.3; -- size of particles
595
596 local dx,dy,dz = localDirectionToWorld(self.emptyEmitterShape, 0,0,1);
597 local factor = 1-(math.abs(dy)/1);
598 local maxFactor = 28*math.sqrt(self.curShovelTipRaycastDistance)*0.3162/100;
599 factor = 1 + factor * maxFactor;
600
601 local lifespan = math.sqrt(self.curShovelTipRaycastDistance)*379.47; -- on gravity y factor of -1.5
602
603 ParticleUtil.setParticleLifespan(self.lastEmptyPS, lifespan/factor);
604 end
605 end;
606 end;
607end;

getAllowFillShovel

Description
Returns fill shovel is allowed
Definition
getAllowFillShovel(integer fillType)
Arguments
integerfillTypefill type
Return Values
booleanallowedfill shovel is allowed
Code
616function Shovel:getAllowFillShovel(fillType)
617 if self.shovelOpenNode ~= nil then
618 local x,_,_ = getRotation(self.shovelOpenNode);
619 if self.shovelOpenDirection > 0 then
620 if x < self.shovelOpenRotation then
621 return false;
622 end;
623 else
624 if x > self.shovelOpenRotation then
625 return false;
626 end;
627 end
628 end;
629 if self:getShovelEmptyingSpeed() > 0 then
630 return false;
631 end;
632 return self:allowFillType(fillType, false)
633end;

getShovelEmptyingSpeed

Description
Returns shovel emptying speed depending on the shovel world rotation
Definition
getShovelEmptyingSpeed()
Return Values
floatemptyingSpeedshovel emptying speed
Code
638function Shovel:getShovelEmptyingSpeed()
639 if self.shovelOpenNode ~= nil then
640 local x,_,_ = getRotation(self.shovelOpenNode);
641 if self.shovelOpenDirection > 0 then
642 if x < self.shovelOpenRotation then
643 return 0;
644 end;
645 else
646 if x > self.shovelOpenRotation then
647 return 0;
648 end;
649 end
650 end;
651 if self.shovelTipReferenceNode ~= nil then
652 local dx,dy,dz = localDirectionToWorld(self.shovelTipReferenceNode, 0,0,1);
653 -- more than 55deg rotated towards the ground
654 --if dy < -0.573576436351 then
655 if dy < self.shovelEmptyStartCosAngle then
656 local scale = math.min((self.shovelEmptyStartCosAngle-dy) / (self.shovelEmptyStartCosAngle - self.shovelEmptyFullCosAngle), 1);
657 return self.shovelEmptySpeed * scale;
658 end;
659 end;
660 return 0;
661end;

updateShovelParticleSystems

Description
Update shovel particle systems
Definition
updateShovelParticleSystems(boolean emptyEffectActive, boolean fillEffectActive)
Arguments
booleanemptyEffectActiveempty effect is active
booleanfillEffectActivefill effect is active
Code
667function Shovel:updateShovelParticleSystems(emptyEffectActive, fillEffectActive)
668 if self.isClient then
669 local fillType = self:getUnitFillType(self.shovel.fillUnitIndex);
670
671 if emptyEffectActive then
672 self.lastEmptyEffectActiveTime = g_currentMission.time;
673 local ps = self.emptyReferenceParticleSystems[fillType];
674 if self.emptyEmitterShape ~= nil and ps ~= nil then
675 ParticleUtil.resetNumOfEmittedParticles(ps);
676 ParticleUtil.setEmittingState(ps, true);
677 self.lastEmptyPS = ps;
678 elseif self.shovelEmptyEffects ~= nil then
679 EffectManager:setFillType(self.shovelEmptyEffects, fillType)
680 EffectManager:startEffects(self.shovelEmptyEffects);
681 end;
682 end
683
684 if fillEffectActive then
685 self.lastFillEffectActiveTime = g_currentMission.time;
686 local ps = self.fillReferenceParticleSystems[fillType];
687 if self.fillEmitterShape ~= nil and ps ~= nil then
688 ParticleUtil.resetNumOfEmittedParticles(ps);
689 ParticleUtil.setEmittingState(ps, true);
690 self.lastFillPS = ps;
691 elseif self.shovelFillEffects ~= nil then
692 EffectManager:setFillType(self.shovelFillEffects, fillType)
693 EffectManager:startEffects(self.shovelFillEffects);
694 end;
695 end
696
697 end;
698end

setFillLevel

Description
Set fill level (filling all fill units that allow given fill type)
Definition
setFillLevel(float filllevel, integer fillType, boolean force, table fillInfo)
Arguments
floatfilllevelnew fill level
integerfillTypefill type
booleanforceforce action
tablefillInfofill info for fill volume
Code
706function Shovel:setFillLevel(oldSetFillLevel, fillLevel, fillType, force, fillInfo)
707 if oldSetFillLevel ~= nil then
708 oldSetFillLevel(self, fillLevel, fillType, force, fillInfo);
709 end;
710end;

setUnitFillLevel

Description
Set unit fill level
Definition
setUnitFillLevel(integer fillUnitIndex, float fillLevel, integer fillType, boolean force, table fillInfo)
Arguments
integerfillUnitIndexindex of fill unit
floatfillLevelnew fill level
integerfillTypefill type
booleanforceforce action
tablefillInfofill info for fill volume
Code
719function Shovel:setUnitFillLevel(superFunc, fillUnitIndex, fillLevel, fillType, force, fillInfo)
720 local fillLevel = self.fillUnits[self.shovel.fillUnitIndex].fillLevel;
721
722 superFunc(self, fillUnitIndex, fillLevel, fillType, force, fillInfo);
723
724 -- adjust emit rate of empty PS
725 if self.lastEmptyPS ~= nil and fillUnitIndex == self.shovel.fillUnitIndex then
726 local delta = self.fillUnits[self.shovel.fillUnitIndex].fillLevel - fillLevel;
727 if delta < 0 then
728 local f = delta / self.emptySpeed;
729 ParticleUtil.setEmitCountScale(self.lastEmptyPS, f);
730 end
731 end
732end

findTrailerRaycastCallback

Description
Raycast callback
Definition
findTrailerRaycastCallback(integer transformId, float x, float y, float z, float distance)
Arguments
integertransformIdid raycasted object
floatxx raycast position
floatyy raycast position
floatzz raycast position
floatdistancedistance to raycast position
Code
741function Shovel:findTrailerRaycastCallback(transformId, x, y, z, distance)
742 local fillType = self.fillUnits[self.shovel.fillUnitIndex].currentFillType;
743
744 if self.trailerFound == nil then
745 self.curShovelTipRaycastDistance = distance;
746 end;
747
748 local trailer = g_currentMission.objectToTrailer[transformId];
749 if trailer ~= nil and trailer ~= self then
750 if trailer:allowFillType(fillType) and trailer.getAllowFillFromAir ~= nil and trailer:getAllowFillFromAir() then
751 self.trailerFound = trailer;
752 self.trailerFoundSupported = true;
753 else
754 if self.trailerFound == nil then
755 self.trailerFound = trailer;
756 self.trailerFoundSupported = false;
757 end
758 end
759
760 --get distance to trailer ground, not to exactFillRootNode
761 if transformId ~= trailer.exactFillRootNode then
762 self.curShovelTipRaycastDistance = distance;
763 end;
764 end;
765 local object = g_currentMission:getNodeObject(transformId);
766 if object ~= nil then
767 -- fix for greenhouse placeable
768 if object.manurePlaneObject ~= nil and transformId == object.manurePlaneCollisionNode then
769 object = object.manurePlaneObject;
770 end
771 end;
772 if object ~= nil and object ~= self and object.addShovelFillLevel ~= nil and object.getAllowShovelFillType ~= nil then
773 if object:getAllowShovelFillType(fillType) then
774 self.objectFound = object;
775 self.objectFoundSupported = true;
776 return false;
777 else
778 if self.objectFound == nil then
779 self.objectFound = object;
780 self.objectFoundSupported = false;
781 end
782 end
783 end;
784
785 return true;
786end;

fillShovelFromTrigger

Description
Fill shovel from trigger
Definition
fillShovelFromTrigger(table shovelTrigger, float deltaFillLevel, integer fillType, float dt)
Arguments
tableshovelTriggershovelTrigger
floatdeltaFillLevelfill level to fill
integerfillTypefill type to fill
floatdttime since last call in ms
Return Values
floatrealFillDeltareal fill delta
Code
795function Shovel:fillShovelFromTrigger(shovelTrigger, deltaFillLevel, fillType, dt)
796 if self:getAllowFillShovel(fillType) and (self.movingDirection == self.vehicleMovingDirection or self.ignoreVehicleDirectionOnLoad) then
797 local fillFactor = 1;
798 if not self.ignoreVehicleDirectionOnLoad then
799 fillFactor = math.min(math.abs(self:getLastSpeed()), 5)*0.1; -- <=5km/h = 50% speed
800 end;
801 deltaFillLevel = math.min(deltaFillLevel, self.shovelFillLitersPerSecond*dt*fillFactor);
802 self:resetFillLevelIfNeeded(fillType);
803
804 local oldFillLevel = self:getFillLevel(fillType);
805
806 local loadInfos = self.fillVolumeLoadInfos[1];
807 if loadInfos == nil then
808 self:setFillLevel(oldFillLevel + deltaFillLevel, fillType);
809 else
810 self:setFillLevel(oldFillLevel + deltaFillLevel, fillType, false, loadInfos);
811 end;
812
813 local finalDelta = self:getFillLevel(fillType) - oldFillLevel;
814
815 return finalDelta;
816 end
817 return 0;
818end;

loadAreaFromXML

Description
Load area from xml
Definition
loadAreaFromXML(table area, integer xmlFile, string key)
Arguments
tableareaarea
integerxmlFileid of xml object
stringkeykey
Return Values
booleanareaLoadedarea successfully loaded
Code
826function Shovel:loadAreaFromXML(area, xmlFile, key)
827 local start = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#startIndex"));
828 local width = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#widthIndex"));
829 local height = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#heightIndex"));
830
831 if start ~= nil and width ~= nil and height ~= nil then
832 area.start = start;
833 area.width = width;
834 area.height = height;
835 return true;
836 end;
837 return false;
838end;

getIsAreaActive

Description
Returns if area is active
Definition
getIsAreaActive(table area)
Arguments
tableareaarea to check
Return Values
booleanisActivearea is active
Code
844function Shovel:getIsAreaActive(area)
845 return true;
846end;

setChangedFillLevelCallback

Description
Set fill level changed callback (e.g. by bunker silo)
Definition
setChangedFillLevelCallback(function callback, table callbackTarget)
Arguments
functioncallbackcallback
tablecallbackTargetcallback target
Code
852function Shovel:setChangedFillLevelCallback(callback, callbackTarget)
853 self.changedFillLevelCallback = callback;
854 self.changedFillLevelCallbackTarget = callbackTarget;
855end