Script v1.7.1.0
- AI
- Animals
- Contracts
- Debug
- Economy
- Effects
- Events
- Farms
- GUI
- Handtools
- I3d
- Materials
- Misc
- Objects
- Placeables
- Player
- Shop
- Sounds
- Specializations
- AIConveyorBelt
- AIImplement
- AIVehicle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BaseMaterial
- BunkerSiloCompacter
- BunkerSiloInteractor
- BuyableBale
- CCTDrivable
- Combine
- ConnectionHoses
- ConveyorBelt
- Cover
- CrabSteering
- Crawlers
- Cultivator
- Cutter
- Cylindered
- CylinderedFoldable
- Dashboard
- Dischargeable
- Drivable
- DynamicallyLoadedParts
- DynamicMountAttacher
- Enterable
- FertilizingCultivator
- FertilizingSowingMachine
- FillTriggerVehicle
- FillUnit
- FillVolume
- Foldable
- FoliageBending
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- GroundAdjustedNodes
- GroundReference
- Honk
- HookLiftContainer
- HookLiftTrailer
- IKChains
- JigglingParts
- Leveler
- Lights
- LivestockTrailer
- Locomotive
- LogGrab
- ManureBarrel
- MixerWagon
- Motorized
- Mountable
- Mower
- Pickup
- Pipe
- Plow
- PowerConsumer
- PowerTakeOffs
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- Rideable
- RidgeMarker
- Roller
- Ropes
- SemiTrailerFront
- Shovel
- SlopeCompensation
- SmartAttach
- SowingMachine
- SpeedRotatingParts
- SplineVehicle
- Sprayer
- StrawBlower
- StumpCutter
- Suspensions
- Tedder
- TensionBeltObject
- TensionBelts
- TipOccluder
- Trailer
- TreePlanter
- TreeSaw
- TurnOnVehicle
- Washable
- WaterTrailer
- Wearable
- Weeder
- Wheels
- Windrower
- Wipers
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkMode
- WorkParticles
- Triggers
- Utils
- Vehicles
- Weather
Engine v1.7.1.0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- XML
- general
Foundation Reference
TreePlanter
DescriptionSpecialization for tree planters providing possibility to pick up seedling pallets and create treesFunctions
- actionEventToggleTreePlanterFieldLimitation
- addNodeObjectMapping
- createTree
- doCheckSpeedLimit
- getCanBeSelected
- getDefaultSpeedLimit
- getDirtMultiplier
- getIsOnField
- getIsSpeedRotatingPartActive
- getIsWorkAreaActive
- getSaplingPalletInRange
- getWearMultiplier
- loadPallet
- onDelete
- onDeleteTreePlanterObject
- onDraw
- onLoad
- onReadStream
- onReadUpdateStream
- onRegisterActionEvents
- onTurnedOff
- onTurnedOn
- onUpdate
- onUpdateTick
- onWriteStream
- onWriteUpdateStream
- palletTriggerCallback
- prerequisitesPresent
- registerEventListeners
- registerFunctions
- registerOverwrittenFunctions
- removeMountedObject
- removeNodeObjectMapping
- saveToXMLFile
- setPlantLimitToField
actionEventToggleTreePlanterFieldLimitation
DescriptionDefinitionactionEventToggleTreePlanterFieldLimitation()Code
883 | function TreePlanter.actionEventToggleTreePlanterFieldLimitation(self, actionName, inputValue, callbackState, isAnalog) |
884 | self:setPlantLimitToField(not self.spec_treePlanter.limitToField) |
885 | end |
addNodeObjectMapping
DescriptionDefinitionaddNodeObjectMapping()Code
816 | function 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 |
823 | end |
createTree
DescriptionCreate tree on current positionDefinition
createTree()Code
656 | function 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 |
705 | end |
doCheckSpeedLimit
DescriptionReturns if speed limit should be checkedDefinition
doCheckSpeedLimit()Return Values
boolean | checkSpeedlimit | check speed limit |
778 | function TreePlanter:doCheckSpeedLimit(superFunc) |
779 | return superFunc(self) or (self:getIsTurnedOn() and self:getIsImplementChainLowered()) |
780 | end |
getCanBeSelected
DescriptionDefinitiongetCanBeSelected()Code
784 | function TreePlanter:getCanBeSelected(superFunc) |
785 | return true |
786 | end |
getDefaultSpeedLimit
DescriptionReturns default speed limitDefinition
getDefaultSpeedLimit()Return Values
float | speedLimit | speed limit |
890 | function TreePlanter.getDefaultSpeedLimit() |
891 | return 5 |
892 | end |
getDirtMultiplier
DescriptionReturns current dirt multiplierDefinition
getDirtMultiplier()Return Values
float | dirtMultiplier | current dirt multiplier |
721 | function 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 |
730 | end |
getIsOnField
DescriptionDefinitiongetIsOnField()Code
801 | function 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 |
812 | end |
getIsSpeedRotatingPartActive
DescriptionReturns true if speed rotating part is activeDefinition
getIsSpeedRotatingPartActive(table speedRotatingPart)Arguments
table | speedRotatingPart | speedRotatingPart |
boolean | isActive | speed rotating part is active |
750 | function 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) |
758 | end |
getIsWorkAreaActive
DescriptionDefinitiongetIsWorkAreaActive()Code
762 | function 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 |
773 | end |
getSaplingPalletInRange
DescriptionReturns nearest sapling pallet in rangeDefinition
getSaplingPalletInRange(integer refNode)Arguments
integer | refNode | id of reference node |
table | object | object of sapling pallet |
898 | function 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 |
935 | end |
getWearMultiplier
DescriptionReturns current wear multiplierDefinition
getWearMultiplier()Return Values
float | dirtMultiplier | current wear multiplier |
735 | function 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 |
744 | end |
loadPallet
DescriptionCalled on loadingDefinition
loadPallet(table savegame)Arguments
table | savegame | savegame |
710 | function TreePlanter:loadPallet(palletObjectId, noEventSend) |
711 | local spec = self.spec_treePlanter |
712 | |
713 | TreePlanterLoadPalletEvent.sendEvent(self, palletObjectId, noEventSend) |
714 | |
715 | spec.palletIdToMount = palletObjectId |
716 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
155 | function 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 |
175 | end |
onDeleteTreePlanterObject
DescriptionDefinitiononDeleteTreePlanterObject()Code
790 | function 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 |
797 | end |
onDraw
DescriptionCalled on drawDefinition
onDraw(boolean isActiveForInput, boolean isSelected)Arguments
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
495 | function 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 |
515 | end |
onLoad
DescriptionCalled on loadingDefinition
onLoad(table savegame)Arguments
table | savegame | savegame |
80 | function 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 |
151 | end |
onReadStream
DescriptionCalled on client side on joinDefinition
onReadStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
207 | function TreePlanter:onReadStream(streamId, connection) |
208 | if streamReadBool(streamId) then |
209 | local spec = self.spec_treePlanter |
210 | spec.palletIdToMount = NetworkUtil.readNodeObjectId(streamId) |
211 | end |
212 | end |
onReadUpdateStream
DescriptionCalled on on updateDefinition
onReadUpdateStream(integer streamId, integer timestamp, table connection)Arguments
integer | streamId | stream ID |
integer | timestamp | timestamp |
table | connection | connection |
232 | function 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 |
241 | end |
onRegisterActionEvents
DescriptionDefinitiononRegisterActionEvents()Code
869 | function 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 |
879 | end |
onTurnedOff
DescriptionCalled on turn offDefinition
onTurnedOff(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
530 | function 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 |
537 | end |
onTurnedOn
DescriptionCalled on turn offDefinition
onTurnedOn(boolean noEventSend)Arguments
boolean | noEventSend | no event send |
520 | function TreePlanter:onTurnedOn() |
521 | if self.isClient then |
522 | local spec = self.spec_treePlanter |
523 | g_animationManager:startAnimations(spec.animationNodes) |
524 | end |
525 | end |
onUpdate
DescriptionCalled on updateDefinition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)Arguments
float | dt | time since last call in ms |
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
264 | function 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 |
309 | end |
onUpdateTick
DescriptionCalled on update tickDefinition
onUpdateTick(float dt, boolean isActiveForInput, boolean isSelected)Arguments
float | dt | time since last call in ms |
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
316 | function 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 |
489 | end |
onWriteStream
DescriptionCalled on server side on joinDefinition
onWriteStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
218 | function 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 |
225 | end |
onWriteUpdateStream
DescriptionCalled on on updateDefinition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)Arguments
integer | streamId | stream ID |
table | connection | connection |
integer | dirtyMask | dirty mask |
248 | function 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 |
257 | end |
palletTriggerCallback
DescriptionDefinitionpalletTriggerCallback()Code
838 | function 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 |
865 | 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 |
20 | function TreePlanter.prerequisitesPresent(specializations) |
21 | return SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations) |
22 | and SpecializationUtil.hasSpecialization(FillUnit, specializations) |
23 | and SpecializationUtil.hasSpecialization(GroundReference, specializations) |
24 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
62 | function 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) |
75 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
28 | function 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) |
35 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
39 | function 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) |
58 | end |
removeMountedObject
DescriptionRemove mounted objectDefinition
removeMountedObject(integer object, boolean isDeleting)Arguments
integer | object | object to remove |
boolean | isDeleting | called on delete |
194 | function 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 |
201 | end |
removeNodeObjectMapping
DescriptionDefinitionremoveNodeObjectMapping()Code
827 | function 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 |
834 | end |
saveToXMLFile
DescriptionDefinitionsaveToXMLFile()Code
179 | function 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 |
188 | end |
setPlantLimitToField
DescriptionSet plant limit to field stateDefinition
setPlantLimitToField(boolean plantLimitToField, boolean noEventSend)Arguments
boolean | plantLimitToField | plant limit to field state |
boolean | noEventSend | no event send |
644 | function 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 |
652 | end |