LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

ExtendedSprayer

Description
Specialization to control the sprayer usage depending on the soil
Functions

actionEventChangeDefaultFruitRequirement

Description
Definition
actionEventChangeDefaultFruitRequirement()
Code
529function ExtendedSprayer.actionEventChangeDefaultFruitRequirement(self, actionName, inputValue, callbackState, isAnalog)
530 local spec = self.spec_extendedSprayer
531 self:setSprayAmountDefaultFruitRequirementIndex(spec.nitrogenMap:getNextFruitRequirementIndex(spec.nApplyAutoModeFruitRequirementDefaultIndex))
532end

actionEventChangeSprayAmount

Description
Definition
actionEventChangeSprayAmount()
Code
522function ExtendedSprayer.actionEventChangeSprayAmount(self, actionName, inputValue, callbackState, isAnalog)
523 local spec = self.spec_extendedSprayer
524 self:setSprayAmountManualValue(spec.sprayAmountManual + MathUtil.sign(inputValue))
525end

actionEventToggleAuto

Description
Definition
actionEventToggleAuto()
Code
516function ExtendedSprayer.actionEventToggleAuto(self, actionName, inputValue, callbackState, isAnalog)
517 self:setSprayAmountAutoMode()
518end

changeSeedIndex

Description
Definition
changeSeedIndex()
Code
928function ExtendedSprayer:changeSeedIndex(superFunc, ...)
929 superFunc(self, ...)
930
931 -- update nitrogen requirements data in ui without need to move
932 local spec = self.spec_extendedSprayer
933 spec.lastGroundUpdateDistance = math.huge
934end

getCurrentNitrogenLevelOffset

Description
Definition
getCurrentNitrogenLevelOffset()
Code
612function ExtendedSprayer:getCurrentNitrogenLevelOffset(lastChangeLevels)
613 return 0
614end

getCurrentNitrogenUsageLevelOffset

Description
Definition
getCurrentNitrogenUsageLevelOffset()
Code
618function ExtendedSprayer:getCurrentNitrogenUsageLevelOffset(lastChangeLevels)
619 return 0
620end

getCurrentSprayerMode

Description
Definition
getCurrentSprayerMode()
Code
581function ExtendedSprayer:getCurrentSprayerMode()
582 local sprayer, fillUnitIndex = ExtendedSprayer.getFillTypeSourceVehicle(self)
583 local fillType = sprayer:getFillUnitLastValidFillType(fillUnitIndex)
584
585 if fillType == FillType.LIME then
586 return true, false
587 end
588
589 if fillType == FillType.FERTILIZER
590 or fillType == FillType.LIQUIDFERTILIZER
591 or fillType == FillType.MANURE
592 or fillType == FillType.LIQUIDFERTILIZER
593 or fillType == FillType.LIQUIDMANURE
594 or fillType == FillType.DIGESTATE then
595 return false, true
596 end
597
598 if fillType == FillType.HERBICIDE then
599 return false, false
600 end
601
602 -- ai worker will always fertilze by default, if nothing is filled
603 if self:getIsAIActive() then
604 return false, true
605 end
606
607 return false, false
608end

getFillTypeSourceVehicle

Description
Definition
getFillTypeSourceVehicle()
Code
561function ExtendedSprayer.getFillTypeSourceVehicle(sprayer)
562 -- check the valid sprayer if he has a fill type source to consume from, otherwise hide the display
563 local fillUnitIndex = sprayer:getSprayerFillUnitIndex()
564 if sprayer:getFillUnitFillLevel(fillUnitIndex) <= 0 then
565 local spec = sprayer.spec_sprayer
566 for _, supportedSprayType in ipairs(spec.supportedSprayTypes) do
567 for _, src in ipairs(spec.fillTypeSources[supportedSprayType]) do
568 local vehicle = src.vehicle
569 if vehicle:getFillUnitFillType(src.fillUnitIndex) == supportedSprayType and vehicle:getFillUnitFillLevel(src.fillUnitIndex) > 0 then
570 return vehicle, src.fillUnitIndex
571 end
572 end
573 end
574 end
575
576 return sprayer, fillUnitIndex
577end

getIsPrecisionSprayingRequired

Description
Definition
getIsPrecisionSprayingRequired()
Code
650function ExtendedSprayer:getIsPrecisionSprayingRequired()
651 local spec = self.spec_extendedSprayer
652 if spec.isDoingMissionWork then
653 return true
654 end
655
656 if spec.sprayAmountAutoMode then
657 -- use last added values, not the buffered value to avoid delays
658 if spec.isLiming then
659 local pHActual = math.floor(spec.phActualBuffer:getLastAdded())
660 local pHTarget = math.floor(spec.phTargetBuffer:getLastAdded())
661 if pHActual >= pHTarget then
662 return false
663 end
664 elseif spec.isFertilizing then
665 local nActual = math.floor(spec.nActualBuffer:getLastAdded())
666 local nTarget = math.floor(spec.nTargetBuffer:getLastAdded())
667 if nActual >= nTarget then
668 return false
669 end
670 end
671 end
672
673 return true
674end

getIsUsingExactNitrogenAmount

Description
Definition
getIsUsingExactNitrogenAmount()
Code
623function ExtendedSprayer:getIsUsingExactNitrogenAmount()
624 return true
625end

getIsVehicleValid

Description
Definition
getIsVehicleValid()
Code
494function ExtendedSprayer.getIsVehicleValid(vehicle)
495 if not SpecializationUtil.hasSpecialization(ExtendedSprayer, vehicle.specializations) then
496 return false
497 end
498
499 if not SpecializationUtil.hasSpecialization(WorkArea, vehicle.specializations) then
500 return false
501 end
502
503 if #vehicle.spec_workArea.workAreas == 0 then
504 return false
505 end
506
507 if SpecializationUtil.hasSpecialization(ManureBarrel, vehicle.specializations) and vehicle.spec_manureBarrel.attachedTool ~= nil then
508 return false
509 end
510
511 return true
512end

getSprayerDoubledAmountActive

Description
Definition
getSprayerDoubledAmountActive()
Code
938function ExtendedSprayer:getSprayerDoubledAmountActive(superFunc, sprayTypeIndex)
939 -- disable double application rate since we can precisely set the application amount
940 return false, false
941end

getSprayerUsage

Description
Definition
getSprayerUsage()
Code
729function ExtendedSprayer:getSprayerUsage(superFunc, fillType, dt)
730 local usage = superFunc(self, fillType, dt)
731
732 if self:getIsTurnedOn() then
733 local specSpray = self.spec_sprayer
734 local usageScale = specSpray.usageScale
735 local activeSprayType = self:getActiveSprayType()
736 if activeSprayType ~= nil then
737 usageScale = activeSprayType.usageScale
738 end
739
740 local workWidth
741 if usageScale.workAreaIndex ~= nil then
742 workWidth = self:getWorkAreaWidth(usageScale.workAreaIndex)
743 else
744 workWidth = usageScale.workingWidth
745 end
746
747 local lastSpeed = math.max(self:getLastSpeed(), 1) -- don't stop usage while player stops, but sprayer still turned on
748
749 local spec = self.spec_extendedSprayer
750 local minRate = spec.sprayAmountAutoMode and 0 or 1
751 if spec.isLiming then
752 if spec.pHMap ~= nil then
753 local changeValue = math.ceil(spec.phChangeBuffer:get())
754 local litersPerUpdate, literPerHectar, regularUsage = spec.pHMap:getLimeUsage(workWidth, lastSpeed, math.max(changeValue, minRate), dt)
755
756 spec.lastRegularUsage = regularUsage
757 usage = litersPerUpdate
758 spec.lastLitersPerHectar = literPerHectar
759 spec.lastNitrogenProportion = 0
760 end
761 elseif spec.isFertilizing then
762 if spec.nitrogenMap ~= nil then
763 if not spec.isDoingMissionWork then
764 local sprayVehicle = specSpray.workAreaParameters.sprayVehicle
765 if sprayVehicle == nil then
766 sprayVehicle = ExtendedSprayer.getFillTypeSourceVehicle(self)
767 end
768
769 local changeValue = math.ceil(spec.nChangeBuffer:get())
770 local actualNitrogen = spec.nActualBuffer:get()
771 local nitrogenUsageLevelOffset = (sprayVehicle ~= nil and sprayVehicle.getCurrentNitrogenUsageLevelOffset ~= nil) and sprayVehicle:getCurrentNitrogenUsageLevelOffset(spec.nChangeBuffer:get()) or 0
772 local litersPerUpdate, literPerHectar, regularUsage, nitrogenProportion = spec.nitrogenMap:getFertilizerUsage(workWidth, lastSpeed, math.max(changeValue, minRate), fillType, dt, spec.sprayAmountAutoMode, spec.nApplyAutoModeFruitType, actualNitrogen, nitrogenUsageLevelOffset)
773
774 spec.lastRegularUsage = regularUsage
775 usage = litersPerUpdate
776 spec.lastLitersPerHectar = literPerHectar
777 spec.lastNitrogenProportion = nitrogenProportion
778 else
779 -- keep default spray rate for mission work
780 spec.lastRegularUsage = usage
781 spec.lastLitersPerHectar = usage / dt * (10000 / workWidth) / (self.speedLimit / 3600)
782 spec.lastNitrogenProportion = 0
783 end
784 end
785 end
786
787 -- use a min. amount of usage to keep the ai going, otherwise he will not work since the usage is the fillLevel while it's active
788 if self:getIsAIActive() and usage == 0 then
789 usage = 0.0001
790 end
791 end
792
793 return usage
794end

getValidSprayerToUse

Description
Definition
getValidSprayerToUse()
Code
480function ExtendedSprayer.getValidSprayerToUse(self)
481 local vehicleList = self.rootVehicle.childVehicles
482 for i=1, #vehicleList do
483 local subVehicle = vehicleList[i]
484 if ExtendedSprayer.getIsVehicleValid(subVehicle) then
485 return subVehicle
486 end
487 end
488
489 return nil
490end

onChangedFillType

Description
Definition
onChangedFillType()
Code
388function ExtendedSprayer:onChangedFillType(fillUnitIndex, fillTypeIndex, oldFillTypeIndex)
389 local spec = self.spec_extendedSprayer
390 if spec.isSolidFertilizerSprayer and fillTypeIndex == FillType.LIME then
391 local _, _, pHMaxValue = spec.pHMap:getMinMaxValue()
392 spec.sprayAmountManualMax = pHMaxValue - 1
393 spec.isLimingActive = true
394 else
395 local _, _, nMaxValue = spec.nitrogenMap:getMinMaxValue()
396 spec.sprayAmountManualMax = nMaxValue - 1
397 spec.isLimingActive = false
398 end
399end

onEndWorkAreaProcessing

Description
Definition
onEndWorkAreaProcessing()
Code
1036function ExtendedSprayer:onEndWorkAreaProcessing(dt, hasProcessed)
1037 local spec = self.spec_extendedSprayer
1038 local specSprayer = self.spec_sprayer
1039
1040 if self.isServer then
1041 if specSprayer.workAreaParameters.isActive then
1042 local sprayVehicle = specSprayer.workAreaParameters.sprayVehicle
1043 local usage = specSprayer.workAreaParameters.usage
1044 local fillType = specSprayer.workAreaParameters.sprayFillType
1045
1046 if sprayVehicle ~= nil or self:getIsAIActive() then
1047 if self:getIsTurnedOn() then
1048 local usageRegular = spec.lastRegularUsage
1049
1050 local farmlandStatistics, _, farmlandId = self:getPFStatisticInfo()
1051 if farmlandStatistics ~= nil and farmlandId ~= nil then
1052 if fillType == FillType.LIME then
1053 farmlandStatistics:updateStatistic(farmlandId, "usedLime", usage)
1054 farmlandStatistics:updateStatistic(farmlandId, "usedLimeRegular", usageRegular)
1055 elseif fillType == FillType.FERTILIZER then
1056 farmlandStatistics:updateStatistic(farmlandId, "usedMineralFertilizer", usage)
1057 farmlandStatistics:updateStatistic(farmlandId, "usedMineralFertilizerRegular", usageRegular)
1058 elseif fillType == FillType.LIQUIDFERTILIZER then
1059 farmlandStatistics:updateStatistic(farmlandId, "usedLiquidFertilizer", usage)
1060 farmlandStatistics:updateStatistic(farmlandId, "usedLiquidFertilizerRegular", usageRegular)
1061 elseif fillType == FillType.MANURE then
1062 farmlandStatistics:updateStatistic(farmlandId, "usedManure", usage)
1063 farmlandStatistics:updateStatistic(farmlandId, "usedManureRegular", usageRegular)
1064 elseif fillType == FillType.LIQUIDMANURE or fillType == FillType.DIGESTATE then
1065 farmlandStatistics:updateStatistic(farmlandId, "usedLiquidManure", usage)
1066 farmlandStatistics:updateStatistic(farmlandId, "usedLiquidManureRegular", usageRegular)
1067 end
1068 end
1069 end
1070 end
1071 end
1072 end
1073end

onPostLoad

Description
Definition
onPostLoad()
Code
144function ExtendedSprayer:onPostLoad(savegame)
145 if savegame ~= nil and not savegame.resetVehicles then
146 local spec = self.spec_extendedSprayer
147 local specName = ExtendedSprayer.MOD_NAME .. ".extendedSprayer"
148 self:setSprayAmountAutoMode(Utils.getNoNil(savegame.xmlFile:getBool(savegame.key .."." .. specName .. "#sprayAmountAutoMode"), spec.sprayAmountAutoMode), true)
149 self:setSprayAmountManualValue(savegame.xmlFile:getInt(savegame.key .."." .. specName .. "#sprayAmountManual") or spec.sprayAmountManual, true)
150 end
151end

onReadUpdateStream

Description
Definition
onReadUpdateStream()
Code
163function ExtendedSprayer:onReadUpdateStream(streamId, timestamp, connection)
164 if connection:getIsServer() then
165 local spec = self.spec_extendedSprayer
166
167 if streamReadBool(streamId) then
168 spec.phChangeBuffer:readStream(streamId, connection)
169 spec.phActualBuffer:readStream(streamId, connection)
170 spec.phTargetBuffer:readStream(streamId, connection)
171 spec.nChangeBuffer:readStream(streamId, connection)
172 spec.nActualBuffer:readStream(streamId, connection)
173 spec.nTargetBuffer:readStream(streamId, connection)
174
175 spec.lastTouchedSoilType = streamReadUIntN(streamId, 3)
176
177 if streamReadBool(streamId) then
178 self:setSprayAmountAutoFruitTypeIndex(streamReadUIntN(streamId, FruitTypeManager.SEND_NUM_BITS))
179 else
180 self:setSprayAmountAutoFruitTypeIndex(nil)
181 end
182 end
183 end
184end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
445function ExtendedSprayer:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
446 if self.isClient then
447 local spec = self.spec_extendedSprayer
448 self:clearActionEventsTable(spec.actionEvents)
449 spec.pHMap:setRequireMinimapDisplay(false, self)
450 spec.nitrogenMap:setRequireMinimapDisplay(false, self)
451 if isActiveForInputIgnoreSelection then
452 if self == ExtendedSprayer.getValidSprayerToUse(self) then
453 if spec.sprayAmountAutoModeChangeAllowed then
454 local _, actionEventId = self:addActionEvent(spec.actionEvents, spec.inputActionToggleAuto, self, ExtendedSprayer.actionEventToggleAuto, false, true, false, true, nil)
455 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH)
456 end
457
458 local _, actionEventId = self:addActionEvent(spec.actionEvents, spec.inputActionToggleSprayAmount, self, ExtendedSprayer.actionEventChangeSprayAmount, false, true, false, true, nil)
459 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH)
460 g_inputBinding:setActionEventText(actionEventId, spec.texts.toggleSprayAmountAutoManual)
461
462 if self.spec_sowingMachine == nil then
463 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_SEEDS, self, ExtendedSprayer.actionEventChangeDefaultFruitRequirement, false, true, false, true, nil)
464 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH)
465 g_inputBinding:setActionEventText(actionEventId, spec.texts.toggleSprayDefaultFruitRequirement)
466 end
467
468 ExtendedSprayer.updateActionEventState(self)
469 ExtendedSprayer.updateActionEventAutoModeDefault(self)
470 ExtendedSprayer.updateMinimapActiveState(self)
471 end
472 end
473
474 spec.attachStateChanged = true
475 end
476end

onStateChange

Description
Definition
onStateChange()
Code
419function ExtendedSprayer:onStateChange(state, data)
420 local spec = self.spec_extendedSprayer
421
422 if state == Vehicle.STATE_CHANGE_ATTACH or state == Vehicle.STATE_CHANGE_DETACH then
423 spec.attachStateChanged = true
424 end
425end

onTurnedOff

Description
Definition
onTurnedOff()
Code
411function ExtendedSprayer:onTurnedOff()
412 if self.isClient then
413 ExtendedSprayer.updateSprayerEffectState(self, true)
414 end
415end

onTurnedOn

Description
Definition
onTurnedOn()
Code
403function ExtendedSprayer:onTurnedOn()
404 if self.isClient then
405 ExtendedSprayer.updateSprayerEffectState(self, true)
406 end
407end

onUpdate

Description
Definition
onUpdate()
Code
211function ExtendedSprayer:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
212 local spec = self.spec_extendedSprayer
213
214 if self.isServer then
215 if g_time - spec.lastAreaChangeTime > 500 then
216 spec.lastGroundUpdateDistance = spec.lastGroundUpdateDistance + self.lastMovedDistance
217 if spec.lastGroundUpdateDistance > spec.groundUpdateDistance then
218 spec.lastGroundUpdateDistance = 0
219
220 local workArea = self:getWorkAreaByIndex(1)
221 if workArea ~= nil then
222 local x, y, z
223
224 -- if the work area starts in the middle of the vehicle we use the start node, otherwise the middle between start and width
225 local lx, _, _ = localToLocal(workArea.start, self.rootNode, 0, 0, 0)
226 if math.abs(lx) < 0.5 then
227 x, y, z = getWorldTranslation(workArea.start)
228 else
229 local x1, y1, z1 = getWorldTranslation(workArea.start)
230 local x2, y2, z2 = getWorldTranslation(workArea.width)
231 x, y, z = (x1 + x2) * 0.5, (y1 + y2) * 0.5, (z1 + z2) * 0.5
232 end
233
234 local isOnField, _ = FSDensityMapUtil.getFieldDataAtWorldPosition(x, 0, z)
235 if isOnField then
236 local sprayer, fillUnitIndex = ExtendedSprayer.getFillTypeSourceVehicle(self)
237 local fillType = sprayer:getFillUnitLastValidFillType(fillUnitIndex)
238 if fillType == FillType.UNKNOWN then
239 fillType = sprayer:getFillUnitFirstSupportedFillType(fillUnitIndex)
240 end
241
242 if fillType == FillType.LIME then
243 local pHLevel = spec.pHMap:getLevelAtWorldPos(x, z)
244 local pHOptimal = 0
245 local soilTypeIndex = spec.soilMap:getTypeIndexAtWorldPos(x, z)
246 if soilTypeIndex > 0 then
247 pHOptimal = spec.pHMap:getOptimalPHValueForSoilTypeIndex(soilTypeIndex)
248 end
249
250
251 spec.phChangeBuffer:add(0)
252 spec.phActualBuffer:add(pHLevel, true)
253 spec.phTargetBuffer:add(pHOptimal, true)
254 spec.lastTouchedSoilTypeReal = soilTypeIndex
255
256 if spec.lastTouchedSoilType == 0 then
257 spec.lastTouchedSoilType = soilTypeIndex
258 end
259 else
260 local forcedFruitType
261 if self.spec_sowingMachine ~= nil then
262 forcedFruitType = self.spec_sowingMachine.workAreaParameters.seedsFruitType
263 end
264
265 local nLevel = spec.nitrogenMap:getLevelAtWorldPos(x, z)
266 local nTarget, soilTypeIndex, fruitTypeIndex = spec.nitrogenMap:getTargetLevelAtWorldPos(x, z, nil, forcedFruitType, fillType, nLevel, spec.nApplyAutoModeFruitRequirementDefaultIndex)
267
268 spec.nChangeBuffer:add(0)
269 spec.nActualBuffer:add(nLevel, true, true)
270 spec.nTargetBuffer:add(nTarget, true, true)
271
272 self:setSprayAmountAutoFruitTypeIndex(fruitTypeIndex)
273 spec.lastTouchedSoilTypeReal = soilTypeIndex
274
275 if spec.lastTouchedSoilType == 0 then
276 spec.lastTouchedSoilType = soilTypeIndex
277 end
278 end
279 else
280 spec.phChangeBuffer:reset()
281 spec.phActualBuffer:reset()
282 spec.phTargetBuffer:reset()
283
284 spec.nChangeBuffer:reset()
285 spec.nActualBuffer:reset()
286 spec.nTargetBuffer:reset()
287
288 spec.lastTouchedSoilType = 0
289 spec.lastTouchedSoilTypeReal = 0
290 spec.lastLitersPerHectar = 0
291 spec.lastNitrogenProportion = 0
292
293 self:raiseDirtyFlags(spec.usageValuesDirtyFlag)
294 end
295 end
296 else
297 spec.phActualBuffer:add(nil, true)
298 spec.phTargetBuffer:add(nil, true)
299
300 spec.nActualBuffer:add(nil, true)
301 spec.nTargetBuffer:add(nil, true)
302 end
303 elseif self:getIsTurnedOn() then
304 spec.phActualBuffer:add()
305 spec.phTargetBuffer:add()
306
307 spec.nActualBuffer:add()
308 spec.nTargetBuffer:add()
309 spec.lastGroundUpdateDistance = spec.groundUpdateDistance * 0.5
310 else
311 spec.lastGroundUpdateDistance = spec.groundUpdateDistance * 0.5
312 end
313 end
314end

onUpdateTick

Description
Definition
onUpdateTick()
Code
318function ExtendedSprayer:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
319 local spec = self.spec_extendedSprayer
320
321 if self.isServer then
322 spec.phChangeBuffer:update(dt)
323 spec.phActualBuffer:update(dt)
324 spec.phTargetBuffer:update(dt)
325
326 spec.nChangeBuffer:update(dt)
327 spec.nActualBuffer:update(dt)
328 spec.nTargetBuffer:update(dt)
329
330 if spec.phChangeBuffer:getIsDirty()
331 or spec.phActualBuffer:getIsDirty()
332 or spec.phTargetBuffer:getIsDirty()
333 or spec.nChangeBuffer:getIsDirty()
334 or spec.nActualBuffer:getIsDirty()
335 or spec.nTargetBuffer:getIsDirty() then
336 spec.phChangeBuffer:resetDirtyState()
337 spec.phActualBuffer:resetDirtyState()
338 spec.phTargetBuffer:resetDirtyState()
339 spec.nChangeBuffer:resetDirtyState()
340 spec.nActualBuffer:resetDirtyState()
341 spec.nTargetBuffer:resetDirtyState()
342
343 self:raiseDirtyFlags(spec.usageValuesDirtyFlag)
344 end
345
346 -- update last touched soil type only every second to avoid flickering
347 spec.lastTouchedSoilTypeTimer = spec.lastTouchedSoilTypeTimer + dt
348 if spec.lastTouchedSoilTypeTimer > spec.lastTouchedSoilTypeInterval then
349 spec.lastTouchedSoilType = spec.lastTouchedSoilTypeReal
350 spec.lastTouchedSoilTypeTimer = 0
351
352 if spec.lastTouchedSoilTypeSent ~= spec.lastTouchedSoilType then
353 self:raiseDirtyFlags(spec.usageValuesDirtyFlag)
354 spec.lastTouchedSoilTypeSent = spec.lastTouchedSoilType
355 end
356 end
357
358 if spec.nApplyAutoModeFruitType ~= spec.nApplyAutoModeFruitTypeSent then
359 self:raiseDirtyFlags(spec.usageValuesDirtyFlag)
360 spec.nApplyAutoModeFruitTypeSent = spec.nApplyAutoModeFruitType
361 end
362 end
363
364 if self.isClient then
365 if self:getIsTurnedOn() then
366 ExtendedSprayer.updateSprayerEffectState(self)
367 else
368 spec.lastSprayerEffectState = true
369 end
370 end
371
372 spec.isLiming, spec.isFertilizing = self:getCurrentSprayerMode()
373
374 if self:getIsActiveForInput(true, true) then
375 ExtendedSprayer.updateMinimapActiveState(self)
376
377 local _, _, _, _, mission = self:getPFStatisticInfo()
378 local isDoingMissionWork = mission ~= nil or (spec.sprayAmountAutoMode and spec.nApplyAutoModeFruitTypeRequiresDefaultMode)
379 if spec.isDoingMissionWork ~= isDoingMissionWork then
380 spec.isDoingMissionWork = isDoingMissionWork
381 ExtendedSprayer.updateMinimapActiveState(self)
382 end
383 end
384end

onVariableWorkWidthSectionChanged

Description
Definition
onVariableWorkWidthSectionChanged()
Code
429function ExtendedSprayer:onVariableWorkWidthSectionChanged()
430 local vehicles = self.rootVehicle.childVehicles
431 for i=1, #vehicles do
432 local vehicle = vehicles[i]
433 if SpecializationUtil.hasSpecialization(CropSensor, vehicle.specializations) then
434 vehicle:updateCropSensorWorkingWidth()
435 end
436 end
437
438 if self.isClient then
439 ExtendedSprayer.updateSprayerEffectState(self, true)
440 end
441end

onWriteUpdateStream

Description
Definition
onWriteUpdateStream()
Code
188function ExtendedSprayer:onWriteUpdateStream(streamId, connection, dirtyMask)
189 if not connection:getIsServer() then
190 local spec = self.spec_extendedSprayer
191
192 if streamWriteBool(streamId, bitAND(dirtyMask, spec.usageValuesDirtyFlag) ~= 0) then
193 spec.phChangeBuffer:writeStream(streamId, connection)
194 spec.phActualBuffer:writeStream(streamId, connection)
195 spec.phTargetBuffer:writeStream(streamId, connection)
196 spec.nChangeBuffer:writeStream(streamId, connection)
197 spec.nActualBuffer:writeStream(streamId, connection)
198 spec.nTargetBuffer:writeStream(streamId, connection)
199
200 streamWriteUIntN(streamId, spec.lastTouchedSoilType, 3)
201
202 if streamWriteBool(streamId, spec.nApplyAutoModeFruitType ~= nil) then
203 streamWriteUIntN(streamId, spec.nApplyAutoModeFruitType, FruitTypeManager.SEND_NUM_BITS)
204 end
205 end
206 end
207end

postProcessExtUnderRootFertilizerArea

Description
Definition
postProcessExtUnderRootFertilizerArea()
Code
1014function ExtendedSprayer:postProcessExtUnderRootFertilizerArea(workArea, dt)
1015 local specSpray = self.spec_sprayer
1016 local spec = self.spec_extendedSprayer
1017
1018 if self.isServer then
1019 local sx, _, sz = getWorldTranslation(workArea.start)
1020 local wx, _, wz = getWorldTranslation(workArea.width)
1021 local hx, _, hz = getWorldTranslation(workArea.height)
1022
1023 local desc = g_sprayTypeManager:getSprayTypeByIndex(SprayType.FERTILIZER)
1024 if desc ~= nil then
1025 FSDensityMapUtil.setGroundTypeLayerArea(sx, sz, wx, wz, hx, hz, desc.sprayGroundType)
1026 end
1027
1028 if spec.nitrogenMap ~= nil then
1029 spec.nitrogenMap:postUpdateSprayArea(sx, sz, wx, wz, hx, hz, specSpray.workAreaParameters.sprayType, SprayType.FERTILIZER, spec.sprayAmountAutoMode, spec.sprayAmountManual)
1030 end
1031 end
1032end

preProcessExtUnderRootFertilizerArea

Description
Definition
preProcessExtUnderRootFertilizerArea()
Code
950function ExtendedSprayer:preProcessExtUnderRootFertilizerArea(workArea, dt)
951 local specSpray = self.spec_sprayer
952 local spec = self.spec_extendedSprayer
953
954 if self.isServer then
955 local sx, _, sz = getWorldTranslation(workArea.start)
956 local wx, _, wz = getWorldTranslation(workArea.width)
957 local hx, _, hz = getWorldTranslation(workArea.height)
958
959 if spec.nitrogenMap ~= nil then
960 local sprayVehicle = specSpray.workAreaParameters.sprayVehicle
961 if sprayVehicle == nil then
962 sprayVehicle = ExtendedSprayer.getFillTypeSourceVehicle(self)
963 end
964
965 local forcedFruitType
966 if self.spec_sowingMachine ~= nil then
967 forcedFruitType = self.spec_sowingMachine.workAreaParameters.seedsFruitType
968 end
969 local nitrogenLevelOffset = 0
970 if sprayVehicle.getCurrentNitrogenLevelOffset ~= nil then
971 nitrogenLevelOffset = sprayVehicle:getCurrentNitrogenLevelOffset(spec.nChangeBuffer:get())
972 end
973
974 local numPixelsChanged, _, autoSoilTypeIndex, foundLevel, targetLevel, changeLevel = spec.nitrogenMap:updateSprayArea(sx, sz, wx, wz, hx, hz, specSpray.workAreaParameters.sprayType, SprayType.FERTILIZER, spec.sprayAmountAutoMode, spec.sprayAmountManual, forcedFruitType, nitrogenLevelOffset)
975
976 if numPixelsChanged > 0 then
977 -- in manual mode we need to check the target, fruit and soil type manually since the updateSprayArea adds just a fixed value
978 if not spec.sprayAmountAutoMode then
979 local cx, cz = (sx + wx + hx) / 3, (sz + wz + hz) / 3
980
981 local sprayer, fillUnitIndex = ExtendedSprayer.getFillTypeSourceVehicle(self)
982 local fillType = sprayer:getFillUnitLastValidFillType(fillUnitIndex)
983 if fillType == FillType.UNKNOWN then
984 fillType = sprayer:getFillUnitFirstSupportedFillType(fillUnitIndex)
985 end
986
987 local nTarget, soilTypeIndex, _ = spec.nitrogenMap:getTargetLevelAtWorldPos(cx, cz, nil, forcedFruitType, fillType, foundLevel, spec.nApplyAutoModeFruitRequirementDefaultIndex)
988 targetLevel = nTarget
989 autoSoilTypeIndex = soilTypeIndex
990 end
991
992 spec.nChangeBuffer:add(changeLevel)
993 spec.nActualBuffer:add(foundLevel)
994 spec.nTargetBuffer:add(targetLevel)
995
996 self:setSprayAmountAutoFruitTypeIndex(forcedFruitType)
997
998 if autoSoilTypeIndex ~= 0 then
999 spec.lastTouchedSoilTypeReal = autoSoilTypeIndex
1000
1001 if spec.lastTouchedSoilType == 0 then
1002 spec.lastTouchedSoilType = autoSoilTypeIndex
1003 end
1004 end
1005
1006 spec.lastAreaChangeTime = g_time
1007 end
1008 end
1009 end
1010end

prerequisitesPresent

Description
Checks if all prerequisite specializations are loaded
Definition
prerequisitesPresent(table specializations)
Arguments
tablespecializationsspecializations
Return Values
booleanhasPrerequisitetrue if all prerequisite specializations are loaded
Code
22function ExtendedSprayer.prerequisitesPresent(specializations)
23 return SpecializationUtil.hasSpecialization(Sprayer, specializations) and SpecializationUtil.hasSpecialization(PrecisionFarmingStatistic, specializations)
24end

processSprayerArea

Description
Definition
processSprayerArea()
Code
798function ExtendedSprayer:processSprayerArea(superFunc, workArea, dt)
799 local specSpray = self.spec_sprayer
800 local spec = self.spec_extendedSprayer
801
802 if specSpray.workAreaParameters.sprayFillLevel <= 0 then
803 return superFunc(self, workArea, dt)
804 end
805
806 if not spec.isLiming and not spec.isFertilizing then
807 return superFunc(self, workArea, dt)
808 end
809
810 local sx, _, sz = getWorldTranslation(workArea.start)
811 local wx, _, wz = getWorldTranslation(workArea.width)
812 local hx, _, hz = getWorldTranslation(workArea.height)
813
814 if self.isServer then
815 if spec.pHMap ~= nil then
816 local numPixelsChanged, phLevelDifference, phLevelActual, phLevelTarget, soilTypeIndex, _ = spec.pHMap:updateSprayArea(sx, sz, wx, wz, hx, hz, specSpray.workAreaParameters.sprayType, spec.sprayAmountAutoMode, spec.sprayAmountManual)
817
818 if numPixelsChanged > 0 and phLevelDifference > 0 then
819 if not spec.sprayAmountAutoMode then
820 local cx, cz = (sx + wx + hx) / 3, (sz + wz + hz) / 3
821
822 soilTypeIndex = spec.soilMap:getTypeIndexAtWorldPos(cx, cz)
823 if soilTypeIndex > 0 then
824 phLevelTarget = spec.pHMap:getOptimalPHValueForSoilTypeIndex(soilTypeIndex)
825 end
826 end
827
828 spec.phChangeBuffer:add(phLevelDifference)
829 spec.phActualBuffer:add(phLevelActual)
830 spec.phTargetBuffer:add(phLevelTarget)
831 spec.lastTouchedSoilTypeReal = soilTypeIndex
832
833 if spec.lastTouchedSoilType == 0 then
834 spec.lastTouchedSoilType = soilTypeIndex
835 end
836
837 spec.lastAreaChangeTime = g_time
838 end
839 end
840
841 if spec.nitrogenMap ~= nil then
842 local sprayVehicle = specSpray.workAreaParameters.sprayVehicle
843 if sprayVehicle == nil then
844 sprayVehicle = ExtendedSprayer.getFillTypeSourceVehicle(self)
845 end
846 local nitrogenLevelOffset = 0
847 if sprayVehicle.getCurrentNitrogenLevelOffset ~= nil then
848 nitrogenLevelOffset = sprayVehicle:getCurrentNitrogenLevelOffset(spec.nChangeBuffer:get())
849 end
850 local defaultNitrogenRequirementIndex = spec.nApplyAutoModeFruitRequirementDefaultIndex
851
852 local numPixelsChanged, autoFruitTypeIndex, autoSoilTypeIndex, foundLevel, targetLevel, changeLevel, _ = spec.nitrogenMap:updateSprayArea(sx, sz, wx, wz, hx, hz, specSpray.workAreaParameters.sprayType, specSpray.workAreaParameters.sprayType, spec.sprayAmountAutoMode, spec.sprayAmountManual, nil, nitrogenLevelOffset, defaultNitrogenRequirementIndex)
853
854 if numPixelsChanged > 0 then
855 -- in manual mode we need to check the target, fruit and soil type manually since the updateSprayArea adds just a fixed value
856 if not spec.sprayAmountAutoMode then
857 local cx, cz = (sx + wx + hx) / 3, (sz + wz + hz) / 3
858
859 if autoFruitTypeIndex == FruitType.UNKNOWN or autoSoilTypeIndex == 0 then
860 local nTarget, soilTypeIndex, fruitTypeIndex = spec.nitrogenMap:getTargetLevelAtWorldPos(cx, cz, nil, nil, nil, nil, spec.nApplyAutoModeFruitRequirementDefaultIndex)
861
862 targetLevel = nTarget
863 autoSoilTypeIndex = soilTypeIndex
864 autoFruitTypeIndex = fruitTypeIndex
865 end
866 end
867
868 spec.nChangeBuffer:add(changeLevel)
869 spec.nActualBuffer:add(foundLevel)
870 spec.nTargetBuffer:add(targetLevel)
871
872 self:setSprayAmountAutoFruitTypeIndex(autoFruitTypeIndex)
873
874 if autoSoilTypeIndex ~= 0 then
875 spec.lastTouchedSoilTypeReal = autoSoilTypeIndex
876
877 if spec.lastTouchedSoilType == 0 then
878 spec.lastTouchedSoilType = autoSoilTypeIndex
879 end
880 end
881
882 spec.lastAreaChangeTime = g_time
883 end
884 end
885
886 local changedArea, totalArea = 0, 0
887 if self:getIsPrecisionSprayingRequired() then
888 changedArea, totalArea = superFunc(self, workArea, dt)
889
890 -- set ground type independent on spray level since we are using it as lock bit
891 local desc = g_sprayTypeManager:getSprayTypeByIndex(specSpray.workAreaParameters.sprayType)
892 if desc ~= nil then
893 FSDensityMapUtil.setGroundTypeLayerArea(sx, sz, wx, wz, hx, hz, desc.sprayGroundType)
894 end
895
896 if spec.isDoingMissionWork and changedArea > 0 then
897 spec.nitrogenMap:setMinimapRequiresUpdate(true)
898 end
899 end
900
901 if spec.pHMap ~= nil then
902 spec.pHMap:postUpdateSprayArea(sx, sz, wx, wz, hx, hz, specSpray.workAreaParameters.sprayType, specSpray.workAreaParameters.sprayType, spec.sprayAmountAutoMode, spec.sprayAmountManual)
903 end
904
905 if spec.nitrogenMap ~= nil then
906 spec.nitrogenMap:postUpdateSprayArea(sx, sz, wx, wz, hx, hz, specSpray.workAreaParameters.sprayType, specSpray.workAreaParameters.sprayType, spec.sprayAmountAutoMode, spec.sprayAmountManual)
907 end
908
909 return changedArea, totalArea
910 else
911 local changedArea, totalArea = 0, 0
912 if self:getIsPrecisionSprayingRequired() then
913 changedArea, totalArea = superFunc(self, workArea, dt)
914
915 -- set ground type independent on spray level since we are using it as lock bit
916 local desc = g_sprayTypeManager:getSprayTypeByIndex(specSpray.workAreaParameters.sprayType)
917 if desc ~= nil then
918 FSDensityMapUtil.setGroundTypeLayerArea(sx, sz, wx, wz, hx, hz, desc.sprayGroundType)
919 end
920 end
921
922 return changedArea, totalArea
923 end
924end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
155function ExtendedSprayer:saveToXMLFile(xmlFile, key, usedModNames)
156 local spec = self.spec_extendedSprayer
157 xmlFile:setBool(key.."#sprayAmountAutoMode", spec.sprayAmountAutoMode)
158 xmlFile:setInt(key.."#sprayAmountManual", spec.sprayAmountManual)
159end

setSprayAmountAutoFruitTypeIndex

Description
Definition
setSprayAmountAutoFruitTypeIndex()
Code
1107function ExtendedSprayer:setSprayAmountAutoFruitTypeIndex(index)
1108 local spec = self.spec_extendedSprayer
1109
1110 if index ~= spec.nApplyAutoModeFruitType then
1111 spec.nApplyAutoModeFruitType = index
1112 spec.nApplyAutoModeFruitTypeRequiresDefaultMode = spec.nitrogenMap:getFruitTypeRequirementRequiresDefaultMode(index)
1113 ExtendedSprayer.updateActionEventAutoModeDefault(self)
1114 end
1115end

setSprayAmountAutoMode

Description
Definition
setSprayAmountAutoMode()
Code
1077function ExtendedSprayer:setSprayAmountAutoMode(state, noEventSend)
1078 local spec = self.spec_extendedSprayer
1079 if state == nil then
1080 state = not spec.sprayAmountAutoMode
1081 end
1082
1083 if not spec.sprayAmountAutoModeChangeAllowed then
1084 state = false
1085 end
1086
1087 spec.sprayAmountAutoMode = state
1088
1089 ExtendedSprayer.updateActionEventState(self)
1090 ExtendedSprayer.updateActionEventAutoModeDefault(self)
1091 ExtendedSprayerAmountEvent.sendEvent(self, spec.sprayAmountAutoMode, spec.sprayAmountManual, noEventSend)
1092end

setSprayAmountDefaultFruitRequirementIndex

Description
Definition
setSprayAmountDefaultFruitRequirementIndex()
Code
1119function ExtendedSprayer:setSprayAmountDefaultFruitRequirementIndex(index, noEventSend)
1120 local spec = self.spec_extendedSprayer
1121
1122 spec.nApplyAutoModeFruitRequirementDefaultIndex = index
1123 spec.lastGroundUpdateDistance = math.huge -- force update of values
1124
1125 ExtendedSprayerDefaultFruitTypeEvent.sendEvent(self, index, noEventSend)
1126end

setSprayAmountManualValue

Description
Definition
setSprayAmountManualValue()
Code
1096function ExtendedSprayer:setSprayAmountManualValue(value, noEventSend)
1097 local spec = self.spec_extendedSprayer
1098
1099 spec.sprayAmountManual = MathUtil.clamp(value, spec.sprayAmountManualMin, spec.sprayAmountManualMax)
1100
1101 ExtendedSprayer.updateActionEventState(self)
1102 ExtendedSprayerAmountEvent.sendEvent(self, spec.sprayAmountAutoMode, spec.sprayAmountManual, noEventSend)
1103end

updateActionEventAutoModeDefault

Description
Definition
updateActionEventAutoModeDefault()
Code
551function ExtendedSprayer.updateActionEventAutoModeDefault(self)
552 local spec = self.spec_extendedSprayer
553 local actionEvent = spec.actionEvents[InputAction.TOGGLE_SEEDS]
554 if actionEvent ~= nil then
555 g_inputBinding:setActionEventActive(actionEvent.actionEventId, spec.sprayAmountAutoMode and (spec.nApplyAutoModeFruitType == nil or spec.nApplyAutoModeFruitType == FruitType.UNKNOWN))
556 end
557end

updateActionEventState

Description
Definition
updateActionEventState()
Code
536function ExtendedSprayer.updateActionEventState(self)
537 local spec = self.spec_extendedSprayer
538 local actionEventToggleAuto = spec.actionEvents[spec.inputActionToggleAuto]
539 if actionEventToggleAuto ~= nil then
540 g_inputBinding:setActionEventText(actionEventToggleAuto.actionEventId, spec.sprayAmountAutoMode and spec.texts.toggleSprayAmountAutoModeNeg or spec.texts.toggleSprayAmountAutoModePos)
541 end
542
543 local actionEventToggleSprayAmount = spec.actionEvents[spec.inputActionToggleSprayAmount]
544 if actionEventToggleSprayAmount ~= nil then
545 g_inputBinding:setActionEventActive(actionEventToggleSprayAmount.actionEventId, not spec.sprayAmountAutoMode)
546 end
547end

updateMinimapActiveState

Description
Definition
updateMinimapActiveState()
Code
629function ExtendedSprayer.updateMinimapActiveState(self)
630 local spec = self.spec_extendedSprayer
631
632 local _, _, _, isOnField = self:getPFStatisticInfo()
633 local isActive = isOnField
634 if isActive then
635 local sprayer, fillUnitIndex = ExtendedSprayer.getFillTypeSourceVehicle(self)
636 isActive = isActive and (sprayer:getFillUnitFillLevel(fillUnitIndex) > 0 or self:getIsAIActive())
637 end
638
639 isActive = isActive and (spec.isLiming or spec.isFertilizing)
640 if spec.isLiming then
641 spec.pHMap:setRequireMinimapDisplay(isActive, self, self:getIsSelected())
642 elseif spec.isFertilizing then
643 spec.nitrogenMap:setRequireMinimapDisplay(isActive, self, self:getIsSelected())
644 spec.nitrogenMap:setMinimapMissionState(spec.isDoingMissionWork)
645 end
646end

updateSprayerEffects

Description
Definition
updateSprayerEffects()
Code
945function ExtendedSprayer:updateSprayerEffects(superFunc, force)
946end

updateSprayerEffectState

Description
Definition
updateSprayerEffectState()
Code
678function ExtendedSprayer.updateSprayerEffectState(self, force)
679 local spec = self.spec_extendedSprayer
680
681 local effectState = self:getIsPrecisionSprayingRequired() and self:getAreEffectsVisible() and self:getIsTurnedOn()
682 if spec.lastSprayerEffectState ~= effectState or force then
683 local specSprayer = self.spec_sprayer
684 local sprayType = self:getActiveSprayType()
685 if effectState then
686 local fillType = self:getFillUnitLastValidFillType(self:getSprayerFillUnitIndex())
687 if fillType == FillType.UNKNOWN then
688 fillType = self:getFillUnitFirstSupportedFillType(self:getSprayerFillUnitIndex())
689 end
690
691 g_effectManager:setFillType(specSprayer.effects, fillType)
692 g_effectManager:startEffects(specSprayer.effects)
693
694 g_soundManager:playSample(specSprayer.samples.spray)
695
696 if sprayType ~= nil then
697 g_effectManager:setFillType(sprayType.effects, fillType)
698 g_effectManager:startEffects(sprayType.effects)
699
700 g_animationManager:startAnimations(sprayType.animationNodes)
701
702 g_soundManager:playSample(sprayType.samples.spray)
703 end
704
705 g_animationManager:startAnimations(specSprayer.animationNodes)
706 else
707 g_effectManager:stopEffects(specSprayer.effects)
708
709 g_soundManager:stopSample(specSprayer.samples.spray)
710
711 -- deactivate effects on all spray types (the spray type has may changed during activation)
712 for _, _sprayType in ipairs(specSprayer.sprayTypes) do
713 g_effectManager:stopEffects(_sprayType.effects)
714
715 g_animationManager:stopAnimations(_sprayType.animationNodes)
716
717 g_soundManager:stopSample(_sprayType.samples.spray)
718 end
719
720 g_animationManager:stopAnimations(specSprayer.animationNodes)
721 end
722
723 spec.lastSprayerEffectState = effectState
724 end
725end