LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

Sprayer

Description
Specialization for vehicles with spraying functionality (fertilizer, lime, herbicide)
Functions

doCheckSpeedLimit

Description
Definition
doCheckSpeedLimit()
Code
666function Sprayer:doCheckSpeedLimit(superFunc)
667 return superFunc(self) or (self:getIsTurnedOn() and self.spec_sprayer.useSpeedLimit)
668end

getActiveSprayType

Description
Definition
getActiveSprayType()
Code
495function Sprayer:getActiveSprayType()
496 local spec = self.spec_sprayer
497 for _, sprayType in ipairs(spec.sprayTypes) do
498 if self:getIsSprayTypeActive(sprayType) then
499 return sprayType
500 end
501 end
502
503 return nil
504end

getAIImplementCollisionTriggers

Description
Definition
getAIImplementCollisionTriggers()
Code
561function Sprayer:getAIImplementCollisionTriggers(superFunc, collisionTriggers)
562 local sprayType = self:getActiveSprayType()
563 if sprayType ~= nil then
564 if sprayType.ai.collisionTrigger ~= nil then
565 collisionTriggers[self] = sprayType.ai.collisionTrigger
566 end
567 end
568
569 return superFunc(self, collisionTriggers)
570end

getAIMarkers

Description
Definition
getAIMarkers()
Code
529function Sprayer:getAIMarkers(superFunc)
530 local spec = self.spec_aiImplement
531
532 local sprayType = self:getActiveSprayType()
533 if sprayType ~= nil and not spec.useAttributesOfAttachedImplement then
534 if sprayType.ai.rightMarker ~= nil then
535 if spec.aiMarkersInverted then
536 return sprayType.ai.rightMarker, sprayType.ai.leftMarker, sprayType.ai.backMarker, true
537 else
538 return sprayType.ai.leftMarker, sprayType.ai.rightMarker, sprayType.ai.backMarker, false
539 end
540 end
541 end
542
543 return superFunc(self)
544end

getAIRequiresTurnOffOnHeadland

Description
Definition
getAIRequiresTurnOffOnHeadland()
Code
690function Sprayer:getAIRequiresTurnOffOnHeadland(superFunc)
691 return true
692end

getAISizeMarkers

Description
Definition
getAISizeMarkers()
Code
548function Sprayer:getAISizeMarkers(superFunc)
549 local sprayType = self:getActiveSprayType()
550 if sprayType ~= nil then
551 if sprayType.ai.sizeLeftMarker ~= nil then
552 return sprayType.ai.sizeLeftMarker, sprayType.ai.sizeRightMarker, sprayType.ai.sizeBackMarker
553 end
554 end
555
556 return superFunc(self)
557end

getAreEffectsVisible

Description
Definition
getAreEffectsVisible()
Code
361function Sprayer:getAreEffectsVisible()
362 return true
363end

getCanBeTurnedOn

Description
Definition
getCanBeTurnedOn()
Code
606function Sprayer:getCanBeTurnedOn(superFunc)
607 local spec = self.spec_sprayer
608 if not spec.allowsSpraying then
609 return false
610 end
611
612 if self:getFillUnitFillLevel(self:getSprayerFillUnitIndex()) <= 0 and spec.needsToBeFilledToTurnOn then
613 if not self:getIsAIActive() then
614 local sprayVehicle = nil
615 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
616 for _, src in ipairs(spec.fillTypeSources[supportedSprayType]) do
617 local vehicle = src.vehicle
618 if vehicle:getFillUnitFillType(src.fillUnitIndex) == supportedSprayType and vehicle:getFillUnitFillLevel(src.fillUnitIndex) > 0 then
619 sprayVehicle = vehicle
620 break
621 end
622 end
623 end
624
625 if sprayVehicle == nil then
626 return false
627 end
628 end
629 end
630
631 return superFunc(self)
632end

getCanToggleTurnedOn

Description
Definition
getCanToggleTurnedOn()
Code
591function Sprayer:getCanToggleTurnedOn(superFunc)
592 if self.isClient then
593 local spec = self.spec_sprayer
594 if spec.needsToBeFilledToTurnOn then
595 if not self:getCanBeTurnedOn() and self:getFillUnitCapacity(self:getSprayerFillUnitIndex()) <= 0 then
596 return false
597 end
598 end
599 end
600
601 return superFunc(self)
602end

getDefaultSpeedLimit

Description
Definition
getDefaultSpeedLimit()
Code
1001function Sprayer.getDefaultSpeedLimit()
1002 return 15
1003end

getDirtMultiplier

Description
Definition
getDirtMultiplier()
Code
696function Sprayer:getDirtMultiplier(superFunc)
697 local spec = self.spec_sprayer
698
699 if spec.isWorking then
700 return superFunc(self) + self:getWorkDirtMultiplier() * self:getLastSpeed() / self.speedLimit
701 end
702
703 return superFunc(self)
704end

getDrawFirstFillText

Description
Definition
getDrawFirstFillText()
Code
574function Sprayer:getDrawFirstFillText(superFunc)
575 if self.isClient then
576 local spec = self.spec_sprayer
577 if spec.needsToBeFilledToTurnOn then
578 if self:getIsActiveForInput() and self:getIsSelected() and not self.isAlwaysTurnedOn then
579 if not self:getCanBeTurnedOn() and self:getFillUnitFillLevel(self:getSprayerFillUnitIndex()) <= 0 and self:getFillUnitCapacity(self:getSprayerFillUnitIndex()) > 0 then
580 return true
581 end
582 end
583 end
584 end
585
586 return superFunc(self)
587end

getExternalFill

Description
Definition
getExternalFill()
Code
259function Sprayer:getExternalFill(fillType, dt)
260 local found = false
261 local isUnknownFillType = fillType == FillType.UNKNOWN
262 local allowLiquidManure = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.LIQUIDMANURE)
263 local allowDigestate = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.DIGESTATE)
264 local allowManure = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.MANURE)
265 local allowLiquidFertilizer = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.LIQUIDFERTILIZER)
266 local allowFertilizer = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.FERTILIZER)
267 local allowsLiquidManureDigistate = allowLiquidManure or allowDigestate
268 local usage = 0
269
270 local farmId = self:getActiveFarm()
271 local stats = g_currentMission:farmStats(self:getLastTouchedFarmlandFarmId())
272
273 if fillType == FillType.LIQUIDMANURE or fillType == FillType.DIGESTATE or (isUnknownFillType and allowsLiquidManureDigistate) then
274 if g_currentMission.missionInfo.helperSlurrySource == 2 then -- buy manure
275 found = true
276 if g_currentMission.economyManager:getCostPerLiter(FillType.LIQUIDMANURE, false) then
277 fillType = FillType.LIQUIDMANURE
278 else
279 fillType = FillType.DIGESTATE
280 end
281
282 usage = self:getSprayerUsage(fillType, dt)
283 if self.isServer then
284 local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType, false) * 1.5 -- increase price if AI is active to reward the player's manual work
285 stats:updateStats("expenses", price)
286 g_currentMission:addMoney(-price, farmId, MoneyType.PURCHASE_FERTILIZER)
287 end
288 elseif g_currentMission.missionInfo.helperSlurrySource > 2 then
289 local info = g_currentMission.liquidManureTriggers[g_currentMission.missionInfo.helperSlurrySource-2]
290 if info ~= nil then -- Can be nil if pen was removed
291 local fillLevel = info.silo:getFillLevel(FillType.LIQUIDMANURE)
292 if fillLevel > 0 then
293 found = true
294 usage = self:getSprayerUsage(FillType.LIQUIDMANURE, dt)
295 if self.isServer then
296 info.silo:setFillLevel(FillType.LIQUIDMANURE, fillLevel-usage)
297 end
298 end
299 end
300 end --
301 elseif fillType == FillType.MANURE or (fillType == FillType.UNKNOWN and allowManure) then
302 if fillType == FillType.UNKNOWN and allowManure then
303 fillType = FillType.MANURE
304 end
305
306 if g_currentMission.missionInfo.helperManureSource == 2 then -- buy manure
307 found = true
308 fillType = FillType.MANURE
309
310 usage = self:getSprayerUsage(fillType, dt)
311 if self.isServer then
312 local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType, false) * 1.5 -- increase price if AI is active to reward the player's manual work
313 stats:updateStats("expenses", price)
314 g_currentMission:addMoney(-price, farmId, MoneyType.PURCHASE_FERTILIZER)
315 end
316 elseif g_currentMission.missionInfo.helperManureSource > 2 then
317 local info = g_currentMission.manureHeaps[g_currentMission.missionInfo.helperManureSource-2]
318 if info ~= nil then -- Can be nil if pen was removed
319 usage = self:getSprayerUsage(FillType.MANURE, dt)
320 if self.isServer then
321 if info.manureHeap:removeManure(usage) > 0 then
322 found = true
323 fillType = FillType.MANURE
324 end
325 end
326 end
327 end --
328 elseif fillType == FillType.FERTILIZER or
329 fillType == FillType.LIQUIDFERTILIZER or
330 fillType == FillType.HERBICIDE or
331 fillType == FillType.LIME or
332 (fillType == FillType.UNKNOWN and (allowLiquidFertilizer or allowFertilizer)) then
333 if g_currentMission.missionInfo.helperBuyFertilizer then
334 found = true
335 if fillType == FillType.UNKNOWN then
336 if self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.LIQUIDFERTILIZER) then
337 fillType = FillType.LIQUIDFERTILIZER
338 else
339 fillType = FillType.FERTILIZER
340 end
341 end
342
343 usage = self:getSprayerUsage(fillType, dt)
344 if self.isServer then
345 local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType, false) * 1.5 -- increase price if AI is active to reward the player's manual work
346 stats:updateStats("expenses", price)
347 g_currentMission:addMoney(-price, farmId, MoneyType.PURCHASE_FERTILIZER)
348 end
349 end
350 end
351
352 if found then
353 return fillType, usage
354 end
355
356 return FillType.UNKNOWN, 0
357end

getFillVolumeUVScrollSpeed

Description
Definition
getFillVolumeUVScrollSpeed()
Code
672function Sprayer:getFillVolumeUVScrollSpeed(superFunc, fillVolumeIndex)
673 local spec = self.spec_sprayer
674
675 local sprayerFillVolumeIndex = spec.fillVolumeIndex
676 local sprayType = self:getActiveSprayType()
677 if sprayType ~= nil then
678 sprayerFillVolumeIndex = sprayType.fillVolumeIndex
679 end
680
681 if fillVolumeIndex == sprayerFillVolumeIndex then
682 return spec.dischargeUVScrollSpeed[1], spec.dischargeUVScrollSpeed[2], spec.dischargeUVScrollSpeed[3]
683 end
684
685 return superFunc(self, fillVolumeIndex)
686end

getIsSprayTypeActive

Description
Definition
getIsSprayTypeActive()
Code
508function Sprayer:getIsSprayTypeActive(sprayType)
509 if sprayType.fillTypes ~= nil then
510 local retValue = false
511
512 local currentFillType = self:getFillUnitFillType(sprayType.fillUnitIndex or self.spec_sprayer.fillUnitIndex)
513 for _, fillType in ipairs(sprayType.fillTypes) do
514 if currentFillType == g_fillTypeManager:getFillTypeIndexByName(fillType) then
515 retValue = true
516 end
517 end
518
519 if not retValue then
520 return false
521 end
522 end
523
524 return true
525end

getIsWorkAreaActive

Description
Definition
getIsWorkAreaActive()
Code
651function Sprayer:getIsWorkAreaActive(superFunc, workArea)
652 if workArea.sprayType ~= nil then
653 local sprayType = self:getActiveSprayType()
654 if sprayType ~= nil then
655 if sprayType.index ~= workArea.sprayType then
656 return false
657 end
658 end
659 end
660
661 return superFunc(self, workArea)
662end

getSprayerFillUnitIndex

Description
Definition
getSprayerFillUnitIndex()
Code
436function Sprayer:getSprayerFillUnitIndex()
437 local sprayType = self:getActiveSprayType()
438 if sprayType ~= nil then
439 return sprayType.fillUnitIndex
440 end
441
442 return self.spec_sprayer.fillUnitIndex
443end

getSprayerUsage

Description
Definition
getSprayerUsage()
Code
367function Sprayer:getSprayerUsage(fillType, dt)
368 if fillType == FillType.UNKNOWN then
369 return 0
370 end
371
372 local spec = self.spec_sprayer
373
374 local scale = Utils.getNoNil(spec.usageScale.fillTypeScales[fillType], spec.usageScale.default)
375 local litersPerSecond = 1
376
377 local sprayType = g_sprayTypeManager:getSprayTypeByFillTypeIndex(fillType)
378 if sprayType ~= nil then
379 litersPerSecond = sprayType.litersPerSecond
380 end
381
382 local activeSprayType = self:getActiveSprayType()
383 local workWidth = spec.usageScale.workingWidth
384 if activeSprayType ~= nil then
385 workWidth = activeSprayType.usageScale.workingWidth or workWidth
386 end
387
388 return scale * litersPerSecond * self.speedLimit * workWidth * dt * 0.001
389end

getUseSprayerAIRequirements

Description
Definition
getUseSprayerAIRequirements()
Code
393function Sprayer:getUseSprayerAIRequirements()
394 return true
395end

getWearMultiplier

Description
Definition
getWearMultiplier()
Code
708function Sprayer:getWearMultiplier(superFunc)
709 local spec = self.spec_sprayer
710
711 if spec.isWorking then
712 return superFunc(self) + self:getWorkWearMultiplier() * self:getLastSpeed() / self.speedLimit
713 end
714
715 return superFunc(self)
716end

initSpecialization

Description
Definition
initSpecialization()
Code
15function Sprayer.initSpecialization()
16 g_workAreaTypeManager:addWorkAreaType("sprayer", false)
17end

loadSprayTypeFromXML

Description
Definition
loadSprayTypeFromXML()
Code
447function Sprayer:loadSprayTypeFromXML(xmlFile, key, sprayType)
448 sprayType.fillUnitIndex = Utils.getNoNil(getXMLInt(xmlFile, key.. "#fillUnitIndex"), 1)
449 sprayType.unloadInfoIndex = Utils.getNoNil(getXMLInt(xmlFile, key.. "#unloadInfoIndex"), 1)
450 sprayType.fillVolumeIndex = getXMLInt(xmlFile, key.. "#fillVolumeIndex")
451
452 sprayType.samples = {}
453 sprayType.samples.work = g_soundManager:loadSampleFromXML(xmlFile, key.. ".sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
454
455 sprayType.effects = g_effectManager:loadEffect(xmlFile, key.. ".effects", self.components, self, self.i3dMappings)
456
457 sprayType.animationNodes = g_animationManager:loadAnimations(xmlFile, key.. ".animationNodes", self.components, self, self.i3dMappings)
458
459 sprayType.turnedAnimation = getXMLString(self.xmlFile, key .. ".turnedAnimation#name") or ""
460
461 sprayType.ai = {}
462 sprayType.ai.leftMarker = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. ".ai.areaMarkers#leftNode"), self.i3dMappings)
463 sprayType.ai.rightMarker = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. ".ai.areaMarkers#rightNode"), self.i3dMappings)
464 sprayType.ai.backMarker = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. ".ai.areaMarkers#backNode"), self.i3dMappings)
465
466 sprayType.ai.sizeLeftMarker = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. ".ai.sizeMarkers#leftNode"), self.i3dMappings)
467 sprayType.ai.sizeRightMarker = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. ".ai.sizeMarkers#rightNode"), self.i3dMappings)
468 sprayType.ai.sizeBackMarker = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. ".ai.sizeMarkers#backNode"), self.i3dMappings)
469
470 sprayType.ai.collisionTrigger = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key .. ".ai.collisionTrigger#node"), self.i3dMappings)
471 if sprayType.ai.collisionTrigger ~= nil then
472 local rigidBodyType = getRigidBodyType(sprayType.ai.collisionTrigger)
473 if rigidBodyType ~= "Kinematic" then
474 g_logManager:xmlWarning(self.configFileName, "'aiCollisionTrigger' is not a kinematic body type")
475 end
476 end
477
478 local fillTypesStr = getXMLString(xmlFile, key.. "#fillTypes")
479 if fillTypesStr ~= nil then
480 sprayType.fillTypes = StringUtil.splitString(" ", fillTypesStr)
481 end
482
483 sprayType.objectChanges = {}
484 ObjectChangeUtil.loadObjectChangeFromXML(self.xmlFile, key, sprayType.objectChanges, self.components, self)
485 ObjectChangeUtil.setObjectChanges(sprayType.objectChanges, false)
486
487 sprayType.usageScale = {}
488 sprayType.usageScale.workingWidth = Utils.getNoNil(getXMLFloat(self.xmlFile, key..".usageScales#workingWidth"), 12)
489
490 return true
491end

loadWorkAreaFromXML

Description
Definition
loadWorkAreaFromXML()
Code
637function Sprayer:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key)
638 local retValue = superFunc(self, workArea, xmlFile, key)
639
640 if workArea.type == WorkAreaType.DEFAULT then
641 workArea.type = WorkAreaType.SPRAYER
642 end
643
644 workArea.sprayType = getXMLInt(xmlFile, key.. "#sprayType")
645
646 return retValue
647end

onAIImplementEnd

Description
Definition
onAIImplementEnd()
Code
984function Sprayer:onAIImplementEnd()
985 -- turn off all fill type sources on ai turn off
986 local spec = self.spec_sprayer
987 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
988 for _, src in ipairs(spec.fillTypeSources[supportedSprayType]) do
989 local vehicle = src.vehicle
990 if vehicle.getIsTurnedOn ~= nil then
991 if vehicle:getIsTurnedOn() then
992 vehicle:setIsTurnedOn(false, true)
993 end
994 end
995 end
996 end
997end

onDelete

Description
Definition
onDelete()
Code
188function Sprayer:onDelete()
189 if self.isClient then
190 local spec = self.spec_sprayer
191
192 g_effectManager:deleteEffects(spec.effects)
193
194 for _,sample in pairs(spec.samples) do
195 g_soundManager:deleteSample(sample)
196 end
197
198 g_animationManager:deleteAnimations(spec.animationNodes)
199
200 for _, sprayType in ipairs(spec.sprayTypes) do
201 g_effectManager:deleteEffects(sprayType.effects)
202 g_soundManager:deleteSamples(sprayType.samples)
203 g_animationManager:deleteAnimations(sprayType.animationNodes)
204 end
205 end
206end

onEndWorkAreaProcessing

Description
Definition
onEndWorkAreaProcessing()
Code
879function Sprayer:onEndWorkAreaProcessing(dt, hasProcessed)
880 local spec = self.spec_sprayer
881
882 if self.isServer then
883 if spec.workAreaParameters.isActive then
884 local sprayVehicle = spec.workAreaParameters.sprayVehicle
885 local usage = spec.workAreaParameters.usage
886
887 if sprayVehicle ~= nil then
888 local sprayVehicleFillUnitIndex = spec.workAreaParameters.sprayVehicleFillUnitIndex
889 local sprayFillType = spec.workAreaParameters.sprayFillType
890
891 local unloadInfoIndex = spec.unloadInfoIndex
892 local sprayType = self:getActiveSprayType()
893 if sprayType ~= nil then
894 unloadInfoIndex = sprayType.unloadInfoIndex
895 end
896
897 local unloadInfo = self:getFillVolumeUnloadInfo(unloadInfoIndex)
898 sprayVehicle:addFillUnitFillLevel(self:getOwnerFarmId(), sprayVehicleFillUnitIndex, -usage, sprayFillType, ToolType.UNDEFINED, unloadInfo)
899 end
900
901 local ha = MathUtil.areaToHa(spec.workAreaParameters.lastStatsArea, g_currentMission:getFruitPixelsToSqm())
902 local stats = g_currentMission:farmStats(self:getLastTouchedFarmlandFarmId())
903 stats:updateStats("workedHectares", ha)
904 stats:updateStats("fertilizedHectares", ha)
905 stats:updateStats("fertilizedTime", dt/(1000*60))
906 stats:updateStats("sprayUsage", usage)
907 end
908 end
909end

onFillUnitFillLevelChanged

Description
Definition
onFillUnitFillLevelChanged()
Code
947function Sprayer:onFillUnitFillLevelChanged(fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta)
948 local fillLevel = self:getFillUnitFillLevel(fillUnitIndex)
949 if fillLevel == 0 and self:getIsTurnedOn() and not self:getIsAIActive() then
950 local spec = self.spec_sprayer
951
952 -- only deactivate sprayer if no fill type source for the same fill type is available
953 local hasValidSource = false
954 if spec.fillTypeSources[fillType] ~= nil then
955 for _, src in ipairs(spec.fillTypeSources[fillType]) do
956 local vehicle = src.vehicle
957 if vehicle:getIsFillUnitActive(src.fillUnitIndex) then
958 local vehicleFillType = vehicle:getFillUnitFillType(src.fillUnitIndex)
959 local vehicleFillLevel = vehicle:getFillUnitFillLevel(src.fillUnitIndex)
960 if vehicleFillLevel > 0 and vehicleFillType == fillType then
961 hasValidSource = true
962 end
963 end
964 end
965 end
966
967 if not hasValidSource then
968 self:setIsTurnedOn(false)
969 end
970 end
971end

onLoad

Description
Definition
onLoad()
Code
86function Sprayer:onLoad(savegame)
87 local spec = self.spec_sprayer
88
89 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.sprayParticles.emitterShape", "vehicle.sprayer.effects.effectNode#effectClass='ParticleEffect'") --FS17 to FS19
90
91 spec.allowsSpraying = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#allowsSpraying"), true)
92 spec.needsTankActivation = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#needsTankActivation"), false)
93 spec.activateTankOnLowering = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#activateTankOnLowering"), false)
94 spec.activateOnLowering = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#activateOnLowering"), false)
95
96 spec.usageScale = {}
97 spec.usageScale.default = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.sprayer.usageScales#scale"), 1)
98 spec.usageScale.workingWidth = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.sprayer.usageScales#workingWidth"), 12)
99 spec.usageScale.fillTypeScales = {}
100 local i=0
101 while true do
102 local key = string.format("vehicle.sprayer.usageScales.sprayUsageScale(%d)", i)
103 if not hasXMLProperty(self.xmlFile, key) then
104 break
105 end
106 local fillTypeStr = getXMLString(self.xmlFile, key.. "#fillType")
107 local scale = getXMLFloat(self.xmlFile, key.. "#scale")
108 if fillTypeStr ~= nil and scale ~= nil then
109 local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeStr)
110 if fillTypeIndex ~= nil then
111 spec.usageScale.fillTypeScales[fillTypeIndex] = scale
112 else
113 print("Warning: Invalid spray usage scale fill type '"..fillTypeStr.."' in '" .. self.configFileName.. "'")
114 end
115 end
116 i = i+1
117 end
118
119 spec.sprayTypes = {}
120 i = 0
121 while true do
122 local key = string.format("vehicle.sprayer.sprayTypes.sprayType(%d)", i)
123 if not hasXMLProperty(self.xmlFile, key) then
124 break
125 end
126
127 local sprayType = {}
128 if self:loadSprayTypeFromXML(self.xmlFile, key, sprayType) then
129 table.insert(spec.sprayTypes, sprayType)
130 sprayType.index = #spec.sprayTypes
131 end
132
133 i = i + 1
134 end
135
136 spec.lastActiveSprayType = nil
137
138 if self.isClient then
139 spec.effects = g_effectManager:loadEffect(self.xmlFile, "vehicle.sprayer.effects", self.components, self, self.i3dMappings)
140
141 spec.animationName = Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.sprayer.animation#name"), "")
142
143 spec.samples = {}
144 spec.samples.work = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.sprayer.sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
145
146 spec.sampleFillEnabled = false
147 spec.sampleFillStopTime = -1
148 spec.lastFillLevel = -1
149
150 spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.sprayer.animationNodes", self.components, self, self.i3dMappings)
151 end
152
153 if self.sowingMachineGroundContactFlag == nil and self.cultivatorGroundContactFlag == nil then
154 if self.addAITerrainDetailRequiredRange ~= nil then
155 self:addAITerrainDetailRequiredRange(g_currentMission.plowValue, g_currentMission.plowValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels)
156 self:addAITerrainDetailRequiredRange(g_currentMission.cultivatorValue, g_currentMission.cultivatorValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels)
157 self:addAITerrainDetailRequiredRange(g_currentMission.sowingValue, g_currentMission.sowingValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels)
158 self:addAITerrainDetailRequiredRange(g_currentMission.sowingWidthValue, g_currentMission.sowingWidthValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels)
159 self:addAITerrainDetailRequiredRange(g_currentMission.grassValue, g_currentMission.grassValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels)
160 end
161
162 --if self.addAITerrainDetailProhibitedRange ~= nil then
163 -- self:addAITerrainDetailProhibitedRange(1, 2, g_currentMission.sprayFirstChannel, g_currentMission.sprayNumChannels)
164 -- self:addAITerrainDetailProhibitedRange(g_currentMission.sprayLevelMaxValue, g_currentMission.sprayLevelMaxValue, g_currentMission.sprayLevelFirstChannel, g_currentMission.sprayLevelNumChannels)
165 --end
166 end
167
168 spec.supportedSprayTypes = {}
169
170 spec.fillUnitIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.sprayer#fillUnitIndex"), 1)
171 spec.unloadInfoIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.sprayer#unloadInfoIndex"), 1)
172 spec.fillVolumeIndex = getXMLInt(self.xmlFile, "vehicle.sprayer#fillVolumeIndex")
173 spec.dischargeUVScrollSpeed = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.sprayer#fillVolumeDischargeScrollSpeed"), "0 0 0")) }
174
175 spec.needsToBeFilledToTurnOn = true
176 spec.useSpeedLimit = true
177 spec.isWorking = false
178
179 spec.workAreaParameters = {}
180 spec.workAreaParameters.sprayVehicle = nil
181 spec.workAreaParameters.sprayVehicleFillUnitIndex = nil
182 spec.workAreaParameters.lastChangedArea = 0
183 spec.workAreaParameters.lastTotalArea = 0
184end

onPreDetach

Description
Definition
onPreDetach()
Code
786function Sprayer:onPreDetach(attacherVehicle, jointDescIndex)
787 if attacherVehicle.setIsTurnedOn ~= nil and attacherVehicle:getIsTurnedOn() then
788 attacherVehicle:setIsTurnedOn(false)
789 end
790end

onSetLowered

Description
Definition
onSetLowered()
Code
937function Sprayer:onSetLowered(isLowered)
938 local spec = self.spec_sprayer
939
940 if spec.activateOnLowering then
941 self:setIsTurnedOn(isLowered, true)
942 end
943end

onSprayTypeChange

Description
Definition
onSprayTypeChange()
Code
975function Sprayer:onSprayTypeChange(activeSprayType)
976 local spec = self.spec_sprayer
977 for _, sprayType in ipairs(spec.sprayTypes) do
978 ObjectChangeUtil.setObjectChanges(sprayType.objectChanges, sprayType == activeSprayType)
979 end
980end

onStartWorkAreaProcessing

Description
Definition
onStartWorkAreaProcessing()
Code
794function Sprayer:onStartWorkAreaProcessing(dt)
795 local spec = self.spec_sprayer
796
797 local sprayVehicle = nil
798 local sprayVehicleFillUnitIndex = nil
799 local fillType = self:getFillUnitFillType(self:getSprayerFillUnitIndex())
800 local usage = self:getSprayerUsage(fillType, dt)
801 local sprayFillLevel = self:getFillUnitFillLevel(self:getSprayerFillUnitIndex())
802
803 if sprayFillLevel > 0 then
804 sprayVehicle = self
805 sprayVehicleFillUnitIndex = self:getSprayerFillUnitIndex()
806 else
807 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
808 for _, src in ipairs(spec.fillTypeSources[supportedSprayType]) do
809 local vehicle = src.vehicle
810 if vehicle:getIsFillUnitActive(src.fillUnitIndex) then
811 local vehicleFillType = vehicle:getFillUnitFillType(src.fillUnitIndex)
812 local vehicleFillLevel = vehicle:getFillUnitFillLevel(src.fillUnitIndex)
813 if vehicleFillLevel > 0 and vehicleFillType == supportedSprayType then
814 sprayVehicle = vehicle
815 sprayVehicleFillUnitIndex = src.fillUnitIndex
816 fillType = sprayVehicle:getFillUnitFillType(sprayVehicleFillUnitIndex)
817 usage = self:getSprayerUsage(fillType, dt)
818 sprayFillLevel = vehicleFillLevel
819 break
820 end
821 else
822 -- if the ai is active we try to activate the source to activate the fill unit
823 if self:getIsAIActive() then
824 if vehicle.setIsTurnedOn ~= nil then
825 if not vehicle:getIsTurnedOn() then
826 vehicle:setIsTurnedOn(true)
827 end
828 end
829 end
830 end
831 end
832 end
833 end
834
835 if self:getIsAIActive() then
836 local isSlurryTanker = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.LIQUIDMANURE) or self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.DIGESTATE)
837 local isManureSpreader = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.MANURE)
838 local isFertilizerSprayer = not isSlurryTanker and not isManureSpreader
839
840 local isBuying = (isSlurryTanker and g_currentMission.missionInfo.helperSlurrySource > 1)
841 or (isManureSpreader and g_currentMission.missionInfo.helperManureSource > 1)
842 or (isFertilizerSprayer and g_currentMission.missionInfo.helperBuyFertilizer)
843
844 if isBuying then
845 -- only consume while ai is on field, not while turning, so we check for the tools turned on state
846 if self:getIsTurnedOn() then
847 fillType, usage = self:getExternalFill(fillType, dt)
848 sprayFillLevel = usage
849
850 -- do not consume the fill unit fill level if we buy fertilizer
851 sprayVehicle = nil
852 sprayVehicleFillUnitIndex = nil
853 end
854 end
855 end
856
857 if self.isServer then
858 if fillType ~= FillType.UNKNOWN and fillType ~= spec.workAreaParameters.sprayFillType then
859 self:setSprayerAITerrainDetailProhibitedRange(fillType)
860 end
861 end
862
863 spec.workAreaParameters.sprayType = g_sprayTypeManager:getSprayTypeIndexByFillTypeIndex(fillType)
864 spec.workAreaParameters.sprayFillType = fillType
865 spec.workAreaParameters.sprayFillLevel = sprayFillLevel
866 spec.workAreaParameters.usage = usage
867 spec.workAreaParameters.sprayVehicle = sprayVehicle
868 spec.workAreaParameters.sprayVehicleFillUnitIndex = sprayVehicleFillUnitIndex
869 spec.workAreaParameters.lastChangedArea = 0
870 spec.workAreaParameters.lastTotalArea = 0
871 spec.workAreaParameters.lastStatsArea = 0
872 spec.workAreaParameters.isActive = false
873
874 spec.isWorking = false
875end

onStateChange

Description
Definition
onStateChange()
Code
913function Sprayer:onStateChange(state, data)
914 if state == Vehicle.STATE_CHANGE_ATTACH or state == Vehicle.STATE_CHANGE_DETACH or Vehicle.STATE_CHANGE_FILLTYPE_CHANGE then
915 local spec = self.spec_sprayer
916
917 spec.fillTypeSources = {}
918 local supportedFillTypes = self:getFillUnitSupportedFillTypes(self:getSprayerFillUnitIndex())
919 spec.supportedSprayTypes = {}
920
921 if supportedFillTypes ~= nil then
922 for fillType, state in pairs(supportedFillTypes) do
923 if state then
924 spec.fillTypeSources[fillType] = {}
925 table.insert(spec.supportedSprayTypes, fillType)
926 end
927 end
928 end
929
930 local root = self:getRootVehicle()
931 FillUnit.addFillTypeSources(spec.fillTypeSources, root, self, spec.supportedSprayTypes)
932 end
933end

onTurnedOff

Description
Definition
onTurnedOff()
Code
760function Sprayer:onTurnedOff()
761 local spec = self.spec_sprayer
762 if self.isClient then
763 g_effectManager:stopEffects(spec.effects)
764 g_animationManager:stopAnimations(spec.animationNodes)
765
766 if spec.animationName ~= "" and self.stopAnimation ~= nil then
767 self:stopAnimation(spec.animationName, true)
768 end
769
770 g_soundManager:stopSample(spec.samples.work)
771
772 -- deactivate effects on all spray types (the spray type has may changed during activation)
773 for _, sprayType in ipairs(spec.sprayTypes) do
774 g_effectManager:stopEffects(sprayType.effects)
775 g_animationManager:stopAnimations(sprayType.animationNodes)
776
777 g_soundManager:stopSample(sprayType.samples.work)
778
779 self:playAnimation(sprayType.turnedAnimation, -1, self:getAnimationTime(sprayType.turnedAnimation), true)
780 end
781 end
782end

onTurnedOn

Description
Definition
onTurnedOn()
Code
720function Sprayer:onTurnedOn()
721 local spec = self.spec_sprayer
722 if self.isClient then
723 local sprayType = self:getActiveSprayType()
724
725 if self:getAreEffectsVisible() then
726 local fillType = self:getFillUnitLastValidFillType(self:getSprayerFillUnitIndex())
727 if fillType == FillType.UNKNOWN then
728 fillType = self:getFillUnitFirstSupportedFillType(self:getSprayerFillUnitIndex())
729 end
730
731 g_effectManager:setFillType(spec.effects, fillType)
732 g_effectManager:startEffects(spec.effects)
733
734 if sprayType ~= nil then
735 g_effectManager:setFillType(sprayType.effects, fillType)
736 g_effectManager:startEffects(sprayType.effects)
737
738 g_animationManager:startAnimations(sprayType.animationNodes)
739 end
740
741 g_animationManager:startAnimations(spec.animationNodes)
742 end
743
744 if spec.animationName ~= "" and self.playAnimation ~= nil then
745 self:playAnimation(spec.animationName, 1, self:getAnimationTime(spec.animationName), true)
746 end
747
748 g_soundManager:playSample(spec.samples.work)
749
750 if sprayType ~= nil then
751 g_soundManager:playSample(sprayType.samples.work)
752
753 self:playAnimation(sprayType.turnedAnimation, 1, self:getAnimationTime(sprayType.turnedAnimation), true)
754 end
755 end
756end

onUpdateTick

Description
Definition
onUpdateTick()
Code
210function Sprayer:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
211 local activeSprayType = self:getActiveSprayType()
212 if activeSprayType ~= nil then
213 local spec = self.spec_sprayer
214 if activeSprayType ~= spec.lastActiveSprayType then
215 SpecializationUtil.raiseEvent(self, "onSprayTypeChange", activeSprayType)
216 spec.lastActiveSprayType = activeSprayType
217 end
218 end
219end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
21function Sprayer.prerequisitesPresent(specializations)
22 return SpecializationUtil.hasSpecialization(FillUnit, specializations) and
23 SpecializationUtil.hasSpecialization(WorkArea, specializations) and
24 SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations)
25end

processSprayerArea

Description
Definition
processSprayerArea()
Code
223function Sprayer:processSprayerArea(workArea, dt)
224 local spec = self.spec_sprayer
225
226 if self:getIsAIActive() and self.isServer then
227 if spec.workAreaParameters.sprayFillType == nil or spec.workAreaParameters.sprayFillType == FillType.UNKNOWN then
228 local rootVehicle = self:getRootVehicle()
229 rootVehicle:stopAIVehicle(AIVehicle.STOP_REASON_OUT_OF_FILL)
230
231 return 0, 0
232 end
233 end
234
235 if spec.workAreaParameters.sprayFillLevel <= 0 then
236 return 0, 0
237 end
238
239 local sx,_,sz = getWorldTranslation(workArea.start)
240 local wx,_,wz = getWorldTranslation(workArea.width)
241 local hx,_,hz = getWorldTranslation(workArea.height)
242
243 local changedArea, totalArea = FSDensityMapUtil.updateSprayArea(sx,sz, wx,wz, hx,hz, spec.workAreaParameters.sprayType)
244
245 spec.workAreaParameters.isActive = true
246 spec.workAreaParameters.lastChangedArea = spec.workAreaParameters.lastChangedArea + changedArea
247 spec.workAreaParameters.lastStatsArea = spec.workAreaParameters.lastStatsArea + changedArea
248 spec.workAreaParameters.lastTotalArea = spec.workAreaParameters.lastTotalArea + totalArea
249
250 if self:getLastSpeed() > 1 then
251 spec.isWorking = true
252 end
253
254 return changedArea, totalArea
255end

registerEventListeners

Description
Definition
registerEventListeners()
Code
68function Sprayer.registerEventListeners(vehicleType)
69 SpecializationUtil.registerEventListener(vehicleType, "onLoad", Sprayer)
70 SpecializationUtil.registerEventListener(vehicleType, "onDelete", Sprayer)
71 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Sprayer)
72 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", Sprayer)
73 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", Sprayer)
74 SpecializationUtil.registerEventListener(vehicleType, "onPreDetach", Sprayer)
75 SpecializationUtil.registerEventListener(vehicleType, "onStartWorkAreaProcessing", Sprayer)
76 SpecializationUtil.registerEventListener(vehicleType, "onEndWorkAreaProcessing", Sprayer)
77 SpecializationUtil.registerEventListener(vehicleType, "onStateChange", Sprayer)
78 SpecializationUtil.registerEventListener(vehicleType, "onSetLowered", Sprayer)
79 SpecializationUtil.registerEventListener(vehicleType, "onFillUnitFillLevelChanged", Sprayer)
80 SpecializationUtil.registerEventListener(vehicleType, "onSprayTypeChange", Sprayer)
81 SpecializationUtil.registerEventListener(vehicleType, "onAIImplementEnd", Sprayer)
82end

registerEvents

Description
Definition
registerEvents()
Code
29function Sprayer.registerEvents(vehicleType)
30 SpecializationUtil.registerEvent(vehicleType, "onSprayTypeChange")
31end

registerFunctions

Description
Definition
registerFunctions()
Code
35function Sprayer.registerFunctions(vehicleType)
36 SpecializationUtil.registerFunction(vehicleType, "processSprayerArea", Sprayer.processSprayerArea)
37 SpecializationUtil.registerFunction(vehicleType, "getExternalFill", Sprayer.getExternalFill)
38 SpecializationUtil.registerFunction(vehicleType, "getAreEffectsVisible", Sprayer.getAreEffectsVisible)
39 SpecializationUtil.registerFunction(vehicleType, "getSprayerUsage", Sprayer.getSprayerUsage)
40 SpecializationUtil.registerFunction(vehicleType, "getUseSprayerAIRequirements", Sprayer.getUseSprayerAIRequirements)
41 SpecializationUtil.registerFunction(vehicleType, "setSprayerAITerrainDetailProhibitedRange", Sprayer.setSprayerAITerrainDetailProhibitedRange)
42 SpecializationUtil.registerFunction(vehicleType, "getSprayerFillUnitIndex", Sprayer.getSprayerFillUnitIndex)
43 SpecializationUtil.registerFunction(vehicleType, "loadSprayTypeFromXML", Sprayer.loadSprayTypeFromXML)
44 SpecializationUtil.registerFunction(vehicleType, "getActiveSprayType", Sprayer.getActiveSprayType)
45 SpecializationUtil.registerFunction(vehicleType, "getIsSprayTypeActive", Sprayer.getIsSprayTypeActive)
46end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
50function Sprayer.registerOverwrittenFunctions(vehicleType)
51 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIMarkers", Sprayer.getAIMarkers)
52 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAISizeMarkers", Sprayer.getAISizeMarkers)
53 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIImplementCollisionTriggers", Sprayer.getAIImplementCollisionTriggers)
54 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDrawFirstFillText", Sprayer.getDrawFirstFillText)
55 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleTurnedOn", Sprayer.getCanToggleTurnedOn)
56 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeTurnedOn", Sprayer.getCanBeTurnedOn)
57 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", Sprayer.loadWorkAreaFromXML)
58 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", Sprayer.getIsWorkAreaActive)
59 SpecializationUtil.registerOverwrittenFunction(vehicleType, "doCheckSpeedLimit", Sprayer.doCheckSpeedLimit)
60 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillVolumeUVScrollSpeed", Sprayer.getFillVolumeUVScrollSpeed)
61 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIRequiresTurnOffOnHeadland", Sprayer.getAIRequiresTurnOffOnHeadland)
62 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", Sprayer.getDirtMultiplier)
63 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", Sprayer.getWearMultiplier)
64end

setSprayerAITerrainDetailProhibitedRange

Description
Definition
setSprayerAITerrainDetailProhibitedRange()
Code
399function Sprayer:setSprayerAITerrainDetailProhibitedRange(fillType)
400 if self:getUseSprayerAIRequirements() then
401 if self.addAITerrainDetailProhibitedRange ~= nil then
402 self:clearAITerrainDetailProhibitedRange()
403 self:clearAIFruitRequirements()
404 self:clearAIFruitProhibitions()
405
406 local sprayTypeDesc = g_sprayTypeManager:getSprayTypeByFillTypeIndex(fillType)
407 if sprayTypeDesc ~= nil then
408 if sprayTypeDesc.isHerbicide then
409 local fruitType = g_fruitTypeManager:getFruitTypeByName("weed")
410 if fruitType ~= nil then
411 self:setAIFruitRequirements(fruitType.index, 1, 2)
412 end
413 else
414 self:addAITerrainDetailProhibitedRange(sprayTypeDesc.groundType, sprayTypeDesc.groundType, g_currentMission.sprayFirstChannel, g_currentMission.sprayNumChannels)
415 self:addAITerrainDetailProhibitedRange(g_currentMission.sprayLevelMaxValue, g_currentMission.sprayLevelMaxValue, g_currentMission.sprayLevelFirstChannel, g_currentMission.sprayLevelNumChannels)
416 end
417
418 -- block ai from working on fully growth fields
419 if sprayTypeDesc.isHerbicide or sprayTypeDesc.isFertilizer then
420 for index, entry in pairs(g_currentMission.fruits) do
421 local fruitType = g_fruitTypeManager:getFruitTypeByIndex(index)
422 if fruitType.name:lower() ~= "grass" then
423 if fruitType.minHarvestingGrowthState ~= nil and fruitType.maxHarvestingGrowthState ~= nil and fruitType.weed == nil then
424 self:addAIFruitProhibitions(fruitType.index, fruitType.minHarvestingGrowthState, fruitType.maxHarvestingGrowthState)
425 end
426 end
427 end
428 end
429 end
430 end
431 end
432end