LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

TreePlanter

Description
Specialization for tree planters providing possibility to pick up seedling pallets and create trees
Functions

actionEventToggleTreePlanterFieldLimitation

Description
Definition
actionEventToggleTreePlanterFieldLimitation()
Code
883function TreePlanter.actionEventToggleTreePlanterFieldLimitation(self, actionName, inputValue, callbackState, isAnalog)
884 self:setPlantLimitToField(not self.spec_treePlanter.limitToField)
885end

addNodeObjectMapping

Description
Definition
addNodeObjectMapping()
Code
816function TreePlanter:addNodeObjectMapping(superFunc, list)
817 superFunc(self, list)
818
819 local spec = self.spec_treePlanter
820 if spec.palletTrigger ~= nil then
821 list[spec.palletTrigger] = self
822 end
823end

createTree

Description
Create tree on current position
Definition
createTree()
Code
656function TreePlanter:createTree()
657 local spec = self.spec_treePlanter
658
659 if not g_treePlantManager:canPlantTree() then
660 spec.showTooManyTreesWarning = true
661 return
662 end
663
664 if self.isServer and spec.mountedSaplingPallet ~= nil then
665 local pallet = spec.mountedSaplingPallet
666 local x,y,z = getWorldTranslation(spec.node)
667 local yRot = math.random() * 2*math.pi
668
669 local fillType = pallet:getFillUnitFillType(1)
670 local treeTypeIndex = 1
671 if fillType == FillType.TREESAPLINGS then
672 local treeTypeName = getUserAttribute(pallet.rootNode, "treeType")
673 if treeTypeName ~= nil then
674 local desc = g_treePlantManager:getTreeTypeDescFromName(treeTypeName)
675 if desc ~= nil then
676 treeTypeIndex = desc.index
677 end
678 end
679 end
680
681 g_treePlantManager:plantTree(treeTypeIndex, x, y, z, 0, yRot, 0, 0)
682 spec.lastTreePos = {x,y,z}
683
684 local stats = g_farmManager:getFarmById(self:getActiveFarm()).stats
685
686 if g_currentMission.missionInfo.helperBuySeeds and self:getIsAIActive() then
687 local storeItem = g_storeManager:getItemByXMLFilename(pallet.configFileName)
688 local pricePerSapling = 1.5 * (storeItem.price / pallet:getFillUnitCapacity(1))
689
690 stats:updateStats("expenses", pricePerSapling)
691 g_currentMission:addMoney(-pricePerSapling, self:getActiveFarm(), MoneyType.PURCHASE_SEEDS)
692 else
693 -- use 0.9999 instead of 1 to compansate float precision on mp sync
694 local fillLevelChange = -0.9999
695 if self:getFillUnitFillLevel(spec.fillUnitIndex) < 1.5 then
696 fillLevelChange = -math.huge
697 end
698
699 self:addFillUnitFillLevel(self:getOwnerFarmId(), spec.fillUnitIndex, fillLevelChange, self:getFillUnitFillType(spec.fillUnitIndex), ToolType.UNDEFINED)
700 end
701
702 -- increase tree plant counter for achievements
703 stats:updateStats("plantedTreeCount", 1)
704 end
705end

doCheckSpeedLimit

Description
Returns if speed limit should be checked
Definition
doCheckSpeedLimit()
Return Values
booleancheckSpeedlimitcheck speed limit
Code
778function TreePlanter:doCheckSpeedLimit(superFunc)
779 return superFunc(self) or (self:getIsTurnedOn() and self:getIsImplementChainLowered())
780end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
784function TreePlanter:getCanBeSelected(superFunc)
785 return true
786end

getDefaultSpeedLimit

Description
Returns default speed limit
Definition
getDefaultSpeedLimit()
Return Values
floatspeedLimitspeed limit
Code
890function TreePlanter.getDefaultSpeedLimit()
891 return 5
892end

getDirtMultiplier

Description
Returns current dirt multiplier
Definition
getDirtMultiplier()
Return Values
floatdirtMultipliercurrent dirt multiplier
Code
721function TreePlanter:getDirtMultiplier(superFunc)
722 local multiplier = superFunc(self)
723
724 local spec = self.spec_treePlanter
725 if spec.hasGroundContact then
726 multiplier = multiplier + self:getWorkDirtMultiplier() * self:getLastSpeed() / self.speedLimit
727 end
728
729 return multiplier
730end

getIsOnField

Description
Definition
getIsOnField()
Code
801function TreePlanter:getIsOnField(superFunc)
802 if superFunc(self) then
803 return true
804 end
805
806 -- since we don't need to be on a field to work we check only for ground contract
807 if self.spec_treePlanter.hasGroundContact then
808 return true
809 end
810
811 return false
812end

getIsSpeedRotatingPartActive

Description
Returns true if speed rotating part is active
Definition
getIsSpeedRotatingPartActive(table speedRotatingPart)
Arguments
tablespeedRotatingPartspeedRotatingPart
Return Values
booleanisActivespeed rotating part is active
Code
750function TreePlanter:getIsSpeedRotatingPartActive(superFunc, speedRotatingPart)
751 local spec = self.spec_treePlanter
752
753 if not spec.hasGroundContact then
754 return false
755 end
756
757 return superFunc(self, speedRotatingPart)
758end

getIsWorkAreaActive

Description
Definition
getIsWorkAreaActive()
Code
762function TreePlanter:getIsWorkAreaActive(superFunc, workArea)
763 local spec = self.spec_treePlanter
764
765 local isActive = superFunc(self, workArea)
766 if workArea.groundReferenceNode == spec.groundReferenceNode then
767 if not self:getIsTurnedOn() then
768 isActive = false
769 end
770 end
771
772 return isActive
773end

getSaplingPalletInRange

Description
Returns nearest sapling pallet in range
Definition
getSaplingPalletInRange(integer refNode)
Arguments
integerrefNodeid of reference node
Return Values
tableobjectobject of sapling pallet
Code
898function TreePlanter.getSaplingPalletInRange(self, refNode, palletsInTrigger)
899 local spec = self.spec_treePlanter
900
901 local nearestDistance = spec.nearestPalletDistance
902 local nearestSaplingPallet = nil
903
904 for object, state in pairs(palletsInTrigger) do
905 if state ~= nil and state > 0 then
906
907 if object ~= spec.mountedSaplingPallet then
908
909 local distance = calcDistanceFrom(refNode, object.rootNode)
910 if distance < nearestDistance then
911 local validPallet = false
912
913 local fillUnits = object:getFillUnits()
914 for fillUnitIndex, _ in pairs(fillUnits) do
915 local filltype = object:getFillUnitFillType(fillUnitIndex)
916 if filltype ~= FillType.UNKNOWN then
917 if self:getFillUnitSupportsFillType(spec.fillUnitIndex, filltype) then
918 if object:getFillUnitFillLevel(fillUnitIndex) > 0 then
919 validPallet = true
920 break
921 end
922 end
923 end
924 end
925
926 if validPallet then
927 nearestSaplingPallet = object
928 end
929 end
930
931 end
932 end
933 end
934 return nearestSaplingPallet
935end

getWearMultiplier

Description
Returns current wear multiplier
Definition
getWearMultiplier()
Return Values
floatdirtMultipliercurrent wear multiplier
Code
735function TreePlanter:getWearMultiplier(superFunc)
736 local multiplier = superFunc(self)
737
738 local spec = self.spec_treePlanter
739 if spec.hasGroundContact then
740 multiplier = multiplier + self:getWorkWearMultiplier() * self:getLastSpeed() / self.speedLimit
741 end
742
743 return multiplier
744end

loadPallet

Description
Called on loading
Definition
loadPallet(table savegame)
Arguments
tablesavegamesavegame
Code
710function TreePlanter:loadPallet(palletObjectId, noEventSend)
711 local spec = self.spec_treePlanter
712
713 TreePlanterLoadPalletEvent.sendEvent(self, palletObjectId, noEventSend)
714
715 spec.palletIdToMount = palletObjectId
716end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
155function TreePlanter:onDelete()
156 local spec = self.spec_treePlanter
157
158 if self.isClient then
159 g_soundManager:deleteSamples(spec.samples)
160 g_animationManager:deleteAnimations(spec.animationNodes)
161
162 if spec.activatable ~= nil then
163 g_currentMission:removeActivatableObject(spec.activatable)
164 end
165 end
166
167 if spec.mountedSaplingPallet ~= nil then
168 spec.mountedSaplingPallet:unmount()
169 spec.mountedSaplingPallet = nil
170 end
171
172 if spec.palletTrigger ~= nil then
173 removeTrigger(spec.palletTrigger)
174 end
175end

onDeleteTreePlanterObject

Description
Definition
onDeleteTreePlanterObject()
Code
790function TreePlanter:onDeleteTreePlanterObject(object)
791 local spec = self.spec_treePlanter
792 if spec.mountedSaplingPallet == object then
793 spec.mountedSaplingPallet = nil
794 end
795
796 spec.palletsInTrigger[object] = nil
797end

onDraw

Description
Called on draw
Definition
onDraw(boolean isActiveForInput, boolean isSelected)
Arguments
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
495function TreePlanter:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
496 local spec = self.spec_treePlanter
497
498 if isActiveForInputIgnoreSelection then
499 if self:getFillUnitFillLevel(spec.fillUnitIndex) <= 0 then
500 g_currentMission:addExtraPrintText(g_i18n:getText("info_firstFillTheTool"))
501 end
502 end
503
504 if spec.showFieldNotOwnedWarning then
505 g_currentMission:showBlinkingWarning(g_i18n:getText("warning_youDontHaveAccessToThisLand"))
506 end
507
508 if spec.showRestrictedZoneWarning then
509 g_currentMission:showBlinkingWarning(g_i18n:getText("warning_actionNotAllowedHere"))
510 end
511
512 if spec.showTooManyTreesWarning then
513 g_currentMission:showBlinkingWarning(g_i18n:getText("warning_tooManyTrees"))
514 end
515end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
80function TreePlanter:onLoad(savegame)
81 local spec = self.spec_treePlanter
82
83 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.treePlanterSound", "vehicle.treePlanter.sounds.work") --FS17 to FS19
84 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.turnedOnRotationNodes.turnedOnRotationNode(0)", "vehicle.treePlanter.animationNodes.animationNode") --FS17 to FS19
85
86 local baseKey = "vehicle.treePlanter"
87
88 if self.isClient then
89 spec.samples = {}
90 spec.samples.work = g_soundManager:loadSampleFromXML(self.xmlFile, baseKey..".sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
91 spec.isWorkSamplePlaying = false
92
93 spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, baseKey..".animationNodes", self.components, self, self.i3dMappings)
94 end
95
96 spec.node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, baseKey.."#node"), self.i3dMappings)
97 spec.minDistance = Utils.getNoNil(getXMLFloat(self.xmlFile, baseKey.."#minDistance"), 20) -- distance to next tree
98
99 spec.palletTrigger = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, baseKey.."#palletTrigger"), self.i3dMappings)
100 if spec.palletTrigger ~= nil then
101 addTrigger(spec.palletTrigger, "palletTriggerCallback", self)
102 else
103 g_logManager:xmlWarning(self.configFileName, "TreePlanter requires a palletTrigger!")
104 end
105 spec.palletsInTrigger = {}
106
107 local refNodeIndex = Utils.getNoNil(getXMLInt(self.xmlFile, baseKey.."#refNodeIndex"), 1)
108 spec.groundReferenceNode = self:getGroundReferenceNodeFromIndex(refNodeIndex)
109 if spec.groundReferenceNode == nil then
110 g_logManager:xmlWarning(self.configFileName, "No groundReferenceNode specified or invalid groundReferenceNode index in '%s'", baseKey.."#refNodeIndex")
111 end
112
113 spec.activatable = TreePlanterActivatable:new(self)
114
115 spec.saplingPalletGrabNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, baseKey.."#saplingPalletGrabNode"), self.i3dMappings), self.rootNode)
116 spec.saplingPalletMountNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, baseKey.."#saplingPalletMountNode"), self.i3dMappings), self.rootNode)
117 spec.mountedSaplingPallet = nil
118
119 spec.fillUnitIndex = Utils.getNoNil(getXMLInt(self.xmlFile, baseKey.."#fillUnitIndex"), 1)
120 spec.nearestPalletDistance = Utils.getNoNil(getXMLInt(self.xmlFile, baseKey.."#palletMountingRange"), 6.0)
121
122 spec.currentTree = 1
123 spec.lastTreePos = nil
124
125 spec.showFieldNotOwnedWarning = false
126 spec.showRestrictedZoneWarning = false
127 spec.showTooManyTreesWarning = false
128 spec.hasGroundContact = false
129
130 spec.limitToField = true
131 spec.forceLimitToField = false
132
133 -- attributes for AI
134 if self.addAITerrainDetailRequiredRange ~= nil then
135 self:addAITerrainDetailRequiredRange(g_currentMission.cultivatorValue, g_currentMission.cultivatorValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels)
136 self:addAITerrainDetailRequiredRange(g_currentMission.plowValue, g_currentMission.plowValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels)
137 self:addAITerrainDetailRequiredRange(g_currentMission.sowingValue, g_currentMission.sowingValue, g_currentMission.terrainDetailTypeFirstChannel, g_currentMission.terrainDetailTypeNumChannels)
138 end
139
140 if self.setAIFruitProhibitions ~= nil then
141 self:setAIFruitProhibitions(FruitType.POPLAR, 1, 5)
142 end
143
144 spec.dirtyFlag = self:getNextDirtyFlag()
145
146 if savegame ~= nil and not savegame.resetVehicles then
147 spec.lastTreePos = StringUtil.getVectorNFromString(getXMLString(savegame.xmlFile, savegame.key..".treePlanter#lastTreePos"), 3)
148
149 spec.palletHadBeenMounted = getXMLBool(savegame.xmlFile, savegame.key .. ".treePlanter#palletHadBeenMounted")
150 end
151end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
207function TreePlanter:onReadStream(streamId, connection)
208 if streamReadBool(streamId) then
209 local spec = self.spec_treePlanter
210 spec.palletIdToMount = NetworkUtil.readNodeObjectId(streamId)
211 end
212end

onReadUpdateStream

Description
Called on on update
Definition
onReadUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
232function TreePlanter:onReadUpdateStream(streamId, timestamp, connection)
233 if connection:getIsServer() then
234 local spec = self.spec_treePlanter
235 if streamReadBool(streamId) then
236 spec.hasGroundContact = streamReadBool(streamId)
237 spec.showFieldNotOwnedWarning = streamReadBool(streamId)
238 spec.showRestrictedZoneWarning = streamReadBool(streamId)
239 end
240 end
241end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
869function TreePlanter:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
870 if self.isClient then
871 local spec = self.spec_treePlanter
872 self:clearActionEventsTable(spec.actionEvents)
873
874 if isActiveForInputIgnoreSelection and not spec.forceLimitToField then
875 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.IMPLEMENT_EXTRA3, self, TreePlanter.actionEventToggleTreePlanterFieldLimitation, false, true, false, true, nil)
876 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL)
877 end
878 end
879end

onTurnedOff

Description
Called on turn off
Definition
onTurnedOff(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
530function TreePlanter:onTurnedOff()
531 if self.isClient then
532 local spec = self.spec_treePlanter
533 g_animationManager:stopAnimations(spec.animationNodes)
534 g_soundManager:stopSamples(spec.samples)
535 spec.isWorkSamplePlaying = false
536 end
537end

onTurnedOn

Description
Called on turn off
Definition
onTurnedOn(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
520function TreePlanter:onTurnedOn()
521 if self.isClient then
522 local spec = self.spec_treePlanter
523 g_animationManager:startAnimations(spec.animationNodes)
524 end
525end

onUpdate

Description
Called on update
Definition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
264function TreePlanter:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
265 local spec = self.spec_treePlanter
266
267 if self.firstTimeRun then
268 local pallet
269 if spec.palletIdToMount ~= nil then
270 pallet = NetworkUtil.getObject(spec.palletIdToMount)
271 elseif spec.palletHadBeenMounted then
272 spec.palletHadBeenMounted = nil
273 pallet = TreePlanter.getSaplingPalletInRange(self, spec.saplingPalletMountNode, spec.palletsInTrigger)
274 end
275
276 if pallet ~= nil then
277 pallet:mount(self, spec.saplingPalletMountNode, 0,0,0, 0,0,0)
278 spec.mountedSaplingPallet = pallet
279 g_currentMission:removeActivatableObject(spec.activatable)
280 spec.palletIdToMount = nil
281 end
282 end
283
284 if self.isClient then
285 local nearestSaplingPallet = nil
286 if spec.mountedSaplingPallet == nil then
287 nearestSaplingPallet = TreePlanter.getSaplingPalletInRange(self, spec.saplingPalletGrabNode, spec.palletsInTrigger)
288 end
289
290 if spec.nearestSaplingPallet ~= nearestSaplingPallet then
291 spec.nearestSaplingPallet = nearestSaplingPallet
292
293 if nearestSaplingPallet ~= nil then
294 g_currentMission:addActivatableObject(spec.activatable)
295 else
296 g_currentMission:removeActivatableObject(spec.activatable)
297 end
298 end
299 end
300
301 if spec.mountedSaplingPallet ~= nil then
302 if spec.mountedSaplingPallet.isDeleted then
303 spec.palletsInTrigger[spec.mountedSaplingPallet] = nil
304 spec.mountedSaplingPallet = nil
305 else
306 spec.mountedSaplingPallet:raiseActive()
307 end
308 end
309end

onUpdateTick

Description
Called on update tick
Definition
onUpdateTick(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
316function TreePlanter:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
317 local spec = self.spec_treePlanter
318
319 spec.showTooManyTreesWarning = false
320 local showFieldNotOwnedWarning = false
321 local showRestrictedZoneWarning = false
322
323 if self.isServer then
324 local hasGroundContact = false
325 if spec.groundReferenceNode ~= nil then
326 hasGroundContact = self:getIsGroundReferenceNodeActive(spec.groundReferenceNode)
327 end
328
329 if spec.hasGroundContact ~= hasGroundContact then
330 self:raiseDirtyFlags(spec.dirtyFlag)
331 spec.hasGroundContact = hasGroundContact
332 end
333 end
334
335 if self:getIsAIActive() then
336 if not g_currentMission.missionInfo.helperBuySeeds then
337 if spec.mountedSaplingPallet == nil then
338 local rootVehicle = self:getRootVehicle()
339 rootVehicle:stopAIVehicle(AIVehicle.STOP_REASON_OUT_OF_FILL)
340 end
341 end
342 end
343
344 if spec.hasGroundContact then
345 if self:getIsTurnedOn() then
346 if self.isServer then
347 local fillLevel = self:getFillUnitFillLevel(spec.fillUnitIndex)
348 local fillType = self:getFillUnitFillType(spec.fillUnitIndex)
349
350 if g_currentMission.missionInfo.helperBuySeeds then
351 if self:getIsAIActive() then
352 if spec.mountedSaplingPallet ~= nil then
353 fillType = spec.mountedSaplingPallet:getFillUnitFillType(1)
354 else
355 fillType = FillType.POPLAR
356 end
357 end
358 end
359
360 if fillLevel == 0 and (not self:getIsAIActive() or not g_currentMission.missionInfo.helperBuySeeds) then
361 fillType = FillType.UNKNOWN
362 end
363
364 if fillType == FillType.TREESAPLINGS then
365 if self:getLastSpeed() > 1 then
366 local x,y,z = getWorldTranslation(spec.node)
367 if g_currentMission.accessHandler:canFarmAccessLand(self:getActiveFarm(), x, z) then
368 if not PlacementUtil.isInsideRestrictedZone(g_currentMission.restrictedZones, nil, x, y, z) then
369 if y > g_currentMission.waterY then
370 if spec.lastTreePos ~= nil then
371 local distance = MathUtil.vector3Length(x-spec.lastTreePos[1], y-spec.lastTreePos[2], z-spec.lastTreePos[3])
372 if distance > spec.minDistance then
373 self:createTree()
374 end
375 else
376 self:createTree()
377 end
378 end
379 else
380 showRestrictedZoneWarning = true
381 end
382 else
383 showFieldNotOwnedWarning = true
384 end
385 end
386 elseif fillType ~= FillType.UNKNOWN then
387 local x,_,z = getWorldTranslation(spec.node)
388 if g_currentMission.accessHandler:canFarmAccessLand(self:getActiveFarm(), x, z) then
389 local width = math.sqrt( g_currentMission:getFruitPixelsToSqm() ) * 0.5
390
391 local sx,_,sz = localToWorld(spec.node, -width,0,width)
392 local wx,_,wz = localToWorld(spec.node, width,0,width)
393 local hx,_,hz = localToWorld(spec.node, -width,0,3*width)
394
395 local fruitType = g_fruitTypeManager:getFruitTypeIndexByFillTypeIndex(fillType)
396 local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(fruitType)
397
398 local dx,_,dz = localDirectionToWorld(spec.node, 0, 0, 1)
399 local angleRad = MathUtil.getYRotationFromDirection(dx, dz)
400 if fruitDesc ~= nil and fruitDesc.directionSnapAngle ~= 0 then
401 angleRad = math.floor(angleRad / fruitDesc.directionSnapAngle + 0.5) * fruitDesc.directionSnapAngle
402 end
403 local angle = FSDensityMapUtil.convertToDensityMapAngle(angleRad, g_currentMission.terrainDetailAngleMaxValue)
404
405 -- cultivate
406 local limitToField = spec.limitToField or spec.forceLimitToField
407 local limitGrassDestructionToField = spec.limitToField or spec.forceLimitToField
408 FSDensityMapUtil.updateCultivatorArea(sx,sz, wx,wz, hx,hz, not limitToField, not limitGrassDestructionToField, angle, nil)
409 FSDensityMapUtil.eraseTireTrack(sx,sz, wx,wz, hx,hz)
410
411 -- plant, shift area
412 sx,_,sz = localToWorld(spec.node, -width,0,-3*width)
413 wx,_,wz = localToWorld(spec.node, width,0,-3*width)
414 hx,_,hz = localToWorld(spec.node, -width,0,-width)
415 local area, _ = FSDensityMapUtil.updateSowingArea(fruitType, sx,sz, wx,wz, hx,hz, angle, 2)
416
417 local usage = fruitDesc.seedUsagePerSqm * area
418
419 local stats = g_farmManager:getFarmById(self:getActiveFarm()).stats
420 if self:getIsAIActive() and g_currentMission.missionInfo.helperBuySeeds then
421 local price = usage * g_currentMission.economyManager:getCostPerLiter(FillType.SEEDS, false) * 1.5 -- increase price if AI is active to reward the player's manual work
422 stats:updateStats("expenses", price)
423 g_currentMission:addMoney(-price, self:getActiveFarm(), MoneyType.PURCHASE_SEEDS)
424 else
425 self:addFillUnitFillLevel(self:getOwnerFarmId(), spec.fillUnitIndex, -usage, fillType, ToolType.UNDEFINED)
426 end
427
428 local lastHa = MathUtil.areaToHa(area, g_currentMission:getFruitPixelsToSqm())
429 stats:updateStats("seedUsage", usage)
430 stats:updateStats("sownHectares", lastHa)
431 stats:updateStats("sownTime", dt/(1000*60))
432 stats:updateStats("workedHectares", lastHa)
433 stats:updateStats("workedTime", dt/(1000*60))
434 else
435 showFieldNotOwnedWarning = true
436 end
437 end
438 end
439 end
440 end
441
442 if self.isServer then
443 if spec.showFieldNotOwnedWarning ~= showFieldNotOwnedWarning or spec.showRestrictedZoneWarning ~= showRestrictedZoneWarning then
444 spec.showFieldNotOwnedWarning = showFieldNotOwnedWarning
445 spec.showRestrictedZoneWarning = showRestrictedZoneWarning
446 self:raiseDirtyFlags(spec.dirtyFlag)
447 end
448 end
449
450 if self.isClient then
451 if self:getIsTurnedOn() and spec.hasGroundContact and self:getLastSpeed() > 1 then
452 if not spec.isWorkSamplePlaying then
453 g_soundManager:playSample(spec.samples.work)
454 spec.isWorkSamplePlaying = true
455 end
456 else
457 if spec.isWorkSamplePlaying then
458 g_soundManager:stopSample(spec.samples.work)
459 spec.isWorkSamplePlaying = false
460 end
461 end
462
463 local actionEvent = spec.actionEvents[InputAction.IMPLEMENT_EXTRA3]
464 if actionEvent ~= nil then
465 local showAction = false
466
467 if isActiveForInputIgnoreSelection then
468 local fillType = self:getFillUnitFillType(spec.fillUnitIndex)
469 if fillType ~= FillType.UNKNOWN and fillType ~= FillType.TREESAPLINGS then
470 if g_currentMission:getHasPlayerPermission("createFields", self:getOwner()) then
471 if not spec.forceLimitToField then
472 showAction = true
473 end
474 end
475 end
476
477 if showAction then
478 if spec.limitToField then
479 g_inputBinding:setActionEventText(actionEvent.actionEventId, g_i18n:getText("action_allowCreateFields"))
480 else
481 g_inputBinding:setActionEventText(actionEvent.actionEventId, g_i18n:getText("action_limitToFields"))
482 end
483 end
484 end
485
486 g_inputBinding:setActionEventActive(actionEvent.actionEventId, showAction)
487 end
488 end
489end

onWriteStream

Description
Called on server side on join
Definition
onWriteStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
218function TreePlanter:onWriteStream(streamId, connection)
219 local spec = self.spec_treePlanter
220 streamWriteBool(streamId, spec.mountedSaplingPallet ~= nil)
221 if spec.mountedSaplingPallet ~= nil then
222 local palletId = NetworkUtil.getObjectId(spec.mountedSaplingPallet)
223 NetworkUtil.writeNodeObjectId(streamId, palletId)
224 end
225end

onWriteUpdateStream

Description
Called on on update
Definition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
248function TreePlanter:onWriteUpdateStream(streamId, connection, dirtyMask)
249 if not connection:getIsServer() then
250 local spec = self.spec_treePlanter
251 if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlag) ~= 0) then
252 streamWriteBool(streamId, spec.hasGroundContact)
253 streamWriteBool(streamId, spec.showFieldNotOwnedWarning)
254 streamWriteBool(streamId, spec.showRestrictedZoneWarning)
255 end
256 end
257end

palletTriggerCallback

Description
Definition
palletTriggerCallback()
Code
838function TreePlanter:palletTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
839 local spec = self.spec_treePlanter
840
841 if otherId ~= 0 then
842 local object = g_currentMission:getNodeObject(otherId)
843 if object ~= nil and object.isa ~= nil then
844 if object:isa(Vehicle) then
845 if object.typeName:find("pallet") ~= nil and g_currentMission.accessHandler:canFarmAccess(self:getActiveFarm(), object) then
846 local currentValue = Utils.getNoNil(spec.palletsInTrigger[object], 0)
847
848 if onEnter then
849 spec.palletsInTrigger[object] = currentValue + 1
850
851 if currentValue == 0 and object.addDeleteListener ~= nil then
852 object:addDeleteListener(self, "onDeleteTreePlanterObject")
853 end
854 elseif onLeave then
855 spec.palletsInTrigger[object] = math.max(currentValue - 1, 0)
856 end
857
858 if spec.palletsInTrigger[object] == 0 then
859 spec.palletsInTrigger[object] = nil
860 end
861 end
862 end
863 end
864 end
865end

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
20function TreePlanter.prerequisitesPresent(specializations)
21 return SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations)
22 and SpecializationUtil.hasSpecialization(FillUnit, specializations)
23 and SpecializationUtil.hasSpecialization(GroundReference, specializations)
24end

registerEventListeners

Description
Definition
registerEventListeners()
Code
62function TreePlanter.registerEventListeners(vehicleType)
63 SpecializationUtil.registerEventListener(vehicleType, "onLoad", TreePlanter)
64 SpecializationUtil.registerEventListener(vehicleType, "onDelete", TreePlanter)
65 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", TreePlanter)
66 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", TreePlanter)
67 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", TreePlanter)
68 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", TreePlanter)
69 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", TreePlanter)
70 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", TreePlanter)
71 SpecializationUtil.registerEventListener(vehicleType, "onDraw", TreePlanter)
72 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", TreePlanter)
73 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", TreePlanter)
74 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", TreePlanter)
75end

registerFunctions

Description
Definition
registerFunctions()
Code
28function TreePlanter.registerFunctions(vehicleType)
29 SpecializationUtil.registerFunction(vehicleType, "removeMountedObject", TreePlanter.removeMountedObject)
30 SpecializationUtil.registerFunction(vehicleType, "setPlantLimitToField", TreePlanter.setPlantLimitToField)
31 SpecializationUtil.registerFunction(vehicleType, "createTree", TreePlanter.createTree)
32 SpecializationUtil.registerFunction(vehicleType, "loadPallet", TreePlanter.loadPallet)
33 SpecializationUtil.registerFunction(vehicleType, "palletTriggerCallback", TreePlanter.palletTriggerCallback)
34 SpecializationUtil.registerFunction(vehicleType, "onDeleteTreePlanterObject", TreePlanter.onDeleteTreePlanterObject)
35end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
39function TreePlanter.registerOverwrittenFunctions(vehicleType)
40 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDirtMultiplier", TreePlanter.getDirtMultiplier)
41 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", TreePlanter.getWearMultiplier)
42 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsSpeedRotatingPartActive", TreePlanter.getIsSpeedRotatingPartActive)
43 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsWorkAreaActive", TreePlanter.getIsWorkAreaActive)
44 SpecializationUtil.registerOverwrittenFunction(vehicleType, "doCheckSpeedLimit", TreePlanter.doCheckSpeedLimit)
45 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", TreePlanter.getCanBeSelected)
46 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsOnField", TreePlanter.getIsOnField)
47 SpecializationUtil.registerOverwrittenFunction(vehicleType, "addNodeObjectMapping", TreePlanter.addNodeObjectMapping)
48 SpecializationUtil.registerOverwrittenFunction(vehicleType, "removeNodeObjectMapping", TreePlanter.removeNodeObjectMapping)
49
50 SpecializationUtil.registerOverwrittenFunction(vehicleType, "addFillUnitFillLevel", TreePlanter.addFillUnitFillLevel)
51 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitFillLevel", TreePlanter.getFillUnitFillLevel)
52 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitFillLevelPercentage", TreePlanter.getFillUnitFillLevelPercentage)
53 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitFillType", TreePlanter.getFillUnitFillType)
54 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitCapacity", TreePlanter.getFillUnitCapacity)
55 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitAllowsFillType", TreePlanter.getFillUnitAllowsFillType)
56 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitFreeCapacity", TreePlanter.getFillUnitFreeCapacity)
57 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillLevelInformation", TreePlanter.getFillLevelInformation)
58end

removeMountedObject

Description
Remove mounted object
Definition
removeMountedObject(integer object, boolean isDeleting)
Arguments
integerobjectobject to remove
booleanisDeletingcalled on delete
Code
194function TreePlanter:removeMountedObject(object, isDeleting)
195 local spec = self.spec_treePlanter
196
197 if spec.mountedSaplingPallet == object then
198 spec.mountedSaplingPallet:unmount()
199 spec.mountedSaplingPallet = nil
200 end
201end

removeNodeObjectMapping

Description
Definition
removeNodeObjectMapping()
Code
827function TreePlanter:removeNodeObjectMapping(superFunc, list)
828 superFunc(self, list)
829
830 local spec = self.spec_treePlanter
831 if spec.palletTrigger ~= nil then
832 list[spec.palletTrigger] = nil
833 end
834end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
179function TreePlanter:saveToXMLFile(xmlFile, key, usedModNames)
180 local spec = self.spec_treePlanter
181
182 if spec.lastTreePos ~= nil then
183 setXMLString(xmlFile, key.."#lastTreePos", string.format("%f %f %f", unpack(spec.lastTreePos)))
184 end
185 if spec.mountedSaplingPallet ~= nil then
186 setXMLBool(xmlFile, key.."#palletHadBeenMounted", true)
187 end
188end

setPlantLimitToField

Description
Set plant limit to field state
Definition
setPlantLimitToField(boolean plantLimitToField, boolean noEventSend)
Arguments
booleanplantLimitToFieldplant limit to field state
booleannoEventSendno event send
Code
644function TreePlanter:setPlantLimitToField(plantLimitToField, noEventSend)
645 local spec = self.spec_treePlanter
646
647 if spec.limitToField ~= plantLimitToField then
648 spec.limitToField = plantLimitToField
649
650 PlantLimitToFieldEvent.sendEvent(self, plantLimitToField, noEventSend)
651 end
652end