LUADOC - Farming Simulator 17

Printable Version

Script v1.4.4.0

Engine v7.0.0.2

Foundation Reference

Windrower

Description
Class for all windrowers
Functions

initSpecialization

Description
Called on specialization initializing
Definition
initSpecialization()
Code
17function Windrower.initSpecialization()
18 WorkArea.registerAreaType("windrower");
19 WorkArea.registerAreaType("windrowerDrop");
20end

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
26function Windrower.prerequisitesPresent(specializations)
27 return SpecializationUtil.hasSpecialization(WorkArea, specializations) and SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations);
28end

preLoad

Description
Called before loading
Definition
preLoad(table savegame)
Arguments
tablesavegamesavegame
Code
33function Windrower:preLoad(savegame)
34 self.loadWorkAreaFromXML = Utils.overwrittenFunction(self.loadWorkAreaFromXML, Windrower.loadWorkAreaFromXML);
35 self.loadWindrowerFromXML = Utils.overwrittenFunction(self.loadWindrowerFromXML, Windrower.loadWindrowerFromXML);
36end

load

Description
Called on loading
Definition
load(table savegame)
Arguments
tablesavegamesavegame
Code
41function Windrower:load(savegame)
42 self.updateWindrower = Windrower.updateWindrower;
43 self.doCheckSpeedLimit = Utils.overwrittenFunction(self.doCheckSpeedLimit, Windrower.doCheckSpeedLimit);
44
45 self.processWindrowerAreas = Windrower.processWindrowerAreas;
46
47 if self.isClient then
48 self.windrowerTurnedOnRotationNodes = Utils.loadRotationNodes(self.xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "windrower", self.components);
49 end
50
51 if hasXMLProperty(self.xmlFile, "vehicle.animation") then
52 print("Warning: Windrower 'vehicle.animation' is not supported anymore in "..self.configFileName..". Use vehicle.windrowers.windrower instead.");
53 end
54
55 self.windrowers = {};
56 local i = 0;
57 while true do
58 local key = string.format("vehicle.windrowers.windrower(%d)", i);
59 if not hasXMLProperty(self.xmlFile, key) then
60 break;
61 end
62
63 local windrower = {};
64 if self:loadWindrowerFromXML(windrower, self.xmlFile, key, i) then
65 table.insert(self.windrowers, windrower);
66 self:updateWindrower(windrower);
67 end;
68 i = i + 1;
69 end
70
71 local numWindrowerDropAreas = table.getn(self:getTypedWorkAreas(WorkArea.AREATYPE_WINDROWERDROP));
72 if numWindrowerDropAreas == 0 then
73 print("Warning: No drop areas specified in '"..self.configFileName.."'");
74 else
75 if numWindrowerDropAreas ~= 1 and numWindrowerDropAreas ~= table.getn(self:getTypedWorkAreas(WorkArea.AREATYPE_WINDROWER)) then
76 print("Warning: Number of cutting areas and drop areas should be equal in '"..self.configFileName.."'");
77 end
78 end
79
80 self.accumulatedFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
81
82 if hasXMLProperty(self.xmlFile, "vehicle.windrowerParticleSystems") then
83 local fillTypes = {};
84 local fillTypeCategories = getXMLString(self.xmlFile, "vehicle.windrowerParticleSystems#fillTypeCategories");
85 local fillTypeNames = getXMLString(self.xmlFile, "vehicle.windrowerParticleSystems#fillTypes");
86 if fillTypeCategories ~= nil and fillTypeNames == nil then
87 fillTypes = FillUtil.getFillTypeByCategoryName(fillTypeCategories, "Warning: '"..self.configFileName.. "' has invalid fillTypeCategory '%s'.")
88 elseif fillTypeCategories == nil and fillTypeNames ~= nil then
89 fillTypes = FillUtil.getFillTypesByNames(fillTypeNames, "Warning: '"..self.configFileName.. "' has invalid fillType '%s'.")
90 else
91 print("Warning: '"..self.configFileName.. "' a windrower particleSystem needs either the 'fillTypeCategories' or 'fillTypes' attribute.")
92 end
93
94 self.windrowerParticleSystems = {}
95 self.sortedWindrowerParticleSystems = {}
96 local i=0;
97 while true do
98 local key = string.format("vehicle.windrowerParticleSystems.emitterShape(%d)", i);
99 if not hasXMLProperty(self.xmlFile, key) then
100 break
101 end
102 local emitterShape = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#node"));
103 local particleType = getXMLString(self.xmlFile, key.."#particleType")
104 if emitterShape ~= nil then
105 local workAreaIndex = Utils.getNoNil(getXMLInt(self.xmlFile, key.."#workAreaIndex"), 0) + 1;
106 if workAreaIndex ~= nil and self.workAreas[workAreaIndex] ~= nil then
107 if self.windrowerParticleSystems[workAreaIndex] == nil then
108 self.windrowerParticleSystems[workAreaIndex] = {}
109 end
110
111 for _, fillType in pairs(fillTypes) do
112 local particleSystem = MaterialUtil.getParticleSystem(fillType, particleType)
113 if particleSystem ~= nil then
114 if self.windrowerParticleSystems[workAreaIndex][fillType] == nil then
115 self.windrowerParticleSystems[workAreaIndex][fillType] = {}
116 end
117
118 local currentPS = ParticleUtil.copyParticleSystem(self.xmlFile, key, particleSystem, emitterShape)
119 currentPS.disableTime = 0;
120 currentPS.isEnabled = false;
121 table.insert(self.windrowerParticleSystems[workAreaIndex][fillType], currentPS)
122 table.insert(self.sortedWindrowerParticleSystems, currentPS)
123 end
124 end
125 end
126 end
127
128 i=i+1;
129 end
130 end
131
132 if self.isClient then
133 self.sampleWindrower = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.windrowerSound", nil, self.baseDirectory);
134 end
135
136 self.isWindrowerSpeedLimitActive = false;
137
138 self.showFieldNotOwnedWarning = false
139
140 self.aiRequiredMinGrowthState = 0;
141 self.aiRequiredMaxGrowthState = g_currentMission.numWindrowChannels;
142 self.aiUseDensityHeightMap = true;
143 self.aiUseWindrowFruitType = true;
144
145 table.insert(self.terrainDetailRequiredValueRanges, {g_currentMission.grassValue, g_currentMission.grassValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels});
146
147 self.windrowerGroundFlag = self:getNextDirtyFlag();
148end

delete

Description
Called on deleting
Definition
delete()
Code
152function Windrower:delete()
153 if self.isClient then
154 SoundUtil.deleteSample(self.sampleWindrower);
155 end
156 ParticleUtil.deleteParticleSystems(self.sortedWindrowerParticleSystems)
157end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
169function Windrower:readStream(streamId, connection)
170 for _, ps in ipairs(self.sortedWindrowerParticleSystems) do
171 ParticleUtil.setEmittingState(ps, streamReadBool(streamId));
172 end
173end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
179function Windrower:writeStream(streamId, connection)
180 for _, ps in ipairs(self.sortedWindrowerParticleSystems) do
181 streamWriteBool(streamId, ps.isEnabled);
182 end
183end

readUpdateStream

Description
Called on on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
190function Windrower:readUpdateStream(streamId, timestamp, connection)
191 if connection:getIsServer() then
192 if streamReadBool(streamId) then
193 for _, ps in ipairs(self.sortedWindrowerParticleSystems) do
194 ParticleUtil.setEmittingState(ps, streamReadBool(streamId));
195 end
196 self.showFieldNotOwnedWarning = streamReadBool(streamId)
197 end
198 end
199end

writeUpdateStream

Description
Called on on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
206function Windrower:writeUpdateStream(streamId, connection, dirtyMask)
207 if not connection:getIsServer() then
208 if streamWriteBool(streamId, bitAND(dirtyMask, self.windrowerGroundFlag) ~= 0) then
209 for _, ps in ipairs(self.sortedWindrowerParticleSystems) do
210 streamWriteBool(streamId, ps.isEnabled);
211 end
212 streamWriteBool(streamId, self.showFieldNotOwnedWarning)
213 end
214 end
215end

update

Description
Called on update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
220function Windrower:update(dt)
221 if self.isClient then
222 Utils.updateRotationNodes(self, self.windrowerTurnedOnRotationNodes, dt, self:getIsActive() and self:getIsTurnedOn() );
223 end
224end

updateTick

Description
Called on update tick
Definition
updateTick(float dt)
Arguments
floatdttime since last call in ms
Code
229function Windrower:updateTick(dt)
230 local showFieldNotOwnedWarning = false
231 self.isWindrowerSpeedLimitActive = false;
232 if self:getIsActive() then
233 if self:getIsTurnedOn() then
234 local hasGroundContact, typedWorkAreas = self:getIsTypedWorkAreaActive(WorkArea.AREATYPE_WINDROWER);
235 self.hasGroundContact = hasGroundContact;
236
237 if hasGroundContact then
238 self.isWindrowerSpeedLimitActive = true;
239 if self.isServer then
240
241 local workAreas = {};
242 local typedWorkAreasDrop, showWarning = self:getTypedNetworkAreas(WorkArea.AREATYPE_WINDROWERDROP, true);
243 showFieldNotOwnedWarning = showWarning;
244
245 if not showWarning then
246
247 for k, workArea in pairs(typedWorkAreas) do
248 if self:getIsWorkAreaActive(workArea) then
249 local x,_,z = getWorldTranslation(workArea.start);
250 local x1,_,z1 = getWorldTranslation(workArea.width);
251 local x2,_,z2 = getWorldTranslation(workArea.height);
252
253 local dropArea = typedWorkAreasDrop[workArea.dropAreaIndex];
254 local dx, dz = dropArea[1], dropArea[2];
255 local dx1,dz1 = dropArea[3], dropArea[4];
256 local dx2,dz2 = dropArea[5], dropArea[6];
257
258 table.insert(workAreas, {x,z, x1,z1, x2,z2, dx,dz, dx1,dz1, dx2,dz2, 0, k});
259 end
260 end
261
262 if table.getn(typedWorkAreas) > 0 then
263 local workAreasRet, fruitType = self:processWindrowerAreas(workAreas, self.accumulatedWorkAreaValues, self.accumulatedFruitType);
264
265 if table.getn(workAreasRet) > 0 then
266 self.accumulatedFruitType = fruitType;
267
268 if self:getLastSpeed(true) > 0.5 then
269 for i=1, table.getn(workAreasRet) do
270 if workAreasRet[i][13] > 0 then
271 local workArea = workAreasRet[i][14];
272 local psPerWorkArea = self.windrowerParticleSystems[workArea]
273 if psPerWorkArea ~= nil then
274 local fillType = FruitUtil.fruitTypeToWindrowFillType[fruitType];
275 local psPerFillType = psPerWorkArea[fillType]
276 if psPerFillType ~= nil then
277 for _, ps in pairs(psPerFillType) do
278 ps.disableTime = g_currentMission.time + 300;
279 if not ps.isEnabled then
280 ps.isEnabled = true;
281 self:raiseDirtyFlags(self.windrowerGroundFlag);
282 if self.isClient then
283 ParticleUtil.setEmittingState(ps, true);
284 end
285 end
286 end
287 end
288 end
289 end
290 end
291 end
292 end
293 end
294
295 end
296 end
297 end
298
299 if self.isClient and self:getIsActiveForSound() then
300 SoundUtil.playSample(self.sampleWindrower, 0, 0, nil);
301 end
302
303 if self.isServer then
304 for _, ps in ipairs(self.sortedWindrowerParticleSystems) do
305 if g_currentMission.time > ps.disableTime then
306 ps.isEnabled = false;
307 self:raiseDirtyFlags(self.windrowerGroundFlag);
308 if self.isClient then
309 ParticleUtil.setEmittingState(ps, false);
310 end
311 end
312 end
313 end
314 end
315 end
316
317 if self.isServer then
318 if showFieldNotOwnedWarning ~= self.showFieldNotOwnedWarning then
319 self.showFieldNotOwnedWarning = showFieldNotOwnedWarning
320 self:raiseDirtyFlags(self.windrowerGroundFlag);
321 end
322 end
323
324 if Utils.areRotationNodesRunning(self.windrowerTurnedOnRotationNodes) then
325 for _, windrower in pairs(self.windrowers) do
326 self:updateWindrower(windrower);
327 end
328 end
329end

draw

Description
Called on draw
Definition
draw()
Code
333function Windrower:draw()
334 if self.isClient then
335 if self.showFieldNotOwnedWarning then
336 g_currentMission:showBlinkingWarning(g_i18n:getText("warning_youDontOwnThisField"))
337 end
338 end
339end

onDeactivateSounds

Description
Called on deactivating sounds
Definition
onDeactivateSounds()
Code
343function Windrower:onDeactivateSounds()
344 if self.isClient then
345 SoundUtil.stopSample(self.sampleWindrower, true);
346 end
347end

onTurnedOff

Description
Called on turn off
Definition
onTurnedOff(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
352function Windrower:onTurnedOff(noEventSend)
353 if self.accumulatedWorkAreaValues ~= nil then
354 for k,_ in pairs(self.accumulatedWorkAreaValues) do
355 self.accumulatedWorkAreaValues[k] = 0;
356 end
357 end
358
359 if self.isServer then
360 for _, ps in ipairs(self.sortedWindrowerParticleSystems) do
361 ps.isEnabled = false;
362 self:raiseDirtyFlags(self.windrowerGroundFlag);
363 if self.isClient then
364 ParticleUtil.setEmittingState(ps, false);
365 end
366 end
367 end
368
369 Windrower.onDeactivateSounds(self)
370end

loadWorkAreaFromXML

Description
Loads work areas from xml
Definition
loadWorkAreaFromXML(table workArea, integer xmlFile, string key)
Arguments
tableworkAreaworkArea
integerxmlFileid of xml object
stringkeykey
Return Values
booleansuccesssuccess
Code
378function Windrower:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key)
379 local retValue = true;
380 if superFunc ~= nil then
381 retValue = superFunc(self, workArea, xmlFile, key)
382 end
383
384 if workArea.type == WorkArea.AREATYPE_DEFAULT then
385 workArea.type = WorkArea.AREATYPE_WINDROWER;
386 end
387
388 if workArea.type == WorkArea.AREATYPE_WINDROWER then
389 workArea.windrowerParticleSystemIndex = getXMLInt(xmlFile, key .. "#particleSystemIndex");
390 workArea.dropAreaIndex = Utils.getNoNil(getXMLInt(xmlFile, key .. "#dropAreaIndex"), 0) + 1;
391
392 if self.accumulatedWorkAreaValues == nil then
393 self.accumulatedWorkAreaValues = {};
394 end
395 self.accumulatedWorkAreaValues[table.getn(self.accumulatedWorkAreaValues)+1] = 0;
396 end
397
398 return retValue;
399end

doCheckSpeedLimit

Description
Returns if speed limit should be checked
Definition
doCheckSpeedLimit()
Return Values
booleancheckSpeedlimitcheck speed limit
Code
404function Windrower:doCheckSpeedLimit(superFunc)
405 local parent = false;
406 if superFunc ~= nil then
407 parent = superFunc(self);
408 end
409
410 return parent or self.isWindrowerSpeedLimitActive;
411end

updateWindrower

Description
Update windrower spike nodes
Definition
updateWindrower(table windrower)
Arguments
tablewindrowerwindrower to update
Code
416function Windrower:updateWindrower(windrower)
417 local _,y,_ = getRotation(windrower.node)
418 y = y % (2*math.pi)
419 if windrower.dir == -1 then
420 y = math.abs(2*math.pi-y);
421 end
422
423 for k, spike in pairs(windrower.spikes) do
424 local yRot = ((y - (k-1)*windrower.yRotOffset) + 2*math.pi) % (2*math.pi);
425 local alpha = 0;
426
427 if yRot > windrower.moveUpStart and yRot <= windrower.moveUpEnd then
428 alpha = 1 - (windrower.moveUpEnd-yRot) / (windrower.moveUpEnd-windrower.moveUpStart);
429 elseif yRot > windrower.moveDownStart and yRot <= windrower.moveDownEnd then
430 alpha = ((windrower.moveDownEnd-yRot) / (windrower.moveDownEnd-windrower.moveDownStart));
431 elseif yRot > windrower.moveUpEnd and yRot <= windrower.moveDownStart then
432 alpha = 1;
433 end
434
435 setRotation(spike.node, 0, 0, windrower.maxRotZ*alpha*spike.dir);
436 end
437end

loadWindrowerFromXML

Description
Called on loading
Definition
loadWindrowerFromXML(table savegame)
Arguments
tablesavegamesavegame
Code
442function Windrower:loadWindrowerFromXML(superFunc, windrower, xmlFile, key, index)
443 if superFunc ~= nil then
444 if not superFunc(self, windrower, xmlFile, key, index) then
445 return false;
446 end;
447 end;
448
449 windrower.node = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key .. "#index"));
450 windrower.spikes = {};
451 windrower.maxRotZ = math.rad(getXMLFloat(xmlFile, key.."#spikeMaxRotZ"));
452 windrower.dir = Utils.getNoNil(getXMLInt(xmlFile, key.."#dir"), 1);
453
454 local moveUpRange = Utils.getRadiansFromString(getXMLString(xmlFile, key .. "#moveUpRange"), 2);
455 local moveDownRange = Utils.getRadiansFromString(getXMLString(xmlFile, key .. "#moveDownRange"), 2);
456 windrower.moveUpStart = moveUpRange[1];
457 windrower.moveUpEnd = moveUpRange[2];
458 windrower.moveDownStart = moveDownRange[1];
459 windrower.moveDownEnd = moveDownRange[2];
460
461 local j = 0;
462 while true do
463 local spikeKey = string.format(key .. ".spike(%d)", j);
464 if not hasXMLProperty(xmlFile, spikeKey) then
465 break;
466 end
467 local spike = {}
468 spike.node = Utils.indexToObject(self.components, getXMLString(xmlFile, spikeKey .. "#index"))
469 spike.dir = Utils.getNoNil(getXMLInt(xmlFile, spikeKey.."#dir"), 1)
470 local _,y,_ = getRotation(getParent(spike.node));
471 spike.yRotOffset = y;
472 table.insert(windrower.spikes, spike);
473 j = j + 1
474 end
475
476 windrower.yRotOffset = (2*math.pi) / #windrower.spikes;
477
478 return true;
479end;

getDefaultSpeedLimit

Description
Returns default speed limit
Definition
getDefaultSpeedLimit()
Return Values
floatspeedLimitspeed limit
Code
484function Windrower.getDefaultSpeedLimit()
485 return 15;
486end

processWindrowerAreas

Description
Process windrower areas
Definition
processWindrowerAreas(table workAreas, table accumulatedWorkAreaValues, integer accumulatedFruitType)
Arguments
tableworkAreaswork areas to process
tableaccumulatedWorkAreaValuescontains remaining fill levels to drop
integeraccumulatedFruitTypeaccumulated fruit type
Return Values
tableworkAreasRetwork areas that dropped
integerfruitTypefruit type
Code
495function Windrower:processWindrowerAreas(workAreas, accumulatedWorkAreaValues, accumulatedFruitType)
496
497 local numAreas = table.getn(workAreas);
498 local fruitType = FruitUtil.FRUITTYPE_GRASS;
499 local fruitTypeFix = false;
500
501 local workAreasRet = {};
502 for i=1, numAreas do
503
504 local x0 = workAreas[i][1];
505 local z0 = workAreas[i][2];
506 local x1 = workAreas[i][3];
507 local z1 = workAreas[i][4];
508 local x2 = workAreas[i][5];
509 local z2 = workAreas[i][6];
510 local dx0 = workAreas[i][7];
511 local dz0 = workAreas[i][8];
512 local dx1 = workAreas[i][9];
513 local dz1 = workAreas[i][10];
514 local dx2 = workAreas[i][11];
515 local dz2 = workAreas[i][12];
516
517 -- pick up
518 local hx = x2 - x0;
519 local hz = z2 - z0;
520 local hLength = Utils.vector2Length(hx, hz);
521 local hLength_2 = 0.5 * hLength;
522
523 local wx = x1 - x0;
524 local wz = z1 - z0;
525 local wLength = Utils.vector2Length(wx, wz);
526
527 local sx = x0 + (hx * 0.5) + ((wx/wLength)*hLength_2);
528 local sz = z0 + (hz * 0.5) + ((wz/wLength)*hLength_2);
529
530 local ex = x1 + (hx * 0.5) - ((wx/wLength)*hLength_2);
531 local ez = z1 + (hz * 0.5) - ((wz/wLength)*hLength_2);
532
533 local sy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, sx,0,sz);
534 local ey = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, ex,0,ez);
535
536 local liters = 0;
537 if fruitTypeFix then
538 liters = -TipUtil.tipToGroundAroundLine(self, -math.huge, FruitUtil.fruitTypeToWindrowFillType[fruitType], sx,sy,sz, ex,ey,ez, hLength_2, nil, nil, false, nil);
539 else
540 -- first try dry grass to avoid wet grass destroying dry grass
541 fruitType = FruitUtil.FRUITTYPE_DRYGRASS;
542 liters = -TipUtil.tipToGroundAroundLine(self, -math.huge, FruitUtil.fruitTypeToWindrowFillType[FruitUtil.FRUITTYPE_DRYGRASS], sx,sy,sz, ex,ey,ez, hLength_2, nil, nil, false, nil);
543
544 if liters == 0 then
545 for fruitId=1, FruitUtil.NUM_FRUITTYPES do
546 if fruitId ~= FruitUtil.FRUITTYPE_DRYGRASS then
547 local ids = g_currentMission.fruits[fruitId];
548 if ids ~= nil and FruitUtil.fruitTypeToWindrowFillType[fruitId] ~= nil then
549 fruitType = fruitId;
550 liters = -TipUtil.tipToGroundAroundLine(self, -math.huge, FruitUtil.fruitTypeToWindrowFillType[fruitType], sx,sy,sz, ex,ey,ez, hLength_2, nil, nil, false, nil);
551 if liters > 0 then
552 break;
553 end
554 end
555 end
556 end
557 end
558 end
559 if liters > 0 then
560 fruitTypeFix = true;
561
562 -- now that we removed the windrow, maybe there is some hidden drygrass to grow (set it to growth state 1 if there is some)
563 if fruitType == FruitUtil.FRUITTYPE_DRYGRASS then
564 Utils.switchFruitTypeArea(FruitUtil.FRUITTYPE_GRASS, FruitUtil.FRUITTYPE_DRYGRASS, x0, z0, x1, z1, x2, z2, 2);
565 end
566
567 end
568
569 -- handle grass as drygrass and vice versa
570 if fruitType == FruitUtil.FRUITTYPE_GRASS then
571 liters = liters - TipUtil.tipToGroundAroundLine(self, -math.huge, FruitUtil.fruitTypeToWindrowFillType[FruitUtil.FRUITTYPE_DRYGRASS], sx,sy,sz, ex,ey,ez, hLength_2, nil, nil, false, nil);
572 elseif fruitType == FruitUtil.FRUITTYPE_DRYGRASS then
573 liters = liters - TipUtil.tipToGroundAroundLine(self, -math.huge, FruitUtil.fruitTypeToWindrowFillType[FruitUtil.FRUITTYPE_GRASS], sx,sy,sz, ex,ey,ez, hLength_2, nil, nil, false, nil);
574 end
575
576 -- add the accumulated value
577 if not fruitTypeFix or accumulatedFruitType == fruitType then
578 fruitType = accumulatedFruitType;
579 liters = liters + accumulatedWorkAreaValues[i];
580 accumulatedWorkAreaValues[i] = 0;
581 end
582
583 if liters > 0 then
584
585 local hx = dx2 - dx0;
586 local hz = dz2 - dz0;
587 local hLength = Utils.vector2Length(hx, hz);
588 local hLength_2 = 0.5 * hLength;
589
590 local wx = dx1 - dx0;
591 local wz = dz1 - dz0;
592 local wLength = Utils.vector2Length(wx, wz);
593
594 local sx = dx0 + (hx * 0.5) + ((wx/wLength)*hLength_2);
595 local sz = dz0 + (hz * 0.5) + ((wz/wLength)*hLength_2);
596
597 local ex = dx1 + (hx * 0.5) - ((wx/wLength)*hLength_2);
598 local ez = dz1 + (hz * 0.5) - ((wz/wLength)*hLength_2);
599
600 local sy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, sx,0,sz);
601 local ey = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, ex,0,ez);
602
603 local dropped, lineOffset = TipUtil.tipToGroundAroundLine(self, liters, FruitUtil.fruitTypeToWindrowFillType[fruitType], sx,sy,sz, ex,ey,ez, hLength_2, nil, self.windrowerLineOffset, false, nil, false);
604 self.windrowerLineOffset = lineOffset;
605
606 local remain = liters - dropped;
607
608 if dropped > 0 then
609 table.insert(workAreasRet, {x0,z0, x1,z1, x2,z2, dx0,dz0, dx1,dz1, dx2,dz2, liters-remain, workAreas[i][14] });
610 end
611
612 accumulatedWorkAreaValues[i] = remain;
613
614 end
615 end
616
617 return workAreasRet, fruitType;
618end