LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

Sprayer

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

actionEventDoubledAmount

Description
Definition
actionEventDoubledAmount()
Code
395function Sprayer.actionEventDoubledAmount(self, actionName, inputValue, callbackState, isAnalog)
396 self:setSprayerDoubledAmountActive(not self.spec_sprayer.doubledAmountIsActive)
397end

doCheckSpeedLimit

Description
Definition
doCheckSpeedLimit()
Code
1008function Sprayer:doCheckSpeedLimit(superFunc)
1009 return superFunc(self) or (self:getIsTurnedOn() and self.spec_sprayer.useSpeedLimit)
1010end

getActiveSprayType

Description
Definition
getActiveSprayType()
Code
787function Sprayer:getActiveSprayType()
788 local spec = self.spec_sprayer
789 for _, sprayType in ipairs(spec.sprayTypes) do
790 if self:getIsSprayTypeActive(sprayType) then
791 return sprayType
792 end
793 end
794
795 return nil
796end

getAIImplementCollisionTrigger

Description
Definition
getAIImplementCollisionTrigger()
Code
887function Sprayer:getAIImplementCollisionTrigger(superFunc)
888 local sprayType = self:getActiveSprayType()
889 if sprayType ~= nil then
890 if sprayType.ai.collisionTrigger ~= nil then
891 return sprayType.ai.collisionTrigger
892 end
893 end
894
895 return superFunc(self)
896end

getAIMarkers

Description
Definition
getAIMarkers()
Code
855function Sprayer:getAIMarkers(superFunc)
856 local spec = self.spec_aiImplement
857
858 local sprayType = self:getActiveSprayType()
859 if sprayType ~= nil and not spec.useAttributesOfAttachedImplement then
860 if sprayType.ai.rightMarker ~= nil then
861 if spec.aiMarkersInverted then
862 return sprayType.ai.rightMarker, sprayType.ai.leftMarker, sprayType.ai.backMarker, true
863 else
864 return sprayType.ai.leftMarker, sprayType.ai.rightMarker, sprayType.ai.backMarker, false
865 end
866 end
867 end
868
869 return superFunc(self)
870end

getAIRequiresTurnOffOnHeadland

Description
Definition
getAIRequiresTurnOffOnHeadland()
Code
1052function Sprayer:getAIRequiresTurnOffOnHeadland(superFunc)
1053 return true
1054end

getAISizeMarkers

Description
Definition
getAISizeMarkers()
Code
874function Sprayer:getAISizeMarkers(superFunc)
875 local sprayType = self:getActiveSprayType()
876 if sprayType ~= nil then
877 if sprayType.ai.sizeLeftMarker ~= nil then
878 return sprayType.ai.sizeLeftMarker, sprayType.ai.sizeRightMarker, sprayType.ai.sizeBackMarker
879 end
880 end
881
882 return superFunc(self)
883end

getAreControlledActionsAllowed

Description
Returns if controlled actions are allowed
Definition
getAreControlledActionsAllowed()
Return Values
booleanallowallow controlled actions
stringwarningnot allowed warning
Code
919function Sprayer:getAreControlledActionsAllowed(superFunc)
920 local spec = self.spec_sprayer
921
922 if spec.needsToBeFilledToTurnOn then
923 if self:getFillUnitFillLevel(spec.fillUnitIndex) <= 0 and self:getFillUnitCapacity(spec.fillUnitIndex) ~= 0 then
924 return false, g_i18n:getText("info_firstFillTheTool")
925 end
926 end
927
928 return superFunc(self)
929end

getAreEffectsVisible

Description
Definition
getAreEffectsVisible()
Code
570function Sprayer:getAreEffectsVisible()
571 return self.spec_sprayer.workAreaParameters.lastSprayTime + 100 > g_time
572end

getCanBeTurnedOn

Description
Definition
getCanBeTurnedOn()
Code
948function Sprayer:getCanBeTurnedOn(superFunc)
949 local spec = self.spec_sprayer
950 if not spec.allowsSpraying then
951 return false
952 end
953
954 if self:getFillUnitFillLevel(self:getSprayerFillUnitIndex()) <= 0 and spec.needsToBeFilledToTurnOn then
955 if not self:getIsAIActive() then
956 local sprayVehicle = nil
957 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
958 for _, src in ipairs(spec.fillTypeSources[supportedSprayType]) do
959 local vehicle = src.vehicle
960 if vehicle:getFillUnitFillType(src.fillUnitIndex) == supportedSprayType and vehicle:getFillUnitFillLevel(src.fillUnitIndex) > 0 then
961 sprayVehicle = vehicle
962 break
963 end
964 end
965 end
966
967 if sprayVehicle == nil then
968 return false
969 end
970 end
971 end
972
973 return superFunc(self)
974end

getCanToggleTurnedOn

Description
Definition
getCanToggleTurnedOn()
Code
933function Sprayer:getCanToggleTurnedOn(superFunc)
934 if self.isClient then
935 local spec = self.spec_sprayer
936 if spec.needsToBeFilledToTurnOn then
937 if not self:getCanBeTurnedOn() and self:getFillUnitCapacity(self:getSprayerFillUnitIndex()) <= 0 then
938 return false
939 end
940 end
941 end
942
943 return superFunc(self)
944end

getDefaultSpeedLimit

Description
Definition
getDefaultSpeedLimit()
Code
1439function Sprayer.getDefaultSpeedLimit()
1440 return 15
1441end

getDirtMultiplier

Description
Definition
getDirtMultiplier()
Code
1058function Sprayer:getDirtMultiplier(superFunc)
1059 local spec = self.spec_sprayer
1060
1061 if spec.isWorking then
1062 return superFunc(self) + self:getWorkDirtMultiplier() * self:getLastSpeed() / self.speedLimit
1063 end
1064
1065 return superFunc(self)
1066end

getDrawFirstFillText

Description
Definition
getDrawFirstFillText()
Code
900function Sprayer:getDrawFirstFillText(superFunc)
901 if self.isClient then
902 local spec = self.spec_sprayer
903 if spec.needsToBeFilledToTurnOn then
904 if self:getIsActiveForInput() and self:getIsSelected() and not self.isAlwaysTurnedOn then
905 if not self:getCanBeTurnedOn() and self:getFillUnitFillLevel(self:getSprayerFillUnitIndex()) <= 0 and self:getFillUnitCapacity(self:getSprayerFillUnitIndex()) > 0 then
906 return true
907 end
908 end
909 end
910 end
911
912 return superFunc(self)
913end

getEffectByNode

Description
Returns the effect object with the given node
Definition
getEffectByNode(integer node)
Arguments
integernodenode
Code
1083function Sprayer:getEffectByNode(superFunc, node)
1084 local spec = self.spec_sprayer
1085
1086 for i=1, #spec.effects do
1087 local effect = spec.effects[i]
1088 if node == effect.node then
1089 return effect
1090 end
1091 end
1092
1093 for i=1, #spec.sprayTypes do
1094 local sprayType = spec.sprayTypes[i]
1095 for j=1, #sprayType.effects do
1096 local effect = sprayType.effects[j]
1097 if node == effect.node then
1098 return effect
1099 end
1100 end
1101 end
1102
1103 return superFunc(self, node)
1104end

getExternalFill

Description
Definition
getExternalFill()
Code
469function Sprayer:getExternalFill(fillType, dt)
470 local found = false
471 local isUnknownFillType = fillType == FillType.UNKNOWN
472 local allowLiquidManure = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.LIQUIDMANURE)
473 local allowDigestate = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.DIGESTATE)
474 local allowManure = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.MANURE)
475 local allowLiquidFertilizer = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.LIQUIDFERTILIZER)
476 local allowFertilizer = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.FERTILIZER)
477 local allowsLiquidManureDigistate = allowLiquidManure or allowDigestate
478 local usage = 0
479
480 local farmId = self:getActiveFarm()
481 local stats = g_currentMission:farmStats(self:getLastTouchedFarmlandFarmId())
482
483 if fillType == FillType.LIQUIDMANURE or fillType == FillType.DIGESTATE or (isUnknownFillType and allowsLiquidManureDigistate) then
484 if g_currentMission.missionInfo.helperSlurrySource == 2 then -- buy manure
485 found = true
486 if g_currentMission.economyManager:getCostPerLiter(FillType.LIQUIDMANURE, false) then
487 fillType = FillType.LIQUIDMANURE
488 else
489 fillType = FillType.DIGESTATE
490 end
491
492 usage = self:getSprayerUsage(fillType, dt)
493 if self.isServer then
494 local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType, false) * 1.5 -- increase price if AI is active to reward the player's manual work
495 stats:updateStats("expenses", price)
496 g_currentMission:addMoney(-price, farmId, MoneyType.PURCHASE_FERTILIZER)
497 end
498 elseif g_currentMission.missionInfo.helperSlurrySource > 2 then
499 local loadingStation = g_currentMission.liquidManureLoadingStations[g_currentMission.missionInfo.helperSlurrySource-2]
500 if self.isServer and loadingStation ~= nil then -- Can be nil if pen was removed
501 usage = self:getSprayerUsage(FillType.LIQUIDMANURE, dt)
502 local remainingDelta = loadingStation:removeFillLevel(FillType.LIQUIDMANURE, usage, farmId or self:getOwnerFarmId())
503 if usage - remainingDelta > 0.000001 then
504 found = true
505 fillType = FillType.LIQUIDMANURE
506 else
507 remainingDelta = loadingStation:removeFillLevel(FillType.DIGESTATE, usage, farmId or self:getOwnerFarmId())
508 if usage - remainingDelta > 0.000001 then
509 found = true
510 fillType = FillType.DIGESTATE
511 end
512 end
513 end
514 end
515 elseif fillType == FillType.MANURE or (fillType == FillType.UNKNOWN and allowManure) then
516 if g_currentMission.missionInfo.helperManureSource == 2 then -- buy manure
517 found = true
518 fillType = FillType.MANURE
519
520 usage = self:getSprayerUsage(fillType, dt)
521 if self.isServer then
522 local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType, false) * 1.5 -- increase price if AI is active to reward the player's manual work
523 stats:updateStats("expenses", price)
524 g_currentMission:addMoney(-price, farmId, MoneyType.PURCHASE_FERTILIZER)
525 end
526 elseif g_currentMission.missionInfo.helperManureSource > 2 then
527 local loadingStation = g_currentMission.manureLoadingStations[g_currentMission.missionInfo.helperManureSource-2]
528 if self.isServer and loadingStation ~= nil then -- Can be nil if pen was removed
529 usage = self:getSprayerUsage(FillType.MANURE, dt)
530 local remainingDelta = loadingStation:removeFillLevel(FillType.MANURE, usage, farmId or self:getOwnerFarmId())
531 if usage - remainingDelta > 0.000001 then
532 found = true
533 fillType = FillType.MANURE
534 end
535 end
536 end
537 elseif fillType == FillType.FERTILIZER or
538 fillType == FillType.LIQUIDFERTILIZER or
539 fillType == FillType.HERBICIDE or
540 fillType == FillType.LIME or
541 (fillType == FillType.UNKNOWN and (allowLiquidFertilizer or allowFertilizer)) then
542 if g_currentMission.missionInfo.helperBuyFertilizer then
543 found = true
544 if fillType == FillType.UNKNOWN then
545 if self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.LIQUIDFERTILIZER) then
546 fillType = FillType.LIQUIDFERTILIZER
547 else
548 fillType = FillType.FERTILIZER
549 end
550 end
551
552 usage = self:getSprayerUsage(fillType, dt)
553 if self.isServer then
554 local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType, false) * 1.5 -- increase price if AI is active to reward the player's manual work
555 stats:updateStats("expenses", price)
556 g_currentMission:addMoney(-price, farmId, MoneyType.PURCHASE_FERTILIZER)
557 end
558 end
559 end
560
561 if found then
562 return fillType, usage
563 end
564
565 return FillType.UNKNOWN, 0
566end

getFillVolumeUVScrollSpeed

Description
Definition
getFillVolumeUVScrollSpeed()
Code
1030function Sprayer:getFillVolumeUVScrollSpeed(superFunc, fillVolumeIndex)
1031 local spec = self.spec_sprayer
1032
1033 local sprayerFillVolumeIndex = spec.fillVolumeIndex
1034 local sprayType = self:getActiveSprayType()
1035 if sprayType ~= nil then
1036 sprayerFillVolumeIndex = sprayType.fillVolumeIndex or sprayerFillVolumeIndex
1037 end
1038
1039 if fillVolumeIndex == sprayerFillVolumeIndex then
1040 if self:getIsTurnedOn() then
1041 if not self:getIsSprayerExternallyFilled() then
1042 return spec.dischargeUVScrollSpeed[1], spec.dischargeUVScrollSpeed[2], spec.dischargeUVScrollSpeed[3]
1043 end
1044 end
1045 end
1046
1047 return superFunc(self, fillVolumeIndex)
1048end

getIsSprayerExternallyFilled

Description
Returns if sprayer is currently filled by external sources
Definition
getIsSprayerExternallyFilled()
Code
439function Sprayer:getIsSprayerExternallyFilled()
440 if self:getIsAIActive() then
441 -- we do not allow the ai to fill externally if no tank is mounted
442 local sprayCapacity = self:getFillUnitCapacity(self:getSprayerFillUnitIndex())
443 if sprayCapacity == 0 then
444 local spec = self.spec_sprayer
445 local hasSource = false
446 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
447 if #spec.fillTypeSources[supportedSprayType] > 0 then
448 hasSource = true
449 break
450 end
451 end
452
453 if not hasSource then
454 return false
455 end
456 end
457
458 local spec = self.spec_sprayer
459 return (spec.isSlurryTanker and g_currentMission.missionInfo.helperSlurrySource > 1)
460 or (spec.isManureSpreader and g_currentMission.missionInfo.helperManureSource > 1)
461 or (spec.isFertilizerSprayer and g_currentMission.missionInfo.helperBuyFertilizer)
462 end
463
464 return false
465end

getIsSprayTypeActive

Description
Definition
getIsSprayTypeActive()
Code
800function Sprayer:getIsSprayTypeActive(sprayType)
801 if sprayType.fillTypes ~= nil then
802 local retValue = false
803
804 local currentFillType = self:getFillUnitFillType(sprayType.fillUnitIndex or self.spec_sprayer.fillUnitIndex)
805 for _, fillType in ipairs(sprayType.fillTypes) do
806 if currentFillType == g_fillTypeManager:getFillTypeIndexByName(fillType) then
807 retValue = true
808 end
809 end
810
811 if not retValue then
812 return false
813 end
814 end
815
816 return true
817end

getIsWorkAreaActive

Description
Definition
getIsWorkAreaActive()
Code
993function Sprayer:getIsWorkAreaActive(superFunc, workArea)
994 if workArea.sprayType ~= nil then
995 local sprayType = self:getActiveSprayType()
996 if sprayType ~= nil then
997 if sprayType.index ~= workArea.sprayType then
998 return false
999 end
1000 end
1001 end
1002
1003 return superFunc(self, workArea)
1004end

getRawSpeedLimit

Description
Definition
getRawSpeedLimit()
Code
1014function Sprayer:getRawSpeedLimit(superFunc)
1015 local spec = self.spec_sprayer
1016 local sprayType
1017 if spec.workAreaParameters ~= nil then
1018 sprayType = spec.workAreaParameters.sprayType
1019 end
1020
1021 if self:getSprayerDoubledAmountActive(sprayType) and self:getIsTurnedOn() then
1022 return spec.doubledAmountSpeed
1023 end
1024
1025 return superFunc(self)
1026end

getSprayerDoubledAmountActive

Description
Definition
getSprayerDoubledAmountActive()
Code
832function Sprayer:getSprayerDoubledAmountActive(sprayTypeIndex)
833 local spec = self.spec_sprayer
834 -- only allow double spray amount for manure, digestate and slurry
835 if not spec.isFertilizerSprayer then
836 if sprayTypeIndex == nil then
837 return spec.doubledAmountIsActive, true
838 else
839 local desc = g_sprayTypeManager:getSprayTypeByIndex(sprayTypeIndex)
840 if desc ~= nil then
841 if desc.isFertilizer then
842 return spec.doubledAmountIsActive, true
843 end
844 else
845 return spec.doubledAmountIsActive, true
846 end
847 end
848 end
849
850 return false, false
851end

getSprayerFillUnitIndex

Description
Definition
getSprayerFillUnitIndex()
Code
727function Sprayer:getSprayerFillUnitIndex()
728 local sprayType = self:getActiveSprayType()
729 if sprayType ~= nil then
730 return sprayType.fillUnitIndex
731 end
732
733 return self.spec_sprayer.fillUnitIndex
734end

getSprayerUsage

Description
Definition
getSprayerUsage()
Code
624function Sprayer:getSprayerUsage(fillType, dt)
625 if fillType == FillType.UNKNOWN then
626 return 0
627 end
628
629 local spec = self.spec_sprayer
630
631 local scale = Utils.getNoNil(spec.usageScale.fillTypeScales[fillType], spec.usageScale.default)
632 local litersPerSecond = 1
633
634 local sprayType = g_sprayTypeManager:getSprayTypeByFillTypeIndex(fillType)
635 if sprayType ~= nil then
636 litersPerSecond = sprayType.litersPerSecond
637 end
638
639 local usageScale = spec.usageScale
640 local activeSprayType = self:getActiveSprayType()
641 if activeSprayType ~= nil then
642 usageScale = activeSprayType.usageScale
643 end
644
645 local workWidth
646 if usageScale.workAreaIndex ~= nil then
647 workWidth = self:getWorkAreaWidth(usageScale.workAreaIndex)
648 else
649 workWidth = usageScale.workingWidth
650 end
651
652 return scale * litersPerSecond * self.speedLimit * workWidth * dt * 0.001
653end

getUseSprayerAIRequirements

Description
Definition
getUseSprayerAIRequirements()
Code
657function Sprayer:getUseSprayerAIRequirements()
658 return true
659end

getVariableWorkWidthUsage

Description
Returns the current usage for variable work width (nil if usage should not be displayed)
Definition
getVariableWorkWidthUsage()
Return Values
floatusageusage
Code
1109function Sprayer:getVariableWorkWidthUsage(superFunc)
1110 local usage = superFunc(self)
1111 if usage == nil then
1112 if self:getIsTurnedOn() then
1113 return self.spec_sprayer.workAreaParameters.usagePerMin
1114 end
1115
1116 return 0
1117 end
1118
1119 return usage
1120end

getWearMultiplier

Description
Definition
getWearMultiplier()
Code
1070function Sprayer:getWearMultiplier(superFunc)
1071 local spec = self.spec_sprayer
1072
1073 if spec.isWorking then
1074 return superFunc(self) + self:getWorkWearMultiplier() * self:getLastSpeed() / self.speedLimit
1075 end
1076
1077 return superFunc(self)
1078end

initSpecialization

Description
Definition
initSpecialization()
Code
34function Sprayer.initSpecialization()
35 g_workAreaTypeManager:addWorkAreaType("sprayer", false)
36
37 local schema = Vehicle.xmlSchema
38 schema:setXMLSpecializationType("Sprayer")
39
40 schema:register(XMLValueType.BOOL, "vehicle.sprayer#allowsSpraying", "Allows spraying", true)
41 schema:register(XMLValueType.BOOL, "vehicle.sprayer#activateTankOnLowering", "Activate tank on lowering", false)
42 schema:register(XMLValueType.BOOL, "vehicle.sprayer#activateOnLowering", "Activate on lowering", false)
43
44 schema:register(XMLValueType.FLOAT, "vehicle.sprayer.usageScales#scale", "Usage scale", 1)
45 schema:register(XMLValueType.FLOAT, "vehicle.sprayer.usageScales#workingWidth", "Working width", 12)
46 schema:register(XMLValueType.INT, "vehicle.sprayer.usageScales#workAreaIndex", "Work area that is used for working width reference instead of #workingWidth")
47
48 schema:register(XMLValueType.STRING, "vehicle.sprayer.usageScales.sprayUsageScale(?)#fillType", "Fill type name")
49 schema:register(XMLValueType.FLOAT, "vehicle.sprayer.usageScales.sprayUsageScale(?)#scale", "Scale")
50
51 schema:register(XMLValueType.INT, Sprayer.SPRAY_TYPE_XML_KEY .. "#fillUnitIndex", "Fill unit index")
52 schema:register(XMLValueType.INT, Sprayer.SPRAY_TYPE_XML_KEY .. "#unloadInfoIndex", "Unload info index")
53 schema:register(XMLValueType.INT, Sprayer.SPRAY_TYPE_XML_KEY .. "#fillVolumeIndex", "Fill volume index")
54
55 SoundManager.registerSampleXMLPaths(schema, Sprayer.SPRAY_TYPE_XML_KEY .. ".sounds", "work")
56 SoundManager.registerSampleXMLPaths(schema, Sprayer.SPRAY_TYPE_XML_KEY .. ".sounds", "spray")
57 AnimationManager.registerAnimationNodesXMLPaths(schema, Sprayer.SPRAY_TYPE_XML_KEY .. ".animationNodes")
58 EffectManager.registerEffectXMLPaths(schema, Sprayer.SPRAY_TYPE_XML_KEY .. ".effects")
59
60 schema:register(XMLValueType.STRING, Sprayer.SPRAY_TYPE_XML_KEY .. ".turnedAnimation#name", "Turned animation name")
61 schema:register(XMLValueType.FLOAT, Sprayer.SPRAY_TYPE_XML_KEY .. ".turnedAnimation#turnOnSpeedScale", "Speed Scale while turned on", 1)
62 schema:register(XMLValueType.FLOAT, Sprayer.SPRAY_TYPE_XML_KEY .. ".turnedAnimation#turnOffSpeedScale", "Speed Scale while turned off", "Inversed #turnOnSpeedScale")
63 schema:register(XMLValueType.BOOL, Sprayer.SPRAY_TYPE_XML_KEY .. ".turnedAnimation#externalFill", "Animation is played while sprayer is externally filled", true)
64
65 schema:register(XMLValueType.NODE_INDEX, Sprayer.SPRAY_TYPE_XML_KEY .. ".ai.areaMarkers#leftNode", "AI marker left node")
66 schema:register(XMLValueType.NODE_INDEX, Sprayer.SPRAY_TYPE_XML_KEY .. ".ai.areaMarkers#rightNode", "AI marker right node")
67 schema:register(XMLValueType.NODE_INDEX, Sprayer.SPRAY_TYPE_XML_KEY .. ".ai.areaMarkers#backNode", "AI marker back node")
68 schema:register(XMLValueType.NODE_INDEX, Sprayer.SPRAY_TYPE_XML_KEY .. ".ai.sizeMarkers#leftNode", "AI size marker left node")
69 schema:register(XMLValueType.NODE_INDEX, Sprayer.SPRAY_TYPE_XML_KEY .. ".ai.sizeMarkers#rightNode", "AI size marker right node")
70 schema:register(XMLValueType.NODE_INDEX, Sprayer.SPRAY_TYPE_XML_KEY .. ".ai.sizeMarkers#backNode", "AI size marker back node")
71
72 AIImplement.registerAICollisionTriggerXMLPaths(schema, Sprayer.SPRAY_TYPE_XML_KEY .. ".ai")
73
74 schema:register(XMLValueType.STRING, Sprayer.SPRAY_TYPE_XML_KEY .. "#fillTypes", "Fill types")
75 schema:register(XMLValueType.FLOAT, Sprayer.SPRAY_TYPE_XML_KEY .. ".usageScales#workingWidth", "Work width", 12)
76 schema:register(XMLValueType.INT, Sprayer.SPRAY_TYPE_XML_KEY .. ".usageScales#workAreaIndex", "Work area that is used for working width reference instead of #workingWidth")
77
78 ObjectChangeUtil.registerObjectChangeXMLPaths(schema, Sprayer.SPRAY_TYPE_XML_KEY)
79
80 EffectManager.registerEffectXMLPaths(schema, "vehicle.sprayer.effects")
81 SoundManager.registerSampleXMLPaths(schema, "vehicle.sprayer.sounds", "work")
82 SoundManager.registerSampleXMLPaths(schema, "vehicle.sprayer.sounds", "spray")
83 AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.sprayer.animationNodes")
84
85 schema:register(XMLValueType.STRING, "vehicle.sprayer.animation#name", "Spray animation name")
86 schema:register(XMLValueType.INT, "vehicle.sprayer#fillUnitIndex", "Fill unit index", 1)
87 schema:register(XMLValueType.INT, "vehicle.sprayer#unloadInfoIndex", "Unload info index", 1)
88 schema:register(XMLValueType.INT, "vehicle.sprayer#fillVolumeIndex", "Fill volume index")
89 schema:register(XMLValueType.VECTOR_3, "vehicle.sprayer#fillVolumeDischargeScrollSpeed", "Fill volume discharge scroll speed", "0 0 0")
90
91 schema:register(XMLValueType.FLOAT, "vehicle.sprayer.doubledAmount#decreasedSpeed", "Speed while doubled amount is sprayed", "automatically calculated")
92 schema:register(XMLValueType.FLOAT, "vehicle.sprayer.doubledAmount#decreaseFactor", "Decrease factor that is applied on speedLimit while doubled amount is sprayed", 0.5)
93 schema:register(XMLValueType.STRING, "vehicle.sprayer.doubledAmount#toggleButton", "Name of input action to toggle doubled amount", "IMPLEMENT_EXTRA4")
94
95 schema:register(XMLValueType.L10N_STRING, "vehicle.sprayer.doubledAmount#deactivateText", "Deactivated text", "action_deactivateDoubledSprayAmount")
96 schema:register(XMLValueType.L10N_STRING, "vehicle.sprayer.doubledAmount#activateText", "Activate text", "action_activateDoubledSprayAmount")
97
98 schema:register(XMLValueType.STRING, "vehicle.sprayer.turnedAnimation#name", "Turned animation name")
99 schema:register(XMLValueType.FLOAT, "vehicle.sprayer.turnedAnimation#turnOnSpeedScale", "Speed Scale while turned on", 1)
100 schema:register(XMLValueType.FLOAT, "vehicle.sprayer.turnedAnimation#turnOffSpeedScale", "Speed Scale while turned off", "Inversed #turnOnSpeedScale")
101 schema:register(XMLValueType.BOOL, "vehicle.sprayer.turnedAnimation#externalFill", "Animation is played while sprayer is externally filled", true)
102
103 schema:register(XMLValueType.INT, WorkArea.WORK_AREA_XML_KEY .. "#sprayType", "Spray type index")
104 schema:register(XMLValueType.INT, WorkArea.WORK_AREA_XML_CONFIG_KEY .. "#sprayType", "Spray type index")
105
106 schema:setXMLSpecializationType()
107end

loadSprayTypeFromXML

Description
Definition
loadSprayTypeFromXML()
Code
738function Sprayer:loadSprayTypeFromXML(xmlFile, key, sprayType)
739 sprayType.fillUnitIndex = xmlFile:getValue(key.. "#fillUnitIndex", 1)
740 sprayType.unloadInfoIndex = xmlFile:getValue(key.. "#unloadInfoIndex", 1)
741 sprayType.fillVolumeIndex = xmlFile:getValue(key.. "#fillVolumeIndex")
742
743 sprayType.samples = {}
744 sprayType.samples.work = g_soundManager:loadSampleFromXML(xmlFile, key.. ".sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
745 sprayType.samples.spray = g_soundManager:loadSampleFromXML(xmlFile, key.. ".sounds", "spray", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
746
747 sprayType.effects = g_effectManager:loadEffect(xmlFile, key.. ".effects", self.components, self, self.i3dMappings)
748
749 sprayType.animationNodes = g_animationManager:loadAnimations(xmlFile, key.. ".animationNodes", self.components, self, self.i3dMappings)
750
751 sprayType.turnedAnimation = self.xmlFile:getValue(key .. ".turnedAnimation#name", "")
752 sprayType.turnedAnimationTurnOnSpeedScale = self.xmlFile:getValue(key .. ".turnedAnimation#turnOnSpeedScale", 1)
753 sprayType.turnedAnimationTurnOffSpeedScale = self.xmlFile:getValue(key .. ".turnedAnimation#turnOffSpeedScale", -sprayType.turnedAnimationTurnOnSpeedScale)
754 sprayType.turnedAnimationExternalFill = self.xmlFile:getValue(key .. ".turnedAnimation#externalFill", true)
755
756 sprayType.ai = {}
757 sprayType.ai.leftMarker = self.xmlFile:getValue(key .. ".ai.areaMarkers#leftNode", nil, self.components, self.i3dMappings)
758 sprayType.ai.rightMarker = self.xmlFile:getValue(key .. ".ai.areaMarkers#rightNode", nil, self.components, self.i3dMappings)
759 sprayType.ai.backMarker = self.xmlFile:getValue(key .. ".ai.areaMarkers#backNode", nil, self.components, self.i3dMappings)
760
761 sprayType.ai.sizeLeftMarker = self.xmlFile:getValue(key .. ".ai.sizeMarkers#leftNode", nil, self.components, self.i3dMappings)
762 sprayType.ai.sizeRightMarker = self.xmlFile:getValue(key .. ".ai.sizeMarkers#rightNode", nil, self.components, self.i3dMappings)
763 sprayType.ai.sizeBackMarker = self.xmlFile:getValue(key .. ".ai.sizeMarkers#backNode", nil, self.components, self.i3dMappings)
764
765 if self.loadAICollisionTriggerFromXML ~= nil then
766 sprayType.ai.collisionTrigger = self:loadAICollisionTriggerFromXML(self.xmlFile, key .. ".ai")
767 end
768
769 local fillTypesStr = xmlFile:getValue(key.. "#fillTypes")
770 if fillTypesStr ~= nil then
771 sprayType.fillTypes = fillTypesStr:split(" ")
772 end
773
774 sprayType.objectChanges = {}
775 ObjectChangeUtil.loadObjectChangeFromXML(self.xmlFile, key, sprayType.objectChanges, self.components, self)
776 ObjectChangeUtil.setObjectChanges(sprayType.objectChanges, false)
777
778 sprayType.usageScale = {}
779 sprayType.usageScale.workingWidth = self.xmlFile:getValue(key..".usageScales#workingWidth", 12)
780 sprayType.usageScale.workAreaIndex = self.xmlFile:getValue(key..".usageScales#workAreaIndex")
781
782 return true
783end

loadWorkAreaFromXML

Description
Definition
loadWorkAreaFromXML()
Code
979function Sprayer:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key)
980 local retValue = superFunc(self, workArea, xmlFile, key)
981
982 if workArea.type == WorkAreaType.DEFAULT then
983 workArea.type = WorkAreaType.SPRAYER
984 end
985
986 workArea.sprayType = xmlFile:getValue(key.. "#sprayType")
987
988 return retValue
989end

onAIImplementEnd

Description
Definition
onAIImplementEnd()
Code
1416function Sprayer:onAIImplementEnd()
1417 -- turn off all fill type sources on ai turn off
1418 local spec = self.spec_sprayer
1419 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
1420 for _, src in ipairs(spec.fillTypeSources[supportedSprayType]) do
1421 local vehicle = src.vehicle
1422 if vehicle.getIsTurnedOn ~= nil then
1423 if vehicle:getIsTurnedOn() then
1424 vehicle:setIsTurnedOn(false, true)
1425 end
1426 end
1427 end
1428 end
1429end

onDelete

Description
Definition
onDelete()
Code
315function Sprayer:onDelete()
316 local spec = self.spec_sprayer
317
318 g_effectManager:deleteEffects(spec.effects)
319 g_soundManager:deleteSamples(spec.samples)
320 g_animationManager:deleteAnimations(spec.animationNodes)
321
322 if spec.sprayTypes ~= nil then
323 for _, sprayType in ipairs(spec.sprayTypes) do
324 g_effectManager:deleteEffects(sprayType.effects)
325 g_soundManager:deleteSamples(sprayType.samples)
326 g_animationManager:deleteAnimations(sprayType.animationNodes)
327 end
328 end
329end

onEndWorkAreaProcessing

Description
Definition
onEndWorkAreaProcessing()
Code
1288function Sprayer:onEndWorkAreaProcessing(dt, hasProcessed)
1289 local spec = self.spec_sprayer
1290
1291 if self.isServer then
1292 if spec.workAreaParameters.isActive then
1293 local sprayVehicle = spec.workAreaParameters.sprayVehicle
1294 local usage = spec.workAreaParameters.usage
1295
1296 if sprayVehicle ~= nil then
1297 local sprayVehicleFillUnitIndex = spec.workAreaParameters.sprayVehicleFillUnitIndex
1298 local sprayFillType = spec.workAreaParameters.sprayFillType
1299
1300 local unloadInfoIndex = spec.unloadInfoIndex
1301 local sprayType = self:getActiveSprayType()
1302 if sprayType ~= nil then
1303 unloadInfoIndex = sprayType.unloadInfoIndex
1304 end
1305
1306 local unloadInfo = self:getFillVolumeUnloadInfo(unloadInfoIndex)
1307 sprayVehicle:addFillUnitFillLevel(self:getOwnerFarmId(), sprayVehicleFillUnitIndex, -usage, sprayFillType, ToolType.UNDEFINED, unloadInfo)
1308 end
1309
1310 local ha = MathUtil.areaToHa(spec.workAreaParameters.lastStatsArea, g_currentMission:getFruitPixelsToSqm())
1311 local stats = g_currentMission:farmStats(self:getLastTouchedFarmlandFarmId())
1312 stats:updateStats("sprayedHectares", ha)
1313 stats:updateStats("sprayedTime", dt/(1000*60))
1314 stats:updateStats("sprayUsage", usage)
1315 self:updateLastWorkedArea(spec.workAreaParameters.lastStatsArea)
1316 end
1317 end
1318
1319 self:updateSprayerEffects()
1320end

onFillUnitFillLevelChanged

Description
Definition
onFillUnitFillLevelChanged()
Code
1379function Sprayer:onFillUnitFillLevelChanged(fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta)
1380 local fillLevel = self:getFillUnitFillLevel(fillUnitIndex)
1381 if fillLevel == 0 and self:getIsTurnedOn() and not self:getIsAIActive() then
1382 local spec = self.spec_sprayer
1383
1384 -- only deactivate sprayer if no fill type source for the same fill type is available
1385 local hasValidSource = false
1386 if spec.fillTypeSources[fillType] ~= nil then
1387 for _, src in ipairs(spec.fillTypeSources[fillType]) do
1388 local vehicle = src.vehicle
1389 if vehicle:getIsFillUnitActive(src.fillUnitIndex) then
1390 local vehicleFillType = vehicle:getFillUnitFillType(src.fillUnitIndex)
1391 local vehicleFillLevel = vehicle:getFillUnitFillLevel(src.fillUnitIndex)
1392 if vehicleFillLevel > 0 and vehicleFillType == fillType then
1393 hasValidSource = true
1394 end
1395 end
1396 end
1397 end
1398
1399 if not hasValidSource then
1400 self:setIsTurnedOn(false)
1401 end
1402 end
1403end

onLoad

Description
Definition
onLoad()
Code
186function Sprayer:onLoad(savegame)
187 local spec = self.spec_sprayer
188
189 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.sprayParticles.emitterShape", "vehicle.sprayer.effects.effectNode#effectClass='ParticleEffect'") --FS17 to FS19
190 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.sprayer#needsTankActivation") --FS19 to FS22
191
192 spec.allowsSpraying = self.xmlFile:getValue("vehicle.sprayer#allowsSpraying", true)
193 spec.activateTankOnLowering = self.xmlFile:getValue("vehicle.sprayer#activateTankOnLowering", false)
194 spec.activateOnLowering = self.xmlFile:getValue("vehicle.sprayer#activateOnLowering", false)
195
196 spec.usageScale = {}
197 spec.usageScale.default = self.xmlFile:getValue("vehicle.sprayer.usageScales#scale", 1)
198 spec.usageScale.workingWidth = self.xmlFile:getValue("vehicle.sprayer.usageScales#workingWidth", 12)
199 spec.usageScale.workAreaIndex = self.xmlFile:getValue("vehicle.sprayer.usageScales#workAreaIndex")
200 spec.usageScale.fillTypeScales = {}
201 local i = 0
202 while true do
203 local key = string.format("vehicle.sprayer.usageScales.sprayUsageScale(%d)", i)
204 if not self.xmlFile:hasProperty(key) then
205 break
206 end
207 local fillTypeStr = self.xmlFile:getValue(key.. "#fillType")
208 local scale = self.xmlFile:getValue(key.. "#scale")
209 if fillTypeStr ~= nil and scale ~= nil then
210 local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeStr)
211 if fillTypeIndex ~= nil then
212 spec.usageScale.fillTypeScales[fillTypeIndex] = scale
213 else
214 print("Warning: Invalid spray usage scale fill type '"..fillTypeStr.."' in '" .. self.configFileName.. "'")
215 end
216 end
217 i = i + 1
218 end
219
220 spec.sprayTypes = {}
221 i = 0
222 while true do
223 local key = string.format("vehicle.sprayer.sprayTypes.sprayType(%d)", i)
224 if not self.xmlFile:hasProperty(key) then
225 break
226 end
227
228 local sprayType = {}
229 if self:loadSprayTypeFromXML(self.xmlFile, key, sprayType) then
230 table.insert(spec.sprayTypes, sprayType)
231 sprayType.index = #spec.sprayTypes
232 end
233
234 i = i + 1
235 end
236
237 spec.lastActiveSprayType = nil
238
239 if self.isClient then
240 spec.effects = g_effectManager:loadEffect(self.xmlFile, "vehicle.sprayer.effects", self.components, self, self.i3dMappings)
241
242 spec.animationName = self.xmlFile:getValue("vehicle.sprayer.animation#name", "")
243
244 spec.samples = {}
245 spec.samples.work = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.sprayer.sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
246 spec.samples.spray = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.sprayer.sounds", "spray", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
247
248 spec.sampleFillEnabled = false
249 spec.sampleFillStopTime = -1
250 spec.lastFillLevel = -1
251
252 spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.sprayer.animationNodes", self.components, self, self.i3dMappings)
253 end
254
255 if self.addAIGroundTypeRequirements ~= nil then
256 self:addAIGroundTypeRequirements(Sprayer.AI_REQUIRED_GROUND_TYPES)
257 end
258
259 spec.supportedSprayTypes = {}
260
261 spec.fillUnitIndex = self.xmlFile:getValue("vehicle.sprayer#fillUnitIndex", 1)
262 spec.unloadInfoIndex = self.xmlFile:getValue("vehicle.sprayer#unloadInfoIndex", 1)
263 spec.fillVolumeIndex = self.xmlFile:getValue("vehicle.sprayer#fillVolumeIndex")
264 spec.dischargeUVScrollSpeed = self.xmlFile:getValue("vehicle.sprayer#fillVolumeDischargeScrollSpeed", "0 0 0", true)
265
266 if self:getFillUnitByIndex(spec.fillUnitIndex) == nil then
267 Logging.xmlError(self.xmlFile, "FillUnit '%d' not defined!", spec.fillUnitIndex)
268 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
269 return
270 end
271
272 local decreasedSpeedLimit = self.xmlFile:getValue("vehicle.sprayer.doubledAmount#decreasedSpeed")
273 if decreasedSpeedLimit == nil then
274 local decreaseFactor = self.xmlFile:getValue("vehicle.sprayer.doubledAmount#decreaseFactor", 0.5)
275 decreasedSpeedLimit = self:getSpeedLimit() * decreaseFactor
276 end
277 spec.doubledAmountSpeed = decreasedSpeedLimit
278 spec.doubledAmountIsActive = false
279
280 local toggleButtonStr = self.xmlFile:getValue("vehicle.sprayer.doubledAmount#toggleButton")
281 if toggleButtonStr ~= nil then
282 spec.toggleDoubledAmountInputBinding = InputAction[toggleButtonStr]
283 end
284 spec.toggleDoubledAmountInputBinding = spec.toggleDoubledAmountInputBinding or InputAction.DOUBLED_SPRAY_AMOUNT
285 spec.doubledAmountDeactivateText = self.xmlFile:getValue("vehicle.sprayer.doubledAmount#deactivateText", "action_deactivateDoubledSprayAmount", self.customEnvironment)
286 spec.doubledAmountActivateText = self.xmlFile:getValue("vehicle.sprayer.doubledAmount#activateText", "action_activateDoubledSprayAmount", self.customEnvironment)
287
288 spec.turnedAnimation = self.xmlFile:getValue("vehicle.sprayer.turnedAnimation#name", "")
289 spec.turnedAnimationTurnOnSpeedScale = self.xmlFile:getValue("vehicle.sprayer.turnedAnimation#turnOnSpeedScale", 1)
290 spec.turnedAnimationTurnOffSpeedScale = self.xmlFile:getValue("vehicle.sprayer.turnedAnimation#turnOffSpeedScale", -spec.turnedAnimationTurnOnSpeedScale)
291 spec.turnedAnimationExternalFill = self.xmlFile:getValue("vehicle.sprayer.turnedAnimation#externalFill", true)
292
293 spec.needsToBeFilledToTurnOn = true
294 spec.useSpeedLimit = true
295 spec.isWorking = false
296 spec.lastEffectsState = false
297
298 spec.isSlurryTanker = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.LIQUIDMANURE) or self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.DIGESTATE)
299 spec.isManureSpreader = self:getFillUnitAllowsFillType(self:getSprayerFillUnitIndex(), FillType.MANURE)
300 spec.isFertilizerSprayer = not spec.isSlurryTanker and not spec.isManureSpreader
301
302 spec.workAreaParameters = {}
303 spec.workAreaParameters.sprayVehicle = nil
304 spec.workAreaParameters.sprayVehicleFillUnitIndex = nil
305 spec.workAreaParameters.lastChangedArea = 0
306 spec.workAreaParameters.lastTotalArea = 0
307 spec.workAreaParameters.lastIsExternallyFilled = false
308 spec.workAreaParameters.lastSprayTime = -math.huge
309 spec.workAreaParameters.usage = 0
310 spec.workAreaParameters.usagePerMin = 0
311end

onPreDetach

Description
Definition
onPreDetach()
Code
1176function Sprayer:onPreDetach(attacherVehicle, jointDescIndex)
1177 if attacherVehicle.setIsTurnedOn ~= nil and attacherVehicle:getIsTurnedOn() then
1178 attacherVehicle:setIsTurnedOn(false)
1179 end
1180end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
382function Sprayer:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
383 if self.isClient then
384 local spec = self.spec_sprayer
385 self:clearActionEventsTable(spec.actionEvents)
386 if isActiveForInputIgnoreSelection then
387 local _, actionEventId = self:addActionEvent(spec.actionEvents, spec.toggleDoubledAmountInputBinding, self, Sprayer.actionEventDoubledAmount, false, true, false, true, nil)
388 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_HIGH)
389 end
390 end
391end

onSetLowered

Description
Definition
onSetLowered()
Code
1348function Sprayer:onSetLowered(isLowered)
1349 local spec = self.spec_sprayer
1350
1351 if self.isServer then
1352 if spec.activateOnLowering then
1353 if self:getCanBeTurnedOn() then
1354 self:setIsTurnedOn(isLowered)
1355 else
1356 spec.pendingActivationAfterLowering = true
1357 end
1358 end
1359
1360 if not isLowered then
1361 spec.pendingActivationAfterLowering = false
1362 end
1363 end
1364
1365 if spec.activateTankOnLowering then
1366 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
1367 for _, src in ipairs(spec.fillTypeSources[supportedSprayType]) do
1368 local vehicle = src.vehicle
1369 if vehicle.getIsTurnedOn ~= nil then
1370 vehicle:setIsTurnedOn(isLowered, true)
1371 end
1372 end
1373 end
1374 end
1375end

onSprayTypeChange

Description
Definition
onSprayTypeChange()
Code
1407function Sprayer:onSprayTypeChange(activeSprayType)
1408 local spec = self.spec_sprayer
1409 for _, sprayType in ipairs(spec.sprayTypes) do
1410 ObjectChangeUtil.setObjectChanges(sprayType.objectChanges, sprayType == activeSprayType)
1411 end
1412end

onStartWorkAreaProcessing

Description
Definition
onStartWorkAreaProcessing()
Code
1184function Sprayer:onStartWorkAreaProcessing(dt)
1185 local spec = self.spec_sprayer
1186
1187 local sprayVehicle = nil
1188 local sprayVehicleFillUnitIndex = nil
1189 local fillType = self:getFillUnitFillType(self:getSprayerFillUnitIndex())
1190 local usage = self:getSprayerUsage(fillType, dt)
1191 local sprayFillLevel = self:getFillUnitFillLevel(self:getSprayerFillUnitIndex())
1192
1193 if sprayFillLevel > 0 then
1194 sprayVehicle = self
1195 sprayVehicleFillUnitIndex = self:getSprayerFillUnitIndex()
1196 else
1197 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
1198 for _, src in ipairs(spec.fillTypeSources[supportedSprayType]) do
1199 local vehicle = src.vehicle
1200 if vehicle:getIsFillUnitActive(src.fillUnitIndex) then
1201 local vehicleFillType = vehicle:getFillUnitFillType(src.fillUnitIndex)
1202 local vehicleFillLevel = vehicle:getFillUnitFillLevel(src.fillUnitIndex)
1203 if vehicleFillLevel > 0 and vehicleFillType == supportedSprayType then
1204 sprayVehicle = vehicle
1205 sprayVehicleFillUnitIndex = src.fillUnitIndex
1206 fillType = sprayVehicle:getFillUnitFillType(sprayVehicleFillUnitIndex)
1207 usage = self:getSprayerUsage(fillType, dt)
1208 sprayFillLevel = vehicleFillLevel
1209 break
1210 end
1211 else
1212 -- if the ai is active we try to activate the source to activate the fill unit
1213 if self:getIsAIActive() then
1214 if vehicle.setIsTurnedOn ~= nil then
1215 if not vehicle:getIsTurnedOn() then
1216 vehicle:setIsTurnedOn(true)
1217 end
1218 end
1219 end
1220 end
1221 end
1222 end
1223 end
1224
1225 local isExternallyFilled = self:getIsSprayerExternallyFilled()
1226 if isExternallyFilled then
1227 -- only consume while ai is on field, not while turning, so we check for the tools turned on state
1228 if self:getIsTurnedOn() then
1229 fillType, usage = self:getExternalFill(fillType, dt)
1230 sprayFillLevel = usage
1231
1232 -- do not consume the fill unit fill level if we buy fertilizer
1233 sprayVehicle = nil
1234 sprayVehicleFillUnitIndex = nil
1235 end
1236 end
1237
1238 if isExternallyFilled ~= spec.workAreaParameters.lastIsExternallyFilled then
1239 local sprayType = self:getActiveSprayType()
1240 if sprayType ~= nil then
1241 if isExternallyFilled then
1242 if not sprayType.turnedAnimationExternalFill and self:getIsAnimationPlaying(sprayType.turnedAnimation) then
1243 self:stopAnimation(sprayType.turnedAnimation)
1244 end
1245 else
1246 if not self:getIsAnimationPlaying(sprayType.turnedAnimation) then
1247 self:playAnimation(sprayType.turnedAnimation, sprayType.turnedAnimationTurnOnSpeedScale, self:getAnimationTime(sprayType.turnedAnimation), true)
1248 end
1249 end
1250 end
1251
1252 if isExternallyFilled then
1253 if not spec.turnedAnimationExternalFill and self:getIsAnimationPlaying(spec.turnedAnimation) then
1254 self:stopAnimation(spec.turnedAnimation)
1255 end
1256 else
1257 if not self:getIsAnimationPlaying(spec.turnedAnimation) then
1258 self:playAnimation(spec.turnedAnimation, spec.turnedAnimationTurnOnSpeedScale, self:getAnimationTime(spec.turnedAnimation), true)
1259 end
1260 end
1261
1262 spec.workAreaParameters.lastIsExternallyFilled = isExternallyFilled
1263 end
1264
1265 if self.isServer then
1266 if fillType ~= FillType.UNKNOWN and fillType ~= spec.workAreaParameters.sprayFillType then
1267 self:setSprayerAITerrainDetailProhibitedRange(fillType)
1268 end
1269 end
1270
1271 spec.workAreaParameters.sprayType = g_sprayTypeManager:getSprayTypeIndexByFillTypeIndex(fillType)
1272 spec.workAreaParameters.sprayFillType = fillType
1273 spec.workAreaParameters.sprayFillLevel = sprayFillLevel
1274 spec.workAreaParameters.usage = usage
1275 spec.workAreaParameters.usagePerMin = usage / dt * 1000 * 60
1276 spec.workAreaParameters.sprayVehicle = sprayVehicle
1277 spec.workAreaParameters.sprayVehicleFillUnitIndex = sprayVehicleFillUnitIndex
1278 spec.workAreaParameters.lastChangedArea = 0
1279 spec.workAreaParameters.lastTotalArea = 0
1280 spec.workAreaParameters.lastStatsArea = 0
1281 spec.workAreaParameters.isActive = false
1282
1283 spec.isWorking = false
1284end

onStateChange

Description
Definition
onStateChange()
Code
1324function Sprayer:onStateChange(state, data)
1325 if state == Vehicle.STATE_CHANGE_ATTACH or state == Vehicle.STATE_CHANGE_DETACH or Vehicle.STATE_CHANGE_FILLTYPE_CHANGE then
1326 local spec = self.spec_sprayer
1327
1328 spec.fillTypeSources = {}
1329 local supportedFillTypes = self:getFillUnitSupportedFillTypes(self:getSprayerFillUnitIndex())
1330 spec.supportedSprayTypes = {}
1331
1332 if supportedFillTypes ~= nil then
1333 for fillType, supported in pairs(supportedFillTypes) do
1334 if supported then
1335 spec.fillTypeSources[fillType] = {}
1336 table.insert(spec.supportedSprayTypes, fillType)
1337 end
1338 end
1339 end
1340
1341 local root = self.rootVehicle
1342 FillUnit.addFillTypeSources(spec.fillTypeSources, root, self, spec.supportedSprayTypes)
1343 end
1344end

onTurnedOff

Description
Definition
onTurnedOff()
Code
1152function Sprayer:onTurnedOff()
1153 local spec = self.spec_sprayer
1154 if self.isClient then
1155 self:updateSprayerEffects()
1156
1157 if spec.animationName ~= "" and self.stopAnimation ~= nil then
1158 self:stopAnimation(spec.animationName, true)
1159 end
1160
1161 g_soundManager:stopSample(spec.samples.work)
1162
1163 -- deactivate effects on all spray types (the spray type has may changed during activation)
1164 for _, sprayType in ipairs(spec.sprayTypes) do
1165 g_soundManager:stopSample(sprayType.samples.work)
1166
1167 self:playAnimation(sprayType.turnedAnimation, sprayType.turnedAnimationTurnOffSpeedScale, self:getAnimationTime(sprayType.turnedAnimation), true)
1168 end
1169
1170 self:playAnimation(spec.turnedAnimation, spec.turnedAnimationTurnOffSpeedScale, self:getAnimationTime(spec.turnedAnimation), true)
1171 end
1172end

onTurnedOn

Description
Definition
onTurnedOn()
Code
1124function Sprayer:onTurnedOn()
1125 local spec = self.spec_sprayer
1126 if self.isClient then
1127 self:updateSprayerEffects()
1128
1129 if spec.animationName ~= "" and self.playAnimation ~= nil then
1130 self:playAnimation(spec.animationName, 1, self:getAnimationTime(spec.animationName), true)
1131 end
1132
1133 g_soundManager:playSample(spec.samples.work)
1134
1135 local sprayType = self:getActiveSprayType()
1136 if sprayType ~= nil then
1137 g_soundManager:playSample(sprayType.samples.work)
1138
1139 if sprayType.turnedAnimationExternalFill or not self:getIsSprayerExternallyFilled() then
1140 self:playAnimation(sprayType.turnedAnimation, sprayType.turnedAnimationTurnOnSpeedScale, self:getAnimationTime(sprayType.turnedAnimation), true)
1141 end
1142 end
1143
1144 if spec.turnedAnimationExternalFill or not self:getIsSprayerExternallyFilled() then
1145 self:playAnimation(spec.turnedAnimation, spec.turnedAnimationTurnOnSpeedScale, self:getAnimationTime(spec.turnedAnimation), true)
1146 end
1147 end
1148end

onUpdateTick

Description
Definition
onUpdateTick()
Code
333function Sprayer:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
334 local activeSprayType = self:getActiveSprayType()
335 if activeSprayType ~= nil then
336 local spec = self.spec_sprayer
337 if activeSprayType ~= spec.lastActiveSprayType then
338 for _, sprayType in ipairs(spec.sprayTypes) do
339 if sprayType == spec.lastActiveSprayType then
340 g_effectManager:stopEffects(sprayType.effects)
341 g_animationManager:stopAnimations(sprayType.animationNodes)
342 end
343 end
344
345 SpecializationUtil.raiseEvent(self, "onSprayTypeChange", activeSprayType)
346 spec.lastActiveSprayType = activeSprayType
347
348 self:updateSprayerEffects(true)
349 end
350 end
351
352 if self.isClient then
353 local spec = self.spec_sprayer
354 local actionEvent = spec.actionEvents[spec.toggleDoubledAmountInputBinding]
355 if actionEvent ~= nil then
356 local text
357 if spec.doubledAmountIsActive then
358 text = spec.doubledAmountDeactivateText
359 else
360 text = spec.doubledAmountActivateText
361 end
362 g_inputBinding:setActionEventText(actionEvent.actionEventId, text)
363
364 local _, isAllowed = self:getSprayerDoubledAmountActive(spec.workAreaParameters.sprayType)
365 g_inputBinding:setActionEventActive(actionEvent.actionEventId, isAllowed)
366 end
367 end
368
369 if self.isServer then
370 local spec = self.spec_sprayer
371 if spec.pendingActivationAfterLowering then
372 if self:getCanBeTurnedOn() then
373 self:setIsTurnedOn(true)
374 spec.pendingActivationAfterLowering = false
375 end
376 end
377 end
378end

onVariableWorkWidthSectionChanged

Description
Definition
onVariableWorkWidthSectionChanged()
Code
1433function Sprayer:onVariableWorkWidthSectionChanged()
1434 self:updateSprayerEffects(true)
1435end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
111function Sprayer.prerequisitesPresent(specializations)
112 return SpecializationUtil.hasSpecialization(FillUnit, specializations) and
113 SpecializationUtil.hasSpecialization(WorkArea, specializations) and
114 SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations)
115end

processSprayerArea

Description
Definition
processSprayerArea()
Code
401function Sprayer:processSprayerArea(workArea, dt)
402 local spec = self.spec_sprayer
403
404 if self:getIsAIActive() and self.isServer then
405 if spec.workAreaParameters.sprayFillType == nil or spec.workAreaParameters.sprayFillType == FillType.UNKNOWN then
406 local rootVehicle = self.rootVehicle
407 rootVehicle:stopCurrentAIJob(AIMessageErrorOutOfFill.new())
408
409 return 0, 0
410 end
411 end
412
413 if spec.workAreaParameters.sprayFillLevel <= 0 then
414 return 0, 0
415 end
416
417 local sx,_,sz = getWorldTranslation(workArea.start)
418 local wx,_,wz = getWorldTranslation(workArea.width)
419 local hx,_,hz = getWorldTranslation(workArea.height)
420
421 local sprayAmount = self:getSprayerDoubledAmountActive(spec.workAreaParameters.sprayType) and 2 or 1
422 local changedArea, totalArea = FSDensityMapUtil.updateSprayArea(sx,sz, wx,wz, hx,hz, spec.workAreaParameters.sprayType, sprayAmount)
423
424 spec.workAreaParameters.isActive = true
425 spec.workAreaParameters.lastChangedArea = spec.workAreaParameters.lastChangedArea + changedArea
426 spec.workAreaParameters.lastStatsArea = spec.workAreaParameters.lastStatsArea + changedArea
427 spec.workAreaParameters.lastTotalArea = spec.workAreaParameters.lastTotalArea + totalArea
428 spec.workAreaParameters.lastSprayTime = g_time
429
430 if self:getLastSpeed() > 1 then
431 spec.isWorking = true
432 end
433
434 return changedArea, totalArea
435end

registerEventListeners

Description
Definition
registerEventListeners()
Code
166function Sprayer.registerEventListeners(vehicleType)
167 SpecializationUtil.registerEventListener(vehicleType, "onLoad", Sprayer)
168 SpecializationUtil.registerEventListener(vehicleType, "onDelete", Sprayer)
169 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Sprayer)
170 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Sprayer)
171 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", Sprayer)
172 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", Sprayer)
173 SpecializationUtil.registerEventListener(vehicleType, "onPreDetach", Sprayer)
174 SpecializationUtil.registerEventListener(vehicleType, "onStartWorkAreaProcessing", Sprayer)
175 SpecializationUtil.registerEventListener(vehicleType, "onEndWorkAreaProcessing", Sprayer)
176 SpecializationUtil.registerEventListener(vehicleType, "onStateChange", Sprayer)
177 SpecializationUtil.registerEventListener(vehicleType, "onSetLowered", Sprayer)
178 SpecializationUtil.registerEventListener(vehicleType, "onFillUnitFillLevelChanged", Sprayer)
179 SpecializationUtil.registerEventListener(vehicleType, "onSprayTypeChange", Sprayer)
180 SpecializationUtil.registerEventListener(vehicleType, "onAIImplementEnd", Sprayer)
181 SpecializationUtil.registerEventListener(vehicleType, "onVariableWorkWidthSectionChanged", Sprayer)
182end

registerEvents

Description
Definition
registerEvents()
Code
119function Sprayer.registerEvents(vehicleType)
120 SpecializationUtil.registerEvent(vehicleType, "onSprayTypeChange")
121end

registerFunctions

Description
Definition
registerFunctions()
Code
125function Sprayer.registerFunctions(vehicleType)
126 SpecializationUtil.registerFunction(vehicleType, "processSprayerArea", Sprayer.processSprayerArea)
127 SpecializationUtil.registerFunction(vehicleType, "getIsSprayerExternallyFilled", Sprayer.getIsSprayerExternallyFilled)
128 SpecializationUtil.registerFunction(vehicleType, "getExternalFill", Sprayer.getExternalFill)
129 SpecializationUtil.registerFunction(vehicleType, "getAreEffectsVisible", Sprayer.getAreEffectsVisible)
130 SpecializationUtil.registerFunction(vehicleType, "updateSprayerEffects", Sprayer.updateSprayerEffects)
131 SpecializationUtil.registerFunction(vehicleType, "getSprayerUsage", Sprayer.getSprayerUsage)
132 SpecializationUtil.registerFunction(vehicleType, "getUseSprayerAIRequirements", Sprayer.getUseSprayerAIRequirements)
133 SpecializationUtil.registerFunction(vehicleType, "setSprayerAITerrainDetailProhibitedRange", Sprayer.setSprayerAITerrainDetailProhibitedRange)
134 SpecializationUtil.registerFunction(vehicleType, "getSprayerFillUnitIndex", Sprayer.getSprayerFillUnitIndex)
135 SpecializationUtil.registerFunction(vehicleType, "loadSprayTypeFromXML", Sprayer.loadSprayTypeFromXML)
136 SpecializationUtil.registerFunction(vehicleType, "getActiveSprayType", Sprayer.getActiveSprayType)
137 SpecializationUtil.registerFunction(vehicleType, "getIsSprayTypeActive", Sprayer.getIsSprayTypeActive)
138 SpecializationUtil.registerFunction(vehicleType, "setSprayerDoubledAmountActive", Sprayer.setSprayerDoubledAmountActive)
139 SpecializationUtil.registerFunction(vehicleType, "getSprayerDoubledAmountActive", Sprayer.getSprayerDoubledAmountActive)
140end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
144function Sprayer.registerOverwrittenFunctions(vehicleType)
145 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIMarkers", Sprayer.getAIMarkers)
146 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAISizeMarkers", Sprayer.getAISizeMarkers)
147 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIImplementCollisionTrigger", Sprayer.getAIImplementCollisionTrigger)
148 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDrawFirstFillText", Sprayer.getDrawFirstFillText)
149 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAreControlledActionsAllowed", Sprayer.getAreControlledActionsAllowed)
150 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleTurnedOn", Sprayer.getCanToggleTurnedOn)
151 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeTurnedOn", Sprayer.getCanBeTurnedOn)
152 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWorkAreaFromXML", Sprayer.loadWorkAreaFromXML)
153 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", Sprayer.getIsWorkAreaActive)
154 SpecializationUtil.registerOverwrittenFunction(vehicleType, "doCheckSpeedLimit", Sprayer.doCheckSpeedLimit)
155 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getRawSpeedLimit", Sprayer.getRawSpeedLimit)
156 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillVolumeUVScrollSpeed", Sprayer.getFillVolumeUVScrollSpeed)
157 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAIRequiresTurnOffOnHeadland", Sprayer.getAIRequiresTurnOffOnHeadland)
158 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", Sprayer.getDirtMultiplier)
159 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", Sprayer.getWearMultiplier)
160 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getEffectByNode", Sprayer.getEffectByNode)
161 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getVariableWorkWidthUsage", Sprayer.getVariableWorkWidthUsage)
162end

setSprayerAITerrainDetailProhibitedRange

Description
Definition
setSprayerAITerrainDetailProhibitedRange()
Code
663function Sprayer:setSprayerAITerrainDetailProhibitedRange(fillType)
664 if self:getUseSprayerAIRequirements() then
665 if self.addAITerrainDetailProhibitedRange ~= nil then
666 self:clearAITerrainDetailProhibitedRange()
667 self:clearAIFruitRequirements()
668 self:clearAIFruitProhibitions()
669
670 self:addAIGroundTypeRequirements(Sprayer.AI_REQUIRED_GROUND_TYPES)
671
672 local sprayTypeDesc = g_sprayTypeManager:getSprayTypeByFillTypeIndex(fillType)
673 if sprayTypeDesc ~= nil then
674 if sprayTypeDesc.isHerbicide then
675 local weedSystem = g_currentMission.weedSystem
676 if weedSystem ~= nil then
677 local weedMapId, weedFirstChannel, weedNumChannels = weedSystem:getDensityMapData()
678 local replacementData = weedSystem:getHerbicideReplacements()
679 if replacementData.weed ~= nil then
680 local startState, lastState = -1, -1
681 for sourceState, targetState in pairs(replacementData.weed.replacements) do
682 if startState == -1 then
683 startState = sourceState
684 else
685 if sourceState ~= lastState + 1 then
686 self:addAIFruitRequirement(nil, startState, lastState, weedMapId, weedFirstChannel, weedNumChannels)
687 startState = sourceState
688 end
689 end
690
691 lastState = sourceState
692 end
693
694 if startState ~= -1 then
695 self:addAIFruitRequirement(nil, startState, lastState, weedMapId, weedFirstChannel, weedNumChannels)
696 end
697 end
698 end
699 else
700 local mission = g_currentMission
701 local sprayTypeMapId, sprayTypeFirstChannel, sprayTypeNumChannels = mission.fieldGroundSystem:getDensityMapData(FieldDensityMap.SPRAY_TYPE)
702 local sprayLevelMapId, sprayLevelFirstChannel, sprayLevelNumChannels = mission.fieldGroundSystem:getDensityMapData(FieldDensityMap.SPRAY_LEVEL)
703 local sprayLevelMaxValue = mission.fieldGroundSystem:getMaxValue(FieldDensityMap.SPRAY_LEVEL)
704 self:addAITerrainDetailProhibitedRange(sprayTypeDesc.sprayGroundType, sprayTypeDesc.sprayGroundType, sprayTypeFirstChannel, sprayTypeNumChannels)
705 -- TODO enable after field crops query support bitVectorMaps
706 --self:addAIFruitProhibitions(0, sprayTypeDesc.sprayGroundType, sprayTypeDesc.sprayGroundType, sprayTypeMapId, sprayTypeFirstChannel, sprayTypeNumChannels)
707 --self:addAIFruitProhibitions(0, sprayLevelMaxValue, sprayLevelMaxValue, sprayLevelMapId, sprayLevelFirstChannel, sprayLevelNumChannels)
708 end
709
710 -- block ai from working on fully growth fields
711 if sprayTypeDesc.isHerbicide or sprayTypeDesc.isFertilizer then
712 for _, fruitType in pairs(g_fruitTypeManager:getFruitTypes()) do
713 if fruitType.terrainDataPlaneId ~= nil and fruitType.name:lower() ~= "grass" then
714 if fruitType.minHarvestingGrowthState ~= nil and fruitType.maxHarvestingGrowthState ~= nil then
715 self:addAIFruitProhibitions(fruitType.index, fruitType.minHarvestingGrowthState, fruitType.maxHarvestingGrowthState)
716 end
717 end
718 end
719 end
720 end
721 end
722 end
723end

setSprayerDoubledAmountActive

Description
Definition
setSprayerDoubledAmountActive()
Code
821function Sprayer:setSprayerDoubledAmountActive(isActive, noEventSend)
822 local spec = self.spec_sprayer
823 if isActive ~= spec.doubledAmountIsActive then
824 spec.doubledAmountIsActive = isActive
825
826 SprayerDoubledAmountEvent.sendEvent(self, isActive, noEventSend)
827 end
828end

updateSprayerEffects

Description
Definition
updateSprayerEffects()
Code
576function Sprayer:updateSprayerEffects(force)
577 local spec = self.spec_sprayer
578
579 local effectsState = self:getAreEffectsVisible()
580 if effectsState ~= spec.lastEffectsState or force then
581 if effectsState then
582 local fillType = self:getFillUnitLastValidFillType(self:getSprayerFillUnitIndex())
583 if fillType == FillType.UNKNOWN then
584 fillType = self:getFillUnitFirstSupportedFillType(self:getSprayerFillUnitIndex())
585 end
586
587 g_effectManager:setFillType(spec.effects, fillType)
588 g_effectManager:startEffects(spec.effects)
589
590 g_soundManager:playSample(spec.samples.spray)
591
592 local sprayType = self:getActiveSprayType()
593 if sprayType ~= nil then
594 g_effectManager:setFillType(sprayType.effects, fillType)
595 g_effectManager:startEffects(sprayType.effects)
596
597 g_animationManager:startAnimations(sprayType.animationNodes)
598
599 g_soundManager:playSample(sprayType.samples.spray)
600 end
601
602 g_animationManager:startAnimations(spec.animationNodes)
603 else
604 g_effectManager:stopEffects(spec.effects)
605 g_animationManager:stopAnimations(spec.animationNodes)
606
607 g_soundManager:stopSample(spec.samples.spray)
608
609 -- deactivate effects on all spray types (the spray type has may changed during activation)
610 for _, sprayType in ipairs(spec.sprayTypes) do
611 g_effectManager:stopEffects(sprayType.effects)
612 g_animationManager:stopAnimations(sprayType.animationNodes)
613
614 g_soundManager:stopSample(sprayType.samples.spray)
615 end
616 end
617
618 spec.lastEffectsState = effectsState
619 end
620end