Script v1.4.4.0
- Handtools
- Events
- Objects
- Placeables
- Triggers
- Utils
- Vehicles
- Specializations
- AIVehicle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BuiltInCutterTrailer
- BunkerSiloCompacter
- Combine
- ConveyorBelt
- Cover
- CrabSteering
- Crawler
- Cultivator
- Cutter
- Cylindered
- Drivable
- DynamicMountAttacher
- Fillable
- FillActivatable
- FillVolume
- Foldable
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- FuelTrailer
- Honk
- HookLiftContainer
- HookLiftTrailer
- Leveler
- Lights
- LivestockTrailer
- ManureBarrel
- ManureSpreader
- MixerWagon
- Motorized
- Mountable
- Mower
- NonTabbable
- Overloading
- Pickup
- Pipe
- Plough
- PowerConsumer
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- RidgeMarker
- Roller
- Ropes
- RotorSpreader
- SemiTrailerFront
- Shovel
- SowingMachine
- SpeedRotatingParts
- Sprayer
- Steerable
- StrawBlower
- StumpCutter
- Tedder
- TensionBelts
- Trailer
- TreePlanter
- TreePlanterActivatable
- TreeSaw
- TurnOnVehicle
- Washable
- WaterTrailer
- Weeder
- WheelRotations
- Windrower
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkParticles
Engine v7.0.0.2
- General
- Entity
- Node
- Scenegraph
- Lighting
- Camera
- Shape
- Particle System
- Physics
- Spline
- Animation
- Overlays
- Sound
- Input
- XML
- Network
- Callbacks
- Text Rendering
- Terrain Detail
- Tire Track
- Editor
- Rendering
- String
- Math
- I3D
- Fillplanes
Foundation Reference
Sprayer
DescriptionClass for all sprayersFunctions
- registerSprayType
- initSpecialization
- prerequisitesPresent
- preLoad
- load
- delete
- readUpdateStream
- writeUpdateStream
- update
- updateTick
- draw
- getDrawFirstFillText
- onDetach
- onDeactivate
- onDeactivateSounds
- getHasSpray
- aiAllowedToRefill
- getCanAddHelpButtonText
- getTankActivators
- getIsTurnedOnAllowed
- onTurnedOn
- onTurnedOff
- onAiTurnOn
- onAiTurnOff
- onAiLower
- onAiRaise
- findAttachedSprayerTank
- loadWorkAreaFromXML
- getIsReadyToSpray
- getAreEffectsVisible
- getLitersPerSecond
- doCheckSpeedLimit
- getDefaultSpeedLimit
- processSprayerAreas
registerSprayType
DescriptionRegister new spray typeDefinition
registerSprayType(string name, string nameI18N, integer category, float pricePerLiter, float litersPerSecond, boolean showOnPriceTable, string hudOverlayFilename, string hudOverlayFilenameSmall, float massPerLiter)Arguments
string | name | name of new type |
string | nameI18N | I18N text |
integer | category | fill type category |
float | pricePerLiter | price per liter |
float | litersPerSecond | usage in liter per second |
boolean | showOnPriceTable | show fill type on price table |
string | hudOverlayFilename | hud overlay filename |
string | hudOverlayFilenameSmall | hud overlay filename small |
float | massPerLiter | mass per liter in t |
35 | function Sprayer.registerSprayType(name, nameI18N, category, pricePerLiter, litersPerSecond, showOnPriceTable, hudOverlayFilename, hudOverlayFilenameSmall, massPerLiter) |
36 | local key = "SPRAYTYPE_"..string.upper(name); |
37 | if Sprayer[key] == nil then |
38 | Sprayer.NUM_SPRAYTYPES = Sprayer.NUM_SPRAYTYPES+1; |
39 | Sprayer[key] = Sprayer.NUM_SPRAYTYPES; |
40 | |
41 | local desc = {name = name, index = Sprayer.NUM_SPRAYTYPES}; |
42 | desc.litersPerSecond = litersPerSecond; |
43 | |
44 | Sprayer.sprayTypes[name] = desc; |
45 | Sprayer.sprayTypeIndexToDesc[Sprayer.NUM_SPRAYTYPES] = desc; |
46 | |
47 | local fillType = FillUtil.registerFillType(name, nameI18N, category, pricePerLiter, showOnPriceTable, hudOverlayFilename, hudOverlayFilenameSmall, massPerLiter) |
48 | Sprayer.sprayTypeToFillType[Sprayer.NUM_SPRAYTYPES] = fillType; |
49 | Sprayer.fillTypeToSprayType[fillType] = Sprayer.NUM_SPRAYTYPES; |
50 | end |
51 | end |
initSpecialization
DescriptionCalled on specialization initializingDefinition
initSpecialization()Code
55 | function Sprayer.initSpecialization() |
56 | WorkArea.registerAreaType("sprayer"); |
57 | end |
prerequisitesPresent
DescriptionChecks if all prerequisite specializations are loadedDefinition
prerequisitesPresent(table specializations)Arguments
table | specializations | specializations |
boolean | hasPrerequisite | true if all prerequisite specializations are loaded |
63 | function Sprayer.prerequisitesPresent(specializations) |
64 | return SpecializationUtil.hasSpecialization(Fillable, specializations) and |
65 | SpecializationUtil.hasSpecialization(WorkArea, specializations) and |
66 | SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations) and |
67 | SpecializationUtil.hasSpecialization(AttacherJoints, specializations); |
68 | end |
preLoad
DescriptionCalled before loadingDefinition
preLoad(table savegame)Arguments
table | savegame | savegame |
73 | function Sprayer:preLoad(savegame) |
74 | self.getIsReadyToSpray = Sprayer.getIsReadyToSpray; |
75 | self.getAreEffectsVisible = Sprayer.getAreEffectsVisible; |
76 | self.getLitersPerSecond = Sprayer.getLitersPerSecond; |
77 | self.supportsFillTriggers = true; |
78 | self.loadWorkAreaFromXML = Utils.overwrittenFunction(self.loadWorkAreaFromXML, Sprayer.loadWorkAreaFromXML); |
79 | self.doCheckSpeedLimit = Utils.overwrittenFunction(self.doCheckSpeedLimit, Sprayer.doCheckSpeedLimit); |
80 | self.getIsTurnedOnAllowed = Utils.overwrittenFunction(self.getIsTurnedOnAllowed, Sprayer.getIsTurnedOnAllowed); |
81 | self.getCanAddHelpButtonText = Utils.overwrittenFunction(self.getCanAddHelpButtonText, Sprayer.getCanAddHelpButtonText); |
82 | self.aiAllowedToRefill = Utils.overwrittenFunction(self.aiAllowedToRefill, Sprayer.aiAllowedToRefill); |
83 | self.getDrawFirstFillText = Utils.overwrittenFunction(self.getDrawFirstFillText, Sprayer.getDrawFirstFillText); |
84 | self.getHasSpray = Sprayer.getHasSpray; |
85 | |
86 | self.processSprayerAreas = Sprayer.processSprayerAreas; |
87 | end |
load
DescriptionCalled on loadingDefinition
load(table savegame)Arguments
table | savegame | savegame |
92 | function Sprayer:load(savegame) |
93 | |
94 | self.isSprayerTank = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#isTank"), false); |
95 | self.allowsSpraying = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#allowsSpraying"), true); |
96 | self.needsTankActivation = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#needsTankActivation"), false); |
97 | self.activateTankOnLowering = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#activateTankOnLowering"), false); |
98 | self.stopAiOnEmpty = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#stopAiOnEmpty"), true); |
99 | self.activateOnLowering = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.sprayer#activateOnLowering"), false); |
100 | |
101 | |
102 | self.sprayUsageScale = {} |
103 | self.sprayUsageScale.default = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.sprayUsageScales#scale"), 1) |
104 | self.sprayUsageScale.workingWidth = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.sprayUsageScales#workingWidth"), 12) |
105 | self.sprayUsageScale.fillTypeScales = {} |
106 | local i=0; |
107 | while true do |
108 | local key = string.format("vehicle.sprayUsageScales.sprayUsageScale(%d)", i); |
109 | if not hasXMLProperty(self.xmlFile, key) then |
110 | break; |
111 | end |
112 | local fillType = getXMLString(self.xmlFile, key.. "#fillType"); |
113 | local scale = getXMLFloat(self.xmlFile, key.. "#scale"); |
114 | if fillType ~= nil and scale ~= nil then |
115 | local fillTypeInt = FillUtil.fillTypeNameToInt[fillType]; |
116 | if fillTypeInt ~= nil then |
117 | self.sprayUsageScale.fillTypeScales[fillTypeInt] = scale |
118 | else |
119 | print("Warning: Invalid spray usage scale fill type '"..fillType.."' in '" .. self.configFileName.. "'"); |
120 | end |
121 | end |
122 | i = i+1; |
123 | end |
124 | |
125 | self.lastSprayValveUpdateFoldTime = nil; |
126 | self.sprayParticleSystems = {}; |
127 | self.sprayerEffects = {}; |
128 | |
129 | if self.isClient then |
130 | local i = 0; |
131 | while true do |
132 | local key = string.format("vehicle.sprayParticleSystems.sprayParticleSystem(%d)", i); |
133 | local t = getXMLString(self.xmlFile, key .. "#type"); |
134 | if t == nil then |
135 | break; |
136 | end |
137 | local fillType = FillUtil.fillTypeNameToInt[t]; |
138 | if fillType ~= nil then |
139 | self.sprayParticleSystems[fillType] = {} |
140 | local currentPS = Utils.getNoNil(self.sprayParticleSystems[fillType], {}); |
141 | ParticleUtil.loadParticleSystem(self.xmlFile, currentPS, key, self.components, false, nil, self.baseDirectory); |
142 | currentPS.foldMinLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#foldMinLimit"), 0); |
143 | currentPS.foldMaxLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#foldMaxLimit"), 1); |
144 | table.insert(self.sprayParticleSystems[fillType], currentPS) |
145 | end |
146 | i = i + 1; |
147 | end |
148 | |
149 | local i = 0 |
150 | while true do |
151 | local key = string.format("vehicle.sprayParticles.emitterShape(%d)", i); |
152 | if not hasXMLProperty(self.xmlFile, key) then |
153 | break |
154 | end |
155 | local emitterShape = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#node")); |
156 | local particleType = getXMLString(self.xmlFile, key.."#particleType") |
157 | if emitterShape ~= nil then |
158 | for index, _ in pairs(self.fillUnits) do |
159 | for fillType, _ in pairs(self:getUnitFillTypes(index)) do |
160 | if self.sprayParticleSystems[fillType] == nil then |
161 | self.sprayParticleSystems[fillType] = {} |
162 | end |
163 | local particleSystem = MaterialUtil.getParticleSystem(fillType, particleType) |
164 | if particleSystem ~= nil then |
165 | local currentPS = ParticleUtil.copyParticleSystem(self.xmlFile, key, particleSystem, emitterShape) |
166 | currentPS.foldMinLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#foldMinLimit"), 0); |
167 | currentPS.foldMaxLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#foldMaxLimit"), 1); |
168 | table.insert(self.sprayParticleSystems[fillType], currentPS) |
169 | end |
170 | end |
171 | end |
172 | end |
173 | i = i + 1 |
174 | end |
175 | |
176 | local i = 0; |
177 | while true do |
178 | local key = string.format("vehicle.sprayerEffects.sprayerEffect(%d)", i); |
179 | if not hasXMLProperty(self.xmlFile, key) then |
180 | break; |
181 | end |
182 | |
183 | local effects = EffectManager:loadEffect(self.xmlFile, key, self.components, self); |
184 | if effects ~= nil then |
185 | local sprayerEffect = {} |
186 | sprayerEffect.effects = effects |
187 | sprayerEffect.foldMinLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, key .. "#foldMinLimit"), 0); |
188 | sprayerEffect.foldMaxLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, key .. "#foldMaxLimit"), 1); |
189 | table.insert(self.sprayerEffects, sprayerEffect); |
190 | end |
191 | i = i + 1; |
192 | end |
193 | |
194 | self.sprayingAnimationName = Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.sprayingAnimation#name"), ""); |
195 | |
196 | self.sampleSprayer = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.spraySound", nil, self.baseDirectory); |
197 | |
198 | if self.sampleFill == nil then |
199 | local linkNode = Utils.indexToObject(self.components, Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.fillSound#linkNode"), "0>")); |
200 | self.sampleFill = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.fillSound", nil, self.baseDirectory, linkNode); |
201 | end |
202 | self.sampleFillEnabled = false; |
203 | self.sampleFillStopTime = -1; |
204 | self.lastFillLevel = -1; |
205 | |
206 | self.sprayerTurnedOnRotationNodes = Utils.loadRotationNodes(self.xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "sprayer", self.components); |
207 | self.sprayerTurnedOnScrollers = Utils.loadScrollers(self.components, self.xmlFile, "vehicle.sprayerTurnedOnScrollers.sprayerTurnedOnScroller", {}, false); |
208 | end |
209 | |
210 | self.showFieldNotOwnedWarning = false; |
211 | |
212 | self.isSprayerSpeedLimitActive = false; |
213 | |
214 | if self.sowingMachineGroundContactFlag == nil and self.cultivatorGroundContactFlag == nil then |
215 | table.insert(self.terrainDetailRequiredValueRanges, {g_currentMission.ploughValue, g_currentMission.ploughValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels}); |
216 | table.insert(self.terrainDetailRequiredValueRanges, {g_currentMission.cultivatorValue, g_currentMission.cultivatorValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels}); |
217 | table.insert(self.terrainDetailRequiredValueRanges, {g_currentMission.sowingValue, g_currentMission.sowingValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels}); |
218 | table.insert(self.terrainDetailRequiredValueRanges, {g_currentMission.sowingWidthValue, g_currentMission.sowingWidthValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels}); |
219 | table.insert(self.terrainDetailRequiredValueRanges, {g_currentMission.grassValue, g_currentMission.grassValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels}); |
220 | |
221 | table.insert(self.terrainDetailProhibitValueRanges, {1, 2, g_currentMission.sprayFirstChannel, g_currentMission.sprayNumChannels}); |
222 | table.insert(self.terrainDetailProhibitValueRanges, {g_currentMission.sprayLevelMaxValue, g_currentMission.sprayLevelMaxValue, g_currentMission.sprayLevelFirstChannel, g_currentMission.sprayLevelNumChannels}); |
223 | end |
224 | |
225 | self.sprayer = {}; |
226 | self.sprayer.fillUnitIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.sprayer#fillUnitIndex"), 1); |
227 | self.sprayer.unloadInfoIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.sprayer#unloadInfoIndex"), 1); |
228 | self.sprayer.loadInfoIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.sprayer#loadInfoIndex"), 1); |
229 | self.sprayer.dischargeInfoIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.sprayer#dischargeInfoIndex"), 1); |
230 | |
231 | self.sprayerDirtyFlag = self:getNextDirtyFlag(); |
232 | end |
delete
DescriptionCalled on deletingDefinition
delete()Code
236 | function Sprayer:delete() |
237 | for _, sprayerEffect in pairs(self.sprayerEffects) do |
238 | EffectManager:deleteEffects(sprayerEffect.effects); |
239 | end |
240 | |
241 | for _, particleSystems in pairs(self.sprayParticleSystems) do |
242 | ParticleUtil.deleteParticleSystems(particleSystems) |
243 | end |
244 | |
245 | if self.isClient then |
246 | SoundUtil.deleteSample(self.sampleSprayer); |
247 | SoundUtil.deleteSample(self.sampleFill); |
248 | end |
249 | end |
readUpdateStream
DescriptionCalled on on updateDefinition
readUpdateStream(integer streamId, integer timestamp, table connection)Arguments
integer | streamId | stream ID |
integer | timestamp | timestamp |
table | connection | connection |
262 | function Sprayer:readUpdateStream(streamId, timestamp, connection) |
263 | if connection:getIsServer() then |
264 | self.showFieldNotOwnedWarning = streamReadBool(streamId); |
265 | end |
266 | end |
writeUpdateStream
DescriptionCalled on on updateDefinition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)Arguments
integer | streamId | stream ID |
table | connection | connection |
integer | dirtyMask | dirty mask |
273 | function Sprayer:writeUpdateStream(streamId, connection, dirtyMask) |
274 | if not connection:getIsServer() then |
275 | streamWriteBool(streamId, self.showFieldNotOwnedWarning); |
276 | end |
277 | end |
update
DescriptionCalled on updateDefinition
update(float dt)Arguments
float | dt | time since last call in ms |
288 | function Sprayer:update(dt) |
289 | if self.isClient then |
290 | Utils.updateRotationNodes(self, self.sprayerTurnedOnRotationNodes, dt, self:getIsActive() and self:getIsTurnedOn()); |
291 | Utils.updateScrollers(self.sprayerTurnedOnScrollers, dt, self:getIsActive() and self:getIsTurnedOn()); |
292 | end |
293 | end |
updateTick
DescriptionCalled on update tickDefinition
updateTick(float dt)Arguments
float | dt | time since last call in ms |
298 | function Sprayer:updateTick(dt) |
299 | self.isSprayerSpeedLimitActive = false; |
300 | if self:getIsActive() then |
301 | local showFieldNotOwnedWarning = false; |
302 | |
303 | if self.isServer then |
304 | if self.turnOnDueToLoweredImplement ~= nil then |
305 | if self.turnOnDueToLoweredImplement.object == nil then |
306 | self.turnOnDueToLoweredImplement = nil; |
307 | end |
308 | end |
309 | if self.turnOnDueToLoweredImplement ~= nil then |
310 | if self:getIsTurnedOn() == false then |
311 | self:setIsTurnedOn(true); |
312 | end |
313 | if self.turnOnDueToLoweredImplement.object.activateOnLowering then |
314 | if self.turnOnDueToLoweredImplement.object:getIsTurnedOn() == false then |
315 | self.turnOnDueToLoweredImplement.object:setIsTurnedOn(true); |
316 | end |
317 | end |
318 | end |
319 | if self:getIsTurnedOn() then |
320 | if not self:getIsTurnedOnAllowed(true) then |
321 | self:setIsTurnedOn(false); |
322 | end |
323 | end |
324 | |
325 | local tankActivators = {}; |
326 | Sprayer.getTankActivators(self:getRootAttacherVehicle(), tankActivators); |
327 | if table.getn(tankActivators) > 0 then |
328 | local doTurnOn = false; |
329 | for _,tankActivator in pairs(tankActivators) do |
330 | local attacherVehicle = tankActivator.attacherVehicle; |
331 | if attacherVehicle ~= nil then |
332 | local implementIndex = attacherVehicle:getImplementIndexByObject(tankActivator); |
333 | local implement = attacherVehicle.attachedImplements[implementIndex]; |
334 | local jointDescIndex = implement.jointDescIndex; |
335 | doTurnOn = doTurnOn or attacherVehicle.attacherJoints[jointDescIndex].moveDown; |
336 | end |
337 | end |
338 | self:setIsTurnedOn(doTurnOn); |
339 | end |
340 | |
341 | if self.activateOnLowering and self.isLowered ~= nil then |
342 | if self:isLowered(false) then |
343 | if self:getCanBeTurnedOn() and not self:getIsTurnedOn(true) then |
344 | self:setIsTurnedOn(true); |
345 | end |
346 | else |
347 | self:setIsTurnedOn(false); |
348 | end |
349 | end |
350 | end |
351 | |
352 | |
353 | if self:getIsTurnedOn() and self.allowsSpraying then |
354 | if self.isClient and self:getIsActiveForSound() then |
355 | SoundUtil.playSample(self.sampleSprayer, 0, 0, nil); |
356 | end |
357 | |
358 | local readyToSpray = self:getIsReadyToSpray(); |
359 | self.isSprayerSpeedLimitActive = readyToSpray; |
360 | |
361 | local fillType = self:getUnitLastValidFillType(self.sprayer.fillUnitIndex); |
362 | if fillType == FillUtil.FILLTYPE_UNKNOWN and self.fillUnits[self.sprayer.fillUnitIndex] ~= nil then |
363 | for unitFillType,state in pairs(self.fillUnits[self.sprayer.fillUnitIndex].fillTypes) do |
364 | if unitFillType ~= FillUtil.FILLTYPE_UNKNOWN and state then |
365 | fillType = unitFillType; |
366 | break; |
367 | end |
368 | end |
369 | end |
370 | |
371 | if readyToSpray then |
372 | if self.isServer then |
373 | local litersPerSecond = self:getLitersPerSecond(fillType); |
374 | local usage = litersPerSecond * dt * 0.001; |
375 | |
376 | local hasSpray, newFillType = self:getHasSpray(fillType, usage) |
377 | fillType = newFillType |
378 | if hasSpray then |
379 | local workAreas, showWarning, _ = self:getTypedNetworkAreas(WorkArea.AREATYPE_SPRAYER, true); |
380 | showFieldNotOwnedWarning = showWarning; |
381 | if (table.getn(workAreas) > 0) then |
382 | local pixels = self:processSprayerAreas(workAreas, fillType); |
383 | local ha = Utils.areaToHa(pixels, g_currentMission:getFruitPixelsToSqm()); |
384 | g_currentMission.missionStats:updateStats("fertilizedHectares", ha); |
385 | g_currentMission.missionStats:updateStats("fertilizedTime", dt/(1000*60)); |
386 | if self.lastSowingArea == nil then |
387 | g_currentMission.missionStats:updateStats("workedHectares", ha); |
388 | g_currentMission.missionStats:updateStats("workedTime", dt/(1000*60)); |
389 | end |
390 | g_currentMission.missionStats:updateStats("sprayUsage", usage); |
391 | end |
392 | end |
393 | end |
394 | end |
395 | |
396 | if self.isClient then |
397 | -- update valve particle systems |
398 | local foldAnimTime = self.foldAnimTime |
399 | if (foldAnimTime ~= nil and foldAnimTime ~= self.lastSprayValveUpdateFoldTime) or self.lastTurnedOn == false then |
400 | |
401 | self.lastSprayValveUpdateFoldTime = foldAnimTime; |
402 | self.lastTurnedOn = true; |
403 | |
404 | if self:getAreEffectsVisible() then |
405 | if foldAnimTime ~= nil then |
406 | if self.sprayParticleSystems[fillType] ~= nil then |
407 | for _, ps in pairs(self.sprayParticleSystems[fillType]) do |
408 | if foldAnimTime <= ps.foldMaxLimit and foldAnimTime >= ps.foldMinLimit then |
409 | ParticleUtil.setEmittingState(ps, true); |
410 | else |
411 | ParticleUtil.setEmittingState(ps, false); |
412 | end |
413 | end; |
414 | end |
415 | |
416 | for _, sprayerEffect in pairs(self.sprayerEffects) do |
417 | readyToSpray = readyToSpray and (foldAnimTime > sprayerEffect.foldMinLimit); |
418 | if foldAnimTime <= sprayerEffect.foldMaxLimit and foldAnimTime >= sprayerEffect.foldMinLimit then |
419 | EffectManager:setFillType(sprayerEffect.effects, fillType) |
420 | EffectManager:startEffects(sprayerEffect.effects) |
421 | else |
422 | EffectManager:stopEffects(sprayerEffect.effects); |
423 | end |
424 | end |
425 | else |
426 | if self.sprayParticleSystems[fillType] ~= nil then |
427 | for _, ps in pairs(self.sprayParticleSystems[fillType]) do |
428 | ParticleUtil.setEmittingState(ps, true); |
429 | end; |
430 | end |
431 | for _, sprayerEffect in pairs(self.sprayerEffects) do |
432 | EffectManager:setFillType(sprayerEffect.effects, fillType) |
433 | EffectManager:startEffects(sprayerEffect.effects) |
434 | end |
435 | end |
436 | end |
437 | end |
438 | end |
439 | |
440 | else |
441 | |
442 | if self.isClient then |
443 | for _, particleSystems in pairs(self.sprayParticleSystems) do |
444 | for _, ps in pairs(particleSystems) do |
445 | ParticleUtil.setEmittingState(ps, false); |
446 | end; |
447 | end |
448 | for _, sprayerEffect in pairs(self.sprayerEffects) do |
449 | EffectManager:stopEffects(sprayerEffect.effects); |
450 | end |
451 | end |
452 | end |
453 | self.lastTurnedOn = self:getIsTurnedOn(); |
454 | |
455 | if self.isServer then |
456 | if self.sowingMachineGroundContactFlag == nil then |
457 | if showFieldNotOwnedWarning ~= self.showFieldNotOwnedWarning then |
458 | self.showFieldNotOwnedWarning = showFieldNotOwnedWarning; |
459 | self:raiseDirtyFlags(self.sprayerDirtyFlag); |
460 | end |
461 | end |
462 | end |
463 | end |
464 | |
465 | if self.isClient then |
466 | if self.isFilling then |
467 | if self:getIsActiveForSound(true) then |
468 | SoundUtil.playSample(self.sampleFill, 0, 0, nil); |
469 | SoundUtil.stop3DSample(self.sampleFill); |
470 | else |
471 | SoundUtil.stopSample(self.sampleFill); |
472 | SoundUtil.play3DSample(self.sampleFill); |
473 | end |
474 | else |
475 | SoundUtil.stopSample(self.sampleFill); |
476 | SoundUtil.stop3DSample(self.sampleFill); |
477 | end |
478 | end |
479 | end |
draw
DescriptionCalled on drawDefinition
draw()Code
483 | function Sprayer:draw() |
484 | if self.isClient then |
485 | if self.showFieldNotOwnedWarning then |
486 | g_currentMission:showBlinkingWarning(g_i18n:getText("warning_youDontOwnThisField")); |
487 | end |
488 | end |
489 | end |
getDrawFirstFillText
DescriptionReturns if 'first fill tool' text should be drawedDefinition
getDrawFirstFillText()Return Values
boolean | draw | draw text |
494 | function Sprayer:getDrawFirstFillText(superFunc) |
495 | if self.isClient then |
496 | if self:getIsActiveForInput(true) and not self.isAlwaysTurnedOn then |
497 | if not self:getIsTurnedOnAllowed(true) and self:getUnitFillLevel(self.sprayer.fillUnitIndex) <= 0 and self:getUnitCapacity(self.sprayer.fillUnitIndex) > 0 then |
498 | return true; |
499 | end |
500 | end |
501 | end |
502 | if superFunc ~= nil then |
503 | return superFunc(self); |
504 | end; |
505 | |
506 | return false; |
507 | end; |
onDetach
DescriptionCalled if vehicle gets detachedDefinition
onDetach(table attacherVehicle, integer jointDescIndex)Arguments
table | attacherVehicle | attacher vehicle |
integer | jointDescIndex | index of attacher joint it was attached to |
513 | function Sprayer:onDetach(attacherVehicle, jointDescIndex) |
514 | if attacherVehicle.setIsTurnedOn ~= nil and attacherVehicle:getIsTurnedOn() then |
515 | attacherVehicle:setIsTurnedOn(false); |
516 | end |
517 | end |
onDeactivate
DescriptionCalled on deactivateDefinition
onDeactivate()Code
521 | function Sprayer:onDeactivate() |
522 | self.showFieldNotOwnedWarning = false; |
523 | end |
onDeactivateSounds
DescriptionCalled on deactivating soundsDefinition
onDeactivateSounds()Code
527 | function Sprayer:onDeactivateSounds() |
528 | if self.isClient then |
529 | SoundUtil.stopSample(self.sampleSprayer, true); |
530 | end |
531 | end |
getHasSpray
DescriptionTry to spray and return if something was consumed to update the spray areasDefinition
getHasSpray(integer fillType, float usage)Arguments
integer | fillType | fill type |
float | usage | usage |
boolean | hasSpray | has spray |
integer | fillType | fill type |
539 | function Sprayer:getHasSpray(fillType, usage) |
540 | |
541 | local hasSpray = false; |
542 | |
543 | if not hasSpray and self:getIsHired() and self:aiAllowedToRefill() then |
544 | |
545 | if fillType == FillUtil.FILLTYPE_LIQUIDMANURE or |
546 | fillType == FillUtil.FILLTYPE_DIGESTATE or |
547 | (fillType == FillUtil.FILLTYPE_UNKNOWN and (self:allowUnitFillType(self.sprayer.fillUnitIndex, FillUtil.FILLTYPE_LIQUIDMANURE) or self:allowUnitFillType(self.sprayer.fillUnitIndex, FillUtil.FILLTYPE_DIGESTATE))) then |
548 | if g_currentMission.missionInfo.helperSlurrySource == 2 then -- buy manure |
549 | hasSpray = true; |
550 | if g_currentMission.economyManager:getCostPerLiter(FillUtil.FILLTYPE_LIQUIDMANURE) then |
551 | fillType = FillUtil.FILLTYPE_LIQUIDMANURE; |
552 | else |
553 | fillType = FillUtil.FILLTYPE_DIGESTATE; |
554 | end |
555 | local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType) * 1.5 -- increase price if AI is active to reward the player's manual work |
556 | g_currentMission.missionStats:updateStats("expenses", price); |
557 | g_currentMission:addSharedMoney(-price, "purchaseFertilizer"); |
558 | elseif g_currentMission.missionInfo.helperSlurrySource > 2 then |
559 | local trigger = g_currentMission.liquidManureTriggers[g_currentMission.missionInfo.helperSlurrySource-2].trigger |
560 | if trigger.fillLevel > 0 then |
561 | hasSpray = true; |
562 | fillType = trigger.fillType |
563 | trigger:setFillLevel(trigger.fillLevel-usage) |
564 | end |
565 | end |
566 | |
567 | elseif fillType == FillUtil.FILLTYPE_MANURE or (fillType == FillUtil.FILLTYPE_UNKNOWN and self:allowUnitFillType(self.sprayer.fillUnitIndex, FillUtil.FILLTYPE_MANURE)) then |
568 | if g_currentMission.missionInfo.helperManureSource == 2 then -- buy manure |
569 | hasSpray = true; |
570 | fillType = FillUtil.FILLTYPE_MANURE; |
571 | local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType) * 1.5 -- increase price if AI is active to reward the player's manual work |
572 | g_currentMission.missionStats:updateStats("expenses", price); |
573 | g_currentMission:addSharedMoney(-price, "purchaseFertilizer"); |
574 | elseif g_currentMission.missionInfo.helperManureSource > 2 then |
575 | local manureHeap = g_currentMission.manureHeaps[g_currentMission.missionInfo.helperManureSource-2].manureHeap |
576 | if manureHeap:removeManure(usage) > 0 then |
577 | hasSpray = true; |
578 | fillType = FillUtil.FILLTYPE_MANURE |
579 | end |
580 | end |
581 | |
582 | elseif fillType == FillUtil.FILLTYPE_FERTILIZER or |
583 | fillType == FillUtil.FILLTYPE_LIQUIDFERTILIZER or |
584 | (fillType == FillUtil.FILLTYPE_UNKNOWN and (self:allowUnitFillType(self.sprayer.fillUnitIndex, FillUtil.FILLTYPE_LIQUIDFERTILIZER) or self:allowUnitFillType(self.sprayer.fillUnitIndex, FillUtil.FILLTYPE_FERTILIZER))) then |
585 | if g_currentMission.missionInfo.helperBuyFertilizer then |
586 | hasSpray = true; |
587 | if self:allowUnitFillType(self.sprayer.fillUnitIndex, FillUtil.FILLTYPE_LIQUIDFERTILIZER) then |
588 | fillType = FillUtil.FILLTYPE_LIQUIDFERTILIZER; |
589 | else |
590 | fillType = FillUtil.FILLTYPE_FERTILIZER; |
591 | end |
592 | local price = usage * g_currentMission.economyManager:getCostPerLiter(fillType) * 1.5 -- increase price if AI is active to reward the player's manual work |
593 | g_currentMission.missionStats:updateStats("expenses", price); |
594 | g_currentMission:addSharedMoney(-price, "purchaseFertilizer"); |
595 | end |
596 | |
597 | else |
598 | |
599 | end |
600 | end |
601 | |
602 | if not hasSpray then |
603 | local sprayUsageVehicle = self |
604 | local newFillType = fillType; |
605 | if self:getUnitFillLevel(self.sprayer.fillUnitIndex) == 0 then |
606 | sprayUsageVehicle, newFillType = Sprayer.findAttachedSprayerTank(self:getRootAttacherVehicle(), self:getUnitFillTypes(self.sprayer.fillUnitIndex), self.needsTankActivation); |
607 | end |
608 | |
609 | local oldFillLevel = 0 |
610 | if sprayUsageVehicle ~= nil then |
611 | fillType = newFillType; |
612 | oldFillLevel = sprayUsageVehicle:getUnitFillLevel(sprayUsageVehicle.sprayer.fillUnitIndex); |
613 | sprayUsageVehicle:setUnitFillLevel(sprayUsageVehicle.sprayer.fillUnitIndex, oldFillLevel - usage, fillType, false, sprayUsageVehicle.fillVolumeUnloadInfos[sprayUsageVehicle.sprayer.unloadInfoIndex]); |
614 | end |
615 | hasSpray = oldFillLevel > 0; |
616 | end |
617 | |
618 | if not hasSpray and self:getIsHired() and self.stopAiOnEmpty then |
619 | local rootVehicle = self:getRootAttacherVehicle() |
620 | rootVehicle:stopAIVehicle(AIVehicle.STOP_REASON_OUT_OF_FILL) |
621 | end |
622 | |
623 | return hasSpray, fillType |
624 | end |
aiAllowedToRefill
DescriptionReturn if ai is allowed to refillDefinition
aiAllowedToRefill()Return Values
boolean | allow | ai is allowed to refill |
629 | function Sprayer:aiAllowedToRefill(superFunc) |
630 | if self.needsTankActivation then |
631 | local sprayUsageVehicle, _ = Sprayer.findAttachedSprayerTank(self:getRootAttacherVehicle(), self:getUnitFillTypes(self.sprayer.fillUnitIndex), false, true); |
632 | if sprayUsageVehicle == nil then |
633 | return false; |
634 | end; |
635 | end; |
636 | |
637 | if superFunc ~= nil then |
638 | return superFunc(self); |
639 | end |
640 | |
641 | return true; |
642 | end; |
getCanAddHelpButtonText
DescriptionReturns if turn on help button texts are allowed to displayDefinition
getCanAddHelpButtonText()Return Values
boolean | allow | allow |
647 | function Sprayer:getCanAddHelpButtonText(superFunc) |
648 | if self.activateOnLowering then |
649 | return false; |
650 | end; |
651 | |
652 | if superFunc ~= nil then |
653 | return superFunc(self); |
654 | end |
655 | return true; |
656 | end; |
getTankActivators
DescriptionReturns sprayers who need a tank to activateDefinition
getTankActivators(table currentVehicle, table result)Arguments
table | currentVehicle | current vehicle to check |
table | result | table to add found tank activators |
662 | function Sprayer.getTankActivators(currentVehicle, results) |
663 | if currentVehicle.needsTankActivation then |
664 | table.insert(results, currentVehicle); |
665 | end |
666 | for _,implement in pairs(currentVehicle.attachedImplements) do |
667 | if implement.object ~= nil then |
668 | Sprayer.getTankActivators(implement.object, results); |
669 | end |
670 | end |
671 | end |
getIsTurnedOnAllowed
DescriptionReturns if turn on is allowedDefinition
getIsTurnedOnAllowed(boolean isTurnedOn)Arguments
boolean | isTurnedOn | is turned on |
boolean | allow | allow turn on |
677 | function Sprayer:getIsTurnedOnAllowed(superFunc, isTurnedOn) |
678 | if not self.allowsSpraying then |
679 | return false; |
680 | end |
681 | |
682 | if self.activateOnLowering and self.isLowered ~= nil then |
683 | return self:isLowered(false); |
684 | end |
685 | |
686 | -- if sowingMachine is involved dismiss sprayer complains |
687 | if isTurnedOn and self.sowingMachineGroundContactFlag ~= nil then |
688 | return superFunc(self, isTurnedOn); |
689 | end |
690 | |
691 | if isTurnedOn and self:getUnitFillLevel(self.sprayer.fillUnitIndex) <= 0 then |
692 | |
693 | if self:getIsHired() then |
694 | return true; |
695 | end |
696 | |
697 | -- try to find tank |
698 | local sprayerTank, fillType = Sprayer.findAttachedSprayerTank(self:getRootAttacherVehicle(), self:getUnitFillTypes(self.sprayer.fillUnitIndex), self.needsTankActivation); |
699 | |
700 | if sprayerTank ~= nil and fillType ~= nil then |
701 | return true; |
702 | else |
703 | return false; |
704 | end |
705 | end |
706 | |
707 | if superFunc ~= nil then |
708 | return superFunc(self, isTurnedOn); |
709 | end |
710 | |
711 | return true; |
712 | end |
onTurnedOn
DescriptionCalled on turn onDefinition
onTurnedOn(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
717 | function Sprayer:onTurnedOn(noEventSend) |
718 | if self.isClient then |
719 | if self.foldAnimTime == nil then |
720 | -- If the sprayer is foldable, the spray valves are only turned on within the update loop |
721 | for _, particleSystems in pairs(self.sprayParticleSystems) do |
722 | for _, particleSystem in pairs(particleSystems) do |
723 | ParticleUtil.setEmittingState(particleSystem, false); |
724 | end; |
725 | end |
726 | |
727 | local fillType = self:getUnitLastValidFillType(self.sprayer.fillUnitIndex); |
728 | if fillType == FillUtil.FILLTYPE_UNKNOWN then |
729 | fillType = self:getFirstEnabledFillType(); |
730 | end |
731 | for _, sprayerEffect in pairs(self.sprayerEffects) do |
732 | EffectManager:setFillType(sprayerEffect.effects, fillType) |
733 | EffectManager:startEffects(sprayerEffect.effects) |
734 | end |
735 | end |
736 | if self.sprayingAnimationName ~= "" and self.playAnimation ~= nil then |
737 | self:playAnimation(self.sprayingAnimationName, 1, self:getAnimationTime(self.sprayingAnimationName), true); |
738 | end |
739 | end |
740 | end |
onTurnedOff
DescriptionCalled on turn offDefinition
onTurnedOff(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
745 | function Sprayer:onTurnedOff(noEventSend) |
746 | if self.isClient then |
747 | for _, particleSystems in pairs(self.sprayParticleSystems) do |
748 | for _, particleSystem in pairs(particleSystems) do |
749 | ParticleUtil.setEmittingState(particleSystem, false); |
750 | end |
751 | end |
752 | for _, sprayerEffect in pairs(self.sprayerEffects) do |
753 | EffectManager:stopEffects(sprayerEffect.effects); |
754 | end |
755 | SoundUtil.stopSample(self.sampleSprayer); |
756 | |
757 | if self.sprayingAnimationName ~= "" and self.stopAnimation ~= nil then |
758 | self:stopAnimation(self.sprayingAnimationName, true); |
759 | end |
760 | end |
761 | end |
onAiTurnOn
DescriptionCalled on ai turn onDefinition
onAiTurnOn()Code
765 | function Sprayer:onAiTurnOn() |
766 | if self.setIsTurnedOn ~= nil then |
767 | self:setIsTurnedOn(true, false); |
768 | end |
769 | end |
onAiTurnOff
DescriptionCalled on ai turn offDefinition
onAiTurnOff()Code
773 | function Sprayer:onAiTurnOff() |
774 | if self.setIsTurnedOn ~= nil then |
775 | self:setIsTurnedOn(false, false); |
776 | end |
777 | end |
onAiLower
DescriptionCalled on ai lowerDefinition
onAiLower()Code
781 | function Sprayer:onAiLower() |
782 | if self.setIsTurnedOn ~= nil then |
783 | self:setIsTurnedOn(true, false); |
784 | end |
785 | end |
onAiRaise
DescriptionCalled on ai raiseDefinition
onAiRaise()Code
789 | function Sprayer:onAiRaise() |
790 | if self.setIsTurnedOn ~= nil then |
791 | self:setIsTurnedOn(false, false); |
792 | end |
793 | end |
findAttachedSprayerTank
DescriptionFind attached sprayer tanksDefinition
findAttachedSprayerTank(table currentVehicle, integer fillType, boolean needsTankActivation, boolean ignoreFillLevel)Arguments
table | currentVehicle | current vehicle to check |
integer | fillType | fill types |
boolean | needsTankActivation | found tank must be activated |
boolean | ignoreFillLevel | ignore fill level |
table | foundTank | found tank |
integer | fillType | tank fill type |
803 | function Sprayer.findAttachedSprayerTank(currentVehicle, fillTypes, needsTankActivation, ignoreFillLevel) |
804 | if currentVehicle.isSprayerTank and currentVehicle.getFillLevel ~= nil and currentVehicle.setFillLevel ~= nil then |
805 | if (not needsTankActivation or (currentVehicle.getIsTurnedOn ~= nil and currentVehicle:getIsTurnedOn())) then |
806 | |
807 | local fillUnit = currentVehicle.fillUnits[currentVehicle.sprayer.fillUnitIndex]; |
808 | for fillType,state in pairs(fillTypes) do |
809 | if state and fillUnit.fillTypes[fillType] then |
810 | if (fillUnit.currentFillType == fillType and fillUnit.fillLevel > 0) or ignoreFillLevel then |
811 | return currentVehicle, fillType; |
812 | end |
813 | end |
814 | end |
815 | end |
816 | end |
817 | for _,implement in pairs(currentVehicle.attachedImplements) do |
818 | if implement.object ~= nil then |
819 | local ret1, ret2 = Sprayer.findAttachedSprayerTank(implement.object, fillTypes, needsTankActivation, ignoreFillLevel); |
820 | if ret1 ~= nil and ret2 ~= nil then |
821 | return ret1, ret2; |
822 | end |
823 | end |
824 | end |
825 | return nil; |
826 | end |
loadWorkAreaFromXML
DescriptionLoads work areas from xmlDefinition
loadWorkAreaFromXML(table workArea, integer xmlFile, string key)Arguments
table | workArea | workArea |
integer | xmlFile | id of xml object |
string | key | key |
boolean | success | success |
834 | function Sprayer:loadWorkAreaFromXML(superFunc, workArea, xmlFile, key) |
835 | local retValue = true; |
836 | if superFunc ~= nil then |
837 | retValue = superFunc(self, workArea, xmlFile, key) |
838 | end |
839 | |
840 | if workArea.type == WorkArea.AREATYPE_DEFAULT then |
841 | workArea.type = WorkArea.AREATYPE_SPRAYER; |
842 | end |
843 | |
844 | return retValue; |
845 | end |
getIsReadyToSpray
DescriptionReturns if tool is ready to sprayDefinition
getIsReadyToSpray()Return Values
boolean | isReady | is ready to spray |
850 | function Sprayer:getIsReadyToSpray() |
851 | if self.lastSowingArea ~= nil then |
852 | return self.lastSowingArea > 0; |
853 | end |
854 | |
855 | return true; |
856 | end |
getAreEffectsVisible
DescriptionReturn if effects are visibleDefinition
getAreEffectsVisible()Return Values
boolean | visible | effects are visible |
861 | function Sprayer:getAreEffectsVisible() |
862 | return true; |
863 | end |
getLitersPerSecond
DescriptionReturns liters per second to consumeDefinition
getLitersPerSecond(integer fillType)Arguments
integer | fillType | fill type |
float | literPerSecond | liter per second |
869 | function Sprayer:getLitersPerSecond(fillType) |
870 | |
871 | local scale = Utils.getNoNil(self.sprayUsageScale.fillTypeScales[fillType], self.sprayUsageScale.default) |
872 | local litersPerSecond = 1 |
873 | |
874 | local sprayTypeIndex = Sprayer.fillTypeToSprayType[fillType] |
875 | if sprayTypeIndex ~= nil then |
876 | local spray = Sprayer.sprayTypeIndexToDesc[sprayTypeIndex] |
877 | if spray ~= nil then |
878 | litersPerSecond = spray.litersPerSecond |
879 | end |
880 | end |
881 | |
882 | return scale * litersPerSecond * self.speedLimit * self.sprayUsageScale.workingWidth |
883 | end |
doCheckSpeedLimit
DescriptionReturns if speed limit should be checkedDefinition
doCheckSpeedLimit()Return Values
boolean | checkSpeedlimit | check speed limit |
888 | function Sprayer:doCheckSpeedLimit(superFunc) |
889 | local parent = false; |
890 | if superFunc ~= nil then |
891 | parent = superFunc(self); |
892 | end |
893 | |
894 | return parent or self.isSprayerSpeedLimitActive; |
895 | end |
getDefaultSpeedLimit
DescriptionReturns default speed limitDefinition
getDefaultSpeedLimit()Return Values
float | speedLimit | speed limit |
900 | function Sprayer.getDefaultSpeedLimit() |
901 | return 15; |
902 | end |
processSprayerAreas
DescriptionProcess sprayer areasDefinition
processSprayerAreas(table workAreas, integer filltype)Arguments
table | workAreas | work areas to consume |
integer | filltype | fill type |
float | totalPixels | total pixels changed |
909 | function Sprayer:processSprayerAreas(workAreas, fillType) |
910 | local sprayType = 1; |
911 | if fillType == FillUtil.FILLTYPE_MANURE then |
912 | sprayType = 2; |
913 | end |
914 | local totalPixels = 0; |
915 | local numAreas = table.getn(workAreas); |
916 | for i=1, numAreas do |
917 | local x = workAreas[i][1]; |
918 | local z = workAreas[i][2]; |
919 | local x1 = workAreas[i][3]; |
920 | local z1 = workAreas[i][4]; |
921 | local x2 = workAreas[i][5]; |
922 | local z2 = workAreas[i][6]; |
923 | |
924 | local pixels, pixelsTotal; |
925 | if self.cultivatorGroundContactFlag ~= nil and self.sowingMachineGroundContactFlag == nil then |
926 | pixels, pixelsTotal = Utils.updateSprayArea(x, z, x1, z1, x2, z2, g_currentMission.cultivatorValue, sprayType); |
927 | else |
928 | pixels, pixelsTotal = Utils.updateSprayArea(x, z, x1, z1, x2, z2, nil, sprayType); |
929 | end |
930 | totalPixels = totalPixels + pixels; |
931 | end; |
932 | return totalPixels; |
933 | end; |