LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

WoodHarvester

Description
Specialization for wood harvesters including grabbing, felling, delimbing and cutting of certrain types of trees
Functions

actionEventCutTree

Description
Definition
actionEventCutTree()
Code
1054function WoodHarvester.actionEventCutTree(self, actionName, inputValue, callbackState, isAnalog)
1055 local spec = self.spec_woodHarvester
1056
1057 if spec.hasAttachedSplitShape then
1058 if not spec.isAttachedSplitShapeMoving and self:getAnimationTime(spec.cutAnimation.name) == 1 then
1059 self:cutTree(spec.currentCutLength)
1060 end
1061 elseif spec.curSplitShape ~= nil then
1062 self:cutTree(0)
1063 end
1064end

actionEventSetCutlength

Description
Definition
actionEventSetCutlength()
Code
1068function WoodHarvester.actionEventSetCutlength(self, actionName, inputValue, callbackState, isAnalog)
1069 local spec = self.spec_woodHarvester
1070
1071 if not spec.isAttachedSplitShapeMoving then
1072 spec.currentCutLength = spec.currentCutLength + spec.cutLengthStep
1073 if spec.currentCutLength > spec.cutLengthMax + 0.0001 then
1074 spec.currentCutLength = spec.cutLengthMin
1075 end
1076 end
1077end

cutTree

Description
Definition
cutTree()
Code
872function WoodHarvester:cutTree(length, noEventSend)
873 local spec = self.spec_woodHarvester
874 WoodHarvesterCutTreeEvent.sendEvent(self, length, noEventSend)
875 if self.isServer then
876 if length == 0 then
877 if spec.attachedSplitShape ~= nil or spec.curSplitShape ~= nil then
878 spec.cutTimer = 100
879 if spec.cutAnimation.name ~= nil then
880 self:setAnimationTime(spec.cutAnimation.name, 0, true)
881 self:playAnimation(spec.cutAnimation.name, spec.cutAnimation.speedScale, self:getAnimationTime(spec.cutAnimation.name))
882 end
883 end
884 elseif length > 0 and spec.attachedSplitShape ~= nil then
885 spec.attachedSplitShapeTargetY = spec.attachedSplitShapeLastCutY + length
886
887 self:onDelimbTree(true)
888 if g_server ~= nil then
889 g_server:broadcastEvent(WoodHarvesterOnDelimbTreeEvent.new(self, true), nil, nil, self)
890 end
891 end
892 end
893end

findSplitShapesInRange

Description
Searches for split shapes in range
Definition
findSplitShapesInRange(float yOffset, boolean skipCutAnimation)
Arguments
floatyOffsety offset for search
booleanskipCutAnimationskip cut animation
Code
798function WoodHarvester:findSplitShapesInRange(yOffset, skipCutAnimation)
799 local spec = self.spec_woodHarvester
800 if spec.attachedSplitShape == nil and spec.cutNode ~= nil then
801 local x,y,z = localToWorld(spec.cutNode, yOffset or 0, 0, 0)
802 local nx,ny,nz = localDirectionToWorld(spec.cutNode, 1,0,0)
803 local yx,yy,yz = localDirectionToWorld(spec.cutNode, 0,1,0)
804
805 --#debug local zx,zy,zz = localDirectionToWorld(spec.cutNode, 0,0,1)
806 --#debug DebugUtil.drawDebugNode(spec.cutNode, "", false)
807 --#debug DebugUtil.drawDebugAreaRectangle(x,y,z, x+zx*spec.cutSizeZ,y+zy*spec.cutSizeZ,z+zz*spec.cutSizeZ, x+yx*spec.cutSizeY,y+yy*spec.cutSizeY,z+yz*spec.cutSizeY, false, 1,0,0)
808
809 if spec.curSplitShape == nil and (spec.cutReleasedComponentJoint == nil or spec.cutReleasedComponentJointRotLimitX == 0) then
810 local shape, minY, maxY, minZ, maxZ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, spec.cutSizeY, spec.cutSizeZ)
811
812 if shape ~= 0 then
813 local splitType = g_splitTypeManager:getSplitTypeByIndex(getSplitType(shape))
814 if splitType == nil or not splitType.allowsWoodHarvester then
815 spec.warnInvalidTree = true
816 else
817 if self:getCanSplitShapeBeAccessed(x, z, shape) then
818 local treeDx,treeDy,treeDz = localDirectionToWorld(shape, 0,1,0) -- wood harvester trees always grow in the y direction
819 local cosTreeAngle = MathUtil.dotProduct(nx,ny,nz, treeDx,treeDy,treeDz)
820
821 -- Only allow cutting if the cut header is approximately parallel to the tree (15° offset)
822 if math.acos(cosTreeAngle) <= 0.2617 then
823 local radius = math.max(maxY-minY, maxZ-minZ)*0.5 * cosTreeAngle
824
825 --#debug local x1, y1, z1 = localToWorld(spec.cutNode, yOffset or 0, minY, minZ)
826 --#debug local x2, y2, z2 = localToWorld(spec.cutNode, yOffset or 0, minY, maxZ)
827 --#debug local x3, y3, z3 = localToWorld(spec.cutNode, yOffset or 0, maxY, minZ)
828 --#debug Utils.renderTextAtWorldPosition((x1+x3) / 2, (y1+y3) / 2, (z1+z3) / 2, string.format("diam: %.1f/%.1f", math.deg(radius*2), math.deg(spec.cutMaxRadius*2)), getCorrectTextSize(0.012), 0)
829 --#debug DebugUtil.drawDebugAreaRectangle(x1, y1, z1, x2, y2, z2, x3, y3, z3, false, 0,1,0)
830
831 if radius > spec.cutMaxRadius then
832 spec.warnInvalidTreeRadius = true
833
834 -- check one meter higher if the tree would fit and then display different warning
835 x, y, z = localToWorld(spec.cutNode, yOffset or 0 + 1, 0, 0)
836 shape, minY, maxY, minZ, maxZ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, spec.cutSizeY, spec.cutSizeZ)
837 if shape ~= 0 then
838 radius = math.max(maxY-minY, maxZ-minZ)*0.5 * cosTreeAngle
839
840 --#debug x1, y1, z1 = localToWorld(spec.cutNode, yOffset or 0 + 1, minY, minZ)
841 --#debug x2, y2, z2 = localToWorld(spec.cutNode, yOffset or 0 + 1, minY, maxZ)
842 --#debug x3, y3, z3 = localToWorld(spec.cutNode, yOffset or 0 + 1, maxY, minZ)
843 --#debug Utils.renderTextAtWorldPosition((x1+x3) / 2, (y1+y3) / 2, (z1+z3) / 2, string.format("diam: %.1f/%.1f", math.deg(radius*2), math.deg(spec.cutMaxRadius*2)), getCorrectTextSize(0.012), 0)
844 --#debug DebugUtil.drawDebugAreaRectangle(x1, y1, z1, x2, y2, z2, x3, y3, z3, false, 0,1,0)
845
846 if radius <= spec.cutMaxRadius then
847 spec.warnInvalidTreeRadius = false
848 spec.warnInvalidTreePosition = true
849 end
850 end
851 else
852 self:setLastTreeDiameter(math.max(maxY-minY, maxZ-minZ))
853 spec.curSplitShape = shape
854
855 if skipCutAnimation then
856 self:setAnimationTime(spec.cutAnimation.name, 1, true)
857 spec.cutTimer = 0
858 end
859 end
860 end
861 else
862 spec.warnTreeNotOwned = true
863 end
864 end
865 end
866 end
867 end
868end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
1029function WoodHarvester:getCanBeSelected(superFunc)
1030 return true
1031end

getDoConsumePtoPower

Description
Returns if should consume pto power
Definition
getDoConsumePtoPower()
Return Values
booleanconsumeconsumePtoPower
Code
1036function WoodHarvester:getDoConsumePtoPower(superFunc)
1037 local spec = self.spec_woodHarvester
1038 return superFunc(self) or spec.isAttachedSplitShapeMoving or self:getIsAnimationPlaying(spec.cutAnimation.name)
1039end

getIsFoldAllowed

Description
Definition
getIsFoldAllowed()
Code
1043function WoodHarvester:getIsFoldAllowed(superFunc, direction, onAiTurnOn)
1044 local spec = self.spec_woodHarvester
1045 if spec.hasAttachedSplitShape then
1046 return false, spec.texts.warningFoldingTreeMounted
1047 end
1048
1049 return superFunc(self, direction, onAiTurnOn)
1050end

initSpecialization

Description
Definition
initSpecialization()
Code
25function WoodHarvester.initSpecialization()
26 local schema = Vehicle.xmlSchema
27 schema:setXMLSpecializationType("WoodHarvester")
28
29 schema:register(XMLValueType.NODE_INDEX, "vehicle.woodHarvester.cutNode#node", "Cut node")
30 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutNode#maxRadius", "Max. radius", 1)
31 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutNode#sizeY", "Size Y", 1)
32 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutNode#sizeZ", "Size Z", 1)
33 schema:register(XMLValueType.NODE_INDEX, "vehicle.woodHarvester.cutNode#attachNode", "Attach node")
34 schema:register(XMLValueType.NODE_INDEX, "vehicle.woodHarvester.cutNode#attachReferenceNode", "Attach reference node")
35 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutNode#attachMoveSpeed", "Attach move speed", 3)
36 schema:register(XMLValueType.INT, "vehicle.woodHarvester.cutNode#releasedComponentJointIndex", "Released component joint")
37 schema:register(XMLValueType.ANGLE, "vehicle.woodHarvester.cutNode#releasedComponentJointRotLimitXSpeed", "Released component joint rot limit X speed", 100)
38 schema:register(XMLValueType.INT, "vehicle.woodHarvester.cutNode#releasedComponentJoint2Index", "Released component joint 2")
39
40 schema:register(XMLValueType.NODE_INDEX, "vehicle.woodHarvester.delimbNode#node", "Delimb node")
41 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.delimbNode#sizeX", "Delimb size X", 0.1)
42 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.delimbNode#sizeY", "Delimb size Y", 1)
43 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.delimbNode#sizeZ", "Delimb size Z", 1)
44 schema:register(XMLValueType.BOOL, "vehicle.woodHarvester.delimbNode#delimbOnCut", "Delimb on cut", false)
45
46 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutLengths#min", "Min. cut length", 1)
47 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutLengths#max", "Max. cut length", 5)
48 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutLengths#step", "Cut length steps", 0.5)
49
50 EffectManager.registerEffectXMLPaths(schema, "vehicle.woodHarvester.cutEffects")
51 EffectManager.registerEffectXMLPaths(schema, "vehicle.woodHarvester.delimbEffects")
52 AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.woodHarvester.forwardingNodes")
53
54 SoundManager.registerSampleXMLPaths(schema, "vehicle.woodHarvester.sounds", "cut")
55 SoundManager.registerSampleXMLPaths(schema, "vehicle.woodHarvester.sounds", "delimb")
56
57 schema:register(XMLValueType.STRING, "vehicle.woodHarvester.cutAnimation#name", "Cut animation name")
58 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutAnimation#speedScale", "Cut animation speed scale")
59 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.cutAnimation#cutTime", "Cut animation cut time")
60
61 schema:register(XMLValueType.STRING, "vehicle.woodHarvester.grabAnimation#name", "Grab animation name")
62 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.grabAnimation#speedScale", "Grab animation speed scale")
63
64 schema:register(XMLValueType.NODE_INDEX, "vehicle.woodHarvester.treeSizeMeasure#node", "Tree size measure node")
65 schema:register(XMLValueType.FLOAT, "vehicle.woodHarvester.treeSizeMeasure#rotMaxRadius", "Max. tree size as reference for grab animation", 1)
66
67 Dashboard.registerDashboardXMLPaths(schema, "vehicle.woodHarvester.dashboards", "cutLength | curCutLength | diameter")
68
69 schema:setXMLSpecializationType()
70
71 local schemaSavegame = Vehicle.xmlSchemaSavegame
72 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?).woodHarvester#currentCutLength", "Current cut length", "Min. length")
73 schemaSavegame:register(XMLValueType.BOOL, "vehicles.vehicle(?).woodHarvester#isTurnedOn", "Harvester is turned on", false)
74 schemaSavegame:register(XMLValueType.VECTOR_4, "vehicles.vehicle(?).woodHarvester#lastTreeSize", "Last dimensions of tree to cutNode")
75 schemaSavegame:register(XMLValueType.VECTOR_3, "vehicles.vehicle(?).woodHarvester#lastTreeJointPos", "Last tree joint position in local space of splitShape")
76 schemaSavegame:register(XMLValueType.BOOL, "vehicles.vehicle(?).woodHarvester#hasAttachedSplitShape", "Has split shape attached", false)
77end

onCutTree

Description
Definition
onCutTree()
Code
897function WoodHarvester:onCutTree(radius, isNewTree)
898 local spec = self.spec_woodHarvester
899 if radius > 0 then
900 if self.isClient then
901 if spec.grabAnimation.name ~= nil then
902 local targetAnimTime = math.min( 1.0, radius / spec.treeSizeMeasure.rotMaxRadius )
903
904 if spec.grabAnimation.speedScale < 0 then
905 targetAnimTime = 1.0 - targetAnimTime
906 end
907 self:setAnimationStopTime(spec.grabAnimation.name, targetAnimTime)
908
909 if targetAnimTime > self:getAnimationTime(spec.grabAnimation.name) then
910 self:playAnimation(spec.grabAnimation.name, spec.grabAnimation.speedScale, self:getAnimationTime(spec.grabAnimation.name), true)
911 else
912 self:playAnimation(spec.grabAnimation.name, -spec.grabAnimation.speedScale, self:getAnimationTime(spec.grabAnimation.name), true)
913 end
914 end
915
916 self:setLastTreeDiameter(2*radius)
917 end
918
919 spec.hasAttachedSplitShape = true
920 else
921 if spec.grabAnimation.name ~= nil then
922 if spec.grabAnimation.speedScale > 0 then
923 self:setAnimationStopTime(spec.grabAnimation.name, 1)
924 else
925 self:setAnimationStopTime(spec.grabAnimation.name, 0)
926 end
927 self:playAnimation(spec.grabAnimation.name, spec.grabAnimation.speedScale, self:getAnimationTime(spec.grabAnimation.name), true)
928 end
929 spec.hasAttachedSplitShape = false
930 spec.cutTimer = -1
931 end
932end

onDeactivate

Description
Definition
onDeactivate()
Code
728function WoodHarvester:onDeactivate()
729 local spec = self.spec_woodHarvester
730 spec.curSplitShape = nil
731 self:setLastTreeDiameter(0)
732end

onDelete

Description
Definition
onDelete()
Code
305function WoodHarvester:onDelete()
306 local spec = self.spec_woodHarvester
307 if spec.attachedSplitShapeJointIndex ~= nil then
308 removeJoint(spec.attachedSplitShapeJointIndex)
309 spec.attachedSplitShapeJointIndex = nil
310 end
311 if spec.cutAttachHelperNode ~= nil then
312 delete(spec.cutAttachHelperNode)
313 end
314
315 g_effectManager:deleteEffects(spec.cutEffects)
316 g_effectManager:deleteEffects(spec.delimbEffects)
317 g_soundManager:deleteSamples(spec.samples)
318 g_animationManager:deleteAnimations(spec.forwardingNodes)
319end

onDelimbTree

Description
Definition
onDelimbTree()
Code
936function WoodHarvester:onDelimbTree(state)
937 local spec = self.spec_woodHarvester
938 if state then
939 spec.isAttachedSplitShapeMoving = true
940 else
941 spec.isAttachedSplitShapeMoving = false
942 self:cutTree(0)
943 end
944end

onDraw

Description
Definition
onDraw()
Code
691function WoodHarvester:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
692 local spec = self.spec_woodHarvester
693 if isActiveForInputIgnoreSelection and isSelected and self:getIsTurnedOn() then
694 if spec.cutNode ~= nil then
695 if spec.warnInvalidTreeRadius then
696 g_currentMission:showBlinkingWarning(spec.texts.warningTreeTooThick, 100)
697 elseif spec.warnInvalidTreePosition then
698 g_currentMission:showBlinkingWarning(spec.texts.warningTreeTooThickAtPosition, 100)
699 elseif spec.warnInvalidTree then
700 g_currentMission:showBlinkingWarning(spec.texts.warningTreeTypeNotSupported, 100)
701 elseif spec.warnTreeNotOwned then
702 g_currentMission:showBlinkingWarning(spec.texts.warningYouDontHaveAccessToThisLand, 100)
703 end
704 end
705 end
706end

onLoad

Description
Definition
onLoad()
Code
126function WoodHarvester:onLoad(savegame)
127 local spec = self.spec_woodHarvester
128
129 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.woodHarvester.delimbSound", "vehicle.woodHarvester.sounds.delimb") --FS17 to FS19
130 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.woodHarvester.cutSound", "vehicle.woodHarvester.sounds.cut") --FS17 to FS19
131 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.woodHarvester.treeSizeMeasure#index", "vehicle.woodHarvester.treeSizeMeasure#node") --FS17 to FS19
132 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.woodHarvester.forwardingWheels.wheel(0)", "vehicle.woodHarvester.forwardingNodes.animationNode") --FS17 to FS19
133 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.woodHarvester.cutParticleSystems", "vehicle.woodHarvester.cutEffects") --FS17 to FS19
134 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.woodHarvester.delimbParticleSystems", "vehicle.woodHarvester.delimbEffects") --FS17 to FS19
135
136 spec.curSplitShape = nil
137 spec.attachedSplitShape = nil
138 spec.hasAttachedSplitShape = false
139 spec.isAttachedSplitShapeMoving = false
140 spec.attachedSplitShapeX = 0
141 spec.attachedSplitShapeY = 0
142 spec.attachedSplitShapeZ = 0
143 spec.attachedSplitShapeTargetY = 0
144 spec.attachedSplitShapeLastCutY = 0
145 spec.attachedSplitShapeStartY = 0
146 spec.cutTimer = -1
147
148 spec.lastTreeSize = nil
149 spec.lastTreeJointPos = nil
150 spec.loadedSplitShapeFromSavegame = false
151
152 spec.cutNode = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#node", nil, self.components, self.i3dMappings)
153 spec.cutMaxRadius = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#maxRadius", 1)
154 spec.cutSizeY = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#sizeY", 1)
155 spec.cutSizeZ = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#sizeZ", 1)
156 spec.cutAttachNode = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#attachNode", nil, self.components, self.i3dMappings)
157 spec.cutAttachReferenceNode = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#attachReferenceNode", nil, self.components, self.i3dMappings)
158 spec.cutAttachMoveSpeed = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#attachMoveSpeed", 3) * 0.001
159 local cutReleasedComponentJointIndex = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#releasedComponentJointIndex")
160 if cutReleasedComponentJointIndex ~= nil then
161 spec.cutReleasedComponentJoint = self.componentJoints[cutReleasedComponentJointIndex]
162 spec.cutReleasedComponentJointRotLimitX = 0
163 spec.cutReleasedComponentJointRotLimitXSpeed = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#releasedComponentJointRotLimitXSpeed", 100) * 0.001
164 end
165 local cutReleasedComponentJoint2Index = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#releasedComponentJoint2Index")
166 if cutReleasedComponentJoint2Index ~= nil then
167 spec.cutReleasedComponentJoint2 = self.componentJoints[cutReleasedComponentJoint2Index]
168 spec.cutReleasedComponentJoint2RotLimitX = 0
169 spec.cutReleasedComponentJoint2RotLimitXSpeed = self.xmlFile:getValue("vehicle.woodHarvester.cutNode#releasedComponentJointRotLimitXSpeed", 100) * 0.001
170 end
171
172 if spec.cutAttachReferenceNode ~= nil and spec.cutAttachNode ~= nil then
173 spec.cutAttachHelperNode = createTransformGroup("helper")
174 link(spec.cutAttachReferenceNode, spec.cutAttachHelperNode)
175 setTranslation(spec.cutAttachHelperNode, 0,0,0)
176 setRotation(spec.cutAttachHelperNode, 0,0,0)
177 end
178
179 spec.delimbNode = self.xmlFile:getValue("vehicle.woodHarvester.delimbNode#node", nil, self.components, self.i3dMappings)
180 spec.delimbSizeX = self.xmlFile:getValue("vehicle.woodHarvester.delimbNode#sizeX", 0.1)
181 spec.delimbSizeY = self.xmlFile:getValue("vehicle.woodHarvester.delimbNode#sizeY", 1)
182 spec.delimbSizeZ = self.xmlFile:getValue("vehicle.woodHarvester.delimbNode#sizeZ", 1)
183 spec.delimbOnCut = self.xmlFile:getValue("vehicle.woodHarvester.delimbNode#delimbOnCut", false)
184
185 spec.cutLengthMin = self.xmlFile:getValue("vehicle.woodHarvester.cutLengths#min", 1)
186 spec.cutLengthMax = self.xmlFile:getValue("vehicle.woodHarvester.cutLengths#max", 5)
187 spec.cutLengthStep = self.xmlFile:getValue("vehicle.woodHarvester.cutLengths#step", 0.5)
188
189 if self.isClient then
190 spec.cutEffects = g_effectManager:loadEffect(self.xmlFile, "vehicle.woodHarvester.cutEffects", self.components, self, self.i3dMappings)
191 spec.delimbEffects = g_effectManager:loadEffect(self.xmlFile, "vehicle.woodHarvester.delimbEffects", self.components, self, self.i3dMappings)
192 spec.forwardingNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.woodHarvester.forwardingNodes", self.components, self, self.i3dMappings)
193
194 spec.samples = {}
195 spec.samples.cut = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.woodHarvester.sounds", "cut", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
196 spec.samples.delimb = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.woodHarvester.sounds", "delimb", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
197 spec.isCutSamplePlaying = false
198 spec.isDelimbSamplePlaying = false
199 end
200
201 spec.cutAnimation = {}
202 spec.cutAnimation.name = self.xmlFile:getValue("vehicle.woodHarvester.cutAnimation#name")
203 spec.cutAnimation.speedScale = self.xmlFile:getValue("vehicle.woodHarvester.cutAnimation#speedScale", 1)
204 spec.cutAnimation.cutTime = self.xmlFile:getValue("vehicle.woodHarvester.cutAnimation#cutTime", 1)
205
206 spec.grabAnimation = {}
207 spec.grabAnimation.name = self.xmlFile:getValue("vehicle.woodHarvester.grabAnimation#name")
208 spec.grabAnimation.speedScale = self.xmlFile:getValue("vehicle.woodHarvester.grabAnimation#speedScale", 1)
209
210 spec.treeSizeMeasure = {}
211 spec.treeSizeMeasure.node = self.xmlFile:getValue("vehicle.woodHarvester.treeSizeMeasure#node", nil, self.components, self.i3dMappings)
212 spec.treeSizeMeasure.rotMaxRadius = self.xmlFile:getValue("vehicle.woodHarvester.treeSizeMeasure#rotMaxRadius", 1)
213
214 spec.warnInvalidTree = false
215 spec.warnInvalidTreeRadius = false
216 spec.warnInvalidTreePosition = false
217 spec.warnTreeNotOwned = false
218
219 spec.currentCutLength = spec.cutLengthMin
220 spec.lastDiameter = 0
221
222 spec.texts = {}
223 spec.texts.actionChangeCutLength = g_i18n:getText("action_woodHarvesterChangeCutLength")
224 spec.texts.actionCut = g_i18n:getText("action_woodHarvesterCut")
225 spec.texts.warningFoldingTreeMounted = g_i18n:getText("warning_foldingTreeMounted")
226 spec.texts.warningTreeTooThick = g_i18n:getText("warning_treeTooThick")
227 spec.texts.warningTreeTooThickAtPosition = g_i18n:getText("warning_treeTooThickAtPosition")
228 spec.texts.warningTreeTypeNotSupported = g_i18n:getText("warning_treeTypeNotSupported")
229 spec.texts.warningYouDontHaveAccessToThisLand = g_i18n:getText("warning_youAreNotAllowedToCutThisTree")
230
231 if self.loadDashboardsFromXML ~= nil then
232 self:loadDashboardsFromXML(self.xmlFile, "vehicle.woodHarvester.dashboards", {valueTypeToLoad = "cutLength",
233 valueObject = spec,
234 valueFunc = function()
235 return spec.currentCutLength * 100
236 end})
237
238 self:loadDashboardsFromXML(self.xmlFile, "vehicle.woodHarvester.dashboards", {valueTypeToLoad = "curCutLength",
239 valueObject = spec,
240 valueFunc = function()
241 return math.abs(spec.currentCutLength - (spec.attachedSplitShapeTargetY - spec.attachedSplitShapeY)) * 100
242 end})
243
244 self:loadDashboardsFromXML(self.xmlFile, "vehicle.woodHarvester.dashboards", {valueTypeToLoad = "diameter",
245 valueObject = spec,
246 valueFunc = function()
247 return spec.lastDiameter * 1000
248 end})
249 end
250end

onLoadFinished

Description
Definition
onLoadFinished()
Code
288function WoodHarvester:onLoadFinished(savegame)
289 if savegame ~= nil and not savegame.resetVehicles then
290 if savegame.xmlFile:getValue(savegame.key..".woodHarvester#hasAttachedSplitShape", false) then
291 if self:getIsTurnedOn() then
292 self:findSplitShapesInRange(0.5, true)
293
294 local spec = self.spec_woodHarvester
295 if spec.curSplitShape ~= nil and spec.curSplitShape ~= 0 then
296 spec.loadedSplitShapeFromSavegame = true
297 end
298 end
299 end
300 end
301end

onPostLoad

Description
Definition
onPostLoad()
Code
254function WoodHarvester:onPostLoad(savegame)
255 local spec = self.spec_woodHarvester
256 if savegame ~= nil and not savegame.resetVehicles then
257 spec.currentCutLength = savegame.xmlFile:getValue(savegame.key..".woodHarvester#currentCutLength", spec.cutLengthMin)
258
259 if savegame.xmlFile:getValue(savegame.key..".woodHarvester#isTurnedOn", false) then
260 self:setIsTurnedOn(true)
261 end
262
263 local minY, maxY, minZ, maxZ = savegame.xmlFile:getValue(savegame.key..".woodHarvester#lastTreeSize")
264 if minY ~= nil then
265 spec.lastTreeSize = {minY, maxY, minZ, maxZ}
266 end
267
268 local x, y, z = savegame.xmlFile:getValue(savegame.key..".woodHarvester#lastTreeJointPos")
269 if x ~= nil then
270 spec.lastTreeJointPos = {x, y, z}
271 end
272 end
273
274 if spec.grabAnimation.name ~= nil then
275 local speedScale = -spec.grabAnimation.speedScale
276 local stopTime = 0
277 if spec.grabAnimation.speedScale < 0 then
278 stopTime = 1
279 end
280 self:playAnimation(spec.grabAnimation.name, speedScale, nil, true)
281 self:setAnimationStopTime(spec.grabAnimation.name, stopTime)
282 AnimatedVehicle.updateAnimationByName(self, spec.grabAnimation.name, 99999999, true)
283 end
284end

onReadStream

Description
Definition
onReadStream()
Code
343function WoodHarvester:onReadStream(streamId, connection)
344 local spec = self.spec_woodHarvester
345 spec.hasAttachedSplitShape = streamReadBool(streamId)
346 spec.isAttachedSplitShapeMoving = streamReadBool(streamId)
347end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
710function WoodHarvester:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
711 if self.isClient then
712 local spec = self.spec_woodHarvester
713 self:clearActionEventsTable(spec.actionEvents)
714
715 if isActiveForInputIgnoreSelection then
716 local _, actionEventId = self:addPoweredActionEvent(spec.actionEvents, InputAction.IMPLEMENT_EXTRA2, self, WoodHarvester.actionEventCutTree, false, true, false, true, nil)
717 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_HIGH)
718 g_inputBinding:setActionEventText(actionEventId, spec.texts.actionCut)
719
720 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.IMPLEMENT_EXTRA3, self, WoodHarvester.actionEventSetCutlength, false, true, false, true, nil)
721 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_HIGH)
722 end
723 end
724end

onStateChange

Description
Definition
onStateChange()
Code
778function WoodHarvester:onStateChange(state, data)
779 if self.isServer then
780 if state == Vehicle.STATE_CHANGE_MOTOR_TURN_ON then
781 if self.spec_woodHarvester.attachedSplitShape ~= nil then
782 if self:getCanBeTurnedOn() then
783 self:setIsTurnedOn(true)
784 end
785 end
786 end
787 end
788end

onTurnedOff

Description
Definition
onTurnedOff()
Code
753function WoodHarvester:onTurnedOff()
754 local spec = self.spec_woodHarvester
755
756 -- first open the cutter completely
757 if spec.grabAnimation.name ~= nil and spec.attachedSplitShape == nil then
758 self.playDelayedGrabAnimationTime = g_currentMission.time + 500
759 if spec.grabAnimation.speedScale > 0 then
760 self:setAnimationStopTime(spec.grabAnimation.name, 1)
761 else
762 self:setAnimationStopTime(spec.grabAnimation.name, 0)
763 end
764 self:playAnimation(spec.grabAnimation.name, spec.grabAnimation.speedScale, self:getAnimationTime(spec.grabAnimation.name), true)
765 end
766
767 if self.isClient then
768 g_effectManager:stopEffects(spec.delimbEffects)
769 g_effectManager:stopEffects(spec.cutEffects)
770 g_soundManager:stopSamples(spec.samples)
771 spec.isCutSamplePlaying = false
772 spec.isDelimbSamplePlaying = false
773 end
774end

onTurnedOn

Description
Definition
onTurnedOn()
Code
736function WoodHarvester:onTurnedOn()
737 local spec = self.spec_woodHarvester
738 self.playDelayedGrabAnimationTime = nil
739 if spec.grabAnimation.name ~= nil then
740 if spec.grabAnimation.speedScale > 0 then
741 self:setAnimationStopTime(spec.grabAnimation.name, 1)
742 else
743 self:setAnimationStopTime(spec.grabAnimation.name, 0)
744 end
745 self:playAnimation(spec.grabAnimation.name, spec.grabAnimation.speedScale, self:getAnimationTime(spec.grabAnimation.name), true)
746 end
747
748 self:setLastTreeDiameter(0)
749end

onUpdate

Description
Definition
onUpdate()
Code
359function WoodHarvester:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
360 local spec = self.spec_woodHarvester
361
362 -- Verify that the split shapes still exist (possible that someone has cut them)
363 if self.isServer then
364 local lostShape = false
365 if spec.attachedSplitShape ~= nil then
366 if not entityExists(spec.attachedSplitShape) then
367 spec.attachedSplitShape = nil
368 spec.attachedSplitShapeJointIndex = nil
369 spec.isAttachedSplitShapeMoving = false
370 spec.cutTimer = -1
371 lostShape = true
372 end
373 elseif spec.curSplitShape ~= nil then
374 if not entityExists(spec.curSplitShape) then
375 spec.curSplitShape = nil
376 lostShape = true
377 end
378 end
379 if lostShape then
380 SpecializationUtil.raiseEvent(self, "onCutTree", 0, false)
381 if g_server ~= nil then
382 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent.new(self, 0), nil, nil, self)
383 end
384 end
385 end
386
387 if self.isServer and (spec.attachedSplitShape ~= nil or spec.curSplitShape ~= nil) then
388 if spec.cutTimer > 0 then
389 if spec.cutAnimation.name ~= nil then
390 if self:getAnimationTime(spec.cutAnimation.name) > spec.cutAnimation.cutTime then
391 spec.cutTimer = 0
392 end
393 else
394 spec.cutTimer = math.max(spec.cutTimer - dt, 0)
395 end
396 end
397 local readyToCut = spec.cutTimer == 0
398
399 -- cut
400 if readyToCut then
401 spec.cutTimer = -1
402
403 local x,y,z = getWorldTranslation(spec.cutNode)
404 local nx,ny,nz = localDirectionToWorld(spec.cutNode, 1,0,0)
405 local yx,yy,yz = localDirectionToWorld(spec.cutNode, 0,1,0)
406 local newTreeCut = false
407
408 local currentSplitShape
409 if spec.attachedSplitShapeJointIndex ~= nil then
410 removeJoint(spec.attachedSplitShapeJointIndex)
411 spec.attachedSplitShapeJointIndex = nil
412 currentSplitShape = spec.attachedSplitShape
413 spec.attachedSplitShape = nil
414 else
415 currentSplitShape = spec.curSplitShape
416 spec.curSplitShape = nil
417 newTreeCut = true
418 end
419
420 -- remember split type name for later (achievement)
421 local splitTypeName = ""
422 local splitType = g_splitTypeManager:getSplitTypeByIndex(getSplitType(currentSplitShape))
423 if splitType ~= nil then
424 splitTypeName = splitType.name
425 end
426
427 if spec.delimbOnCut then
428 local xD,yD,zD = getWorldTranslation(spec.delimbNode)
429 local nxD,nyD,nzD = localDirectionToWorld(spec.delimbNode, 1,0,0)
430 local yxD,yyD,yzD = localDirectionToWorld(spec.delimbNode, 0,1,0)
431 local vx,vy,vz = x-xD,y-yD,z-zD
432 local sizeX = MathUtil.vector3Length(vx,vy,vz)
433 removeSplitShapeAttachments(currentSplitShape, xD+vx*0.5,yD+vy*0.5,zD+vz*0.5, nxD,nyD,nzD, yxD,yyD,yzD, sizeX*0.7+spec.delimbSizeX, spec.delimbSizeY, spec.delimbSizeZ)
434 end
435
436 spec.attachedSplitShape = nil
437 spec.curSplitShape = nil
438 spec.prevSplitShape = currentSplitShape
439
440 if not spec.loadedSplitShapeFromSavegame then
441 g_currentMission:removeKnownSplitShape(currentSplitShape)
442 self.shapeBeingCut = currentSplitShape
443 self.shapeBeingCutIsTree = getRigidBodyType(currentSplitShape) == RigidBodyType.STATIC
444 self.shapeBeingCutIsNew = newTreeCut
445 splitShape(currentSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, spec.cutSizeY, spec.cutSizeZ, "woodHarvesterSplitShapeCallback", self)
446 g_treePlantManager:removingSplitShape(currentSplitShape)
447 else
448 self:woodHarvesterSplitShapeCallback(currentSplitShape, false, true, unpack(spec.lastTreeSize))
449 end
450
451 if spec.attachedSplitShape == nil then
452 SpecializationUtil.raiseEvent(self, "onCutTree", 0, false)
453 if g_server ~= nil then
454 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent.new(self, 0), nil, nil, self)
455 end
456 else
457 if spec.delimbOnCut then
458 local xD,yD,zD = getWorldTranslation(spec.delimbNode)
459 local nxD,nyD,nzD = localDirectionToWorld(spec.delimbNode, 1,0,0)
460 local yxD,yyD,yzD = localDirectionToWorld(spec.delimbNode, 0,1,0)
461 local vx,vy,vz = x-xD,y-yD,z-zD
462 local sizeX = MathUtil.vector3Length(vx,vy,vz)
463 removeSplitShapeAttachments(spec.attachedSplitShape, xD+vx*3,yD+vy*3,zD+vz*3, nxD,nyD,nzD, yxD,yyD,yzD, sizeX*3+spec.delimbSizeX, spec.delimbSizeY, spec.delimbSizeZ)
464 end
465 end
466
467 if newTreeCut then
468 local stats = g_currentMission:farmStats(self:getActiveFarm())
469
470 -- increase tree cut counter for achievements
471 local cutTreeCount = stats:updateStats("cutTreeCount", 1)
472
473 g_achievementManager:tryUnlock("CutTreeFirst", cutTreeCount)
474 g_achievementManager:tryUnlock("CutTree", cutTreeCount)
475
476 -- update the types of trees cut so far (achievement)
477 if splitTypeName ~= "" then
478 stats:updateTreeTypesCut(splitTypeName)
479 end
480 end
481 end
482
483 -- delimb
484 if spec.attachedSplitShape ~= nil and spec.isAttachedSplitShapeMoving then
485 if spec.delimbNode ~= nil then
486 local x,y,z = getWorldTranslation(spec.delimbNode)
487 local nx,ny,nz = localDirectionToWorld(spec.delimbNode, 1,0,0)
488 local yx,yy,yz = localDirectionToWorld(spec.delimbNode, 0,1,0)
489
490 removeSplitShapeAttachments(spec.attachedSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, spec.delimbSizeX, spec.delimbSizeY, spec.delimbSizeZ)
491 end
492
493 if spec.cutNode ~= nil and spec.attachedSplitShapeJointIndex ~= nil then
494 local x,y,z = getWorldTranslation(spec.cutAttachReferenceNode)
495 local nx,ny,nz = localDirectionToWorld(spec.cutAttachReferenceNode, 0,1,0)
496 local _, lengthRem = getSplitShapePlaneExtents(spec.attachedSplitShape, x,y,z, nx,ny,nz)
497
498 if lengthRem == nil or lengthRem <= 0.1 then
499
500 -- end of tree
501 removeJoint(spec.attachedSplitShapeJointIndex)
502 spec.attachedSplitShapeJointIndex = nil
503 spec.attachedSplitShape = nil
504
505 self:onDelimbTree(false)
506 if g_server ~= nil then
507 g_server:broadcastEvent(WoodHarvesterOnDelimbTreeEvent.new(self, false), nil, nil, self)
508 end
509
510 SpecializationUtil.raiseEvent(self, "onCutTree", 0, false)
511 if g_server ~= nil then
512 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent.new(self, 0), nil, nil, self)
513 end
514 else
515 spec.attachedSplitShapeY = spec.attachedSplitShapeY + spec.cutAttachMoveSpeed*dt
516
517 if spec.attachedSplitShapeY >= spec.attachedSplitShapeTargetY then
518 spec.attachedSplitShapeY = spec.attachedSplitShapeTargetY
519 self:onDelimbTree(false)
520 if g_server ~= nil then
521 g_server:broadcastEvent(WoodHarvesterOnDelimbTreeEvent.new(self, false), nil, nil, self)
522 end
523 end
524 if spec.attachedSplitShapeJointIndex ~= nil then
525 x,y,z = localToWorld(spec.cutNode, 0.3,0,0)
526 nx,ny,nz = localDirectionToWorld(spec.cutNode, 1,0,0)
527 local yx,yy,yz = localDirectionToWorld(spec.cutNode, 0,1,0)
528 local shape, minY, maxY, minZ, maxZ = findSplitShape(x,y,z, nx,ny,nz, yx,yy,yz, spec.cutSizeY, spec.cutSizeZ)
529 if shape == spec.attachedSplitShape then
530 local treeCenterX,treeCenterY,treeCenterZ = localToWorld(spec.cutNode, 0, (minY+maxY)*0.5, (minZ+maxZ)*0.5)
531 spec.attachedSplitShapeX, _, spec.attachedSplitShapeZ = worldToLocal(spec.attachedSplitShape, treeCenterX,treeCenterY,treeCenterZ)
532 self:setLastTreeDiameter((maxY-minY + maxZ-minZ)*0.5)
533 end
534 x,y,z = localToWorld(spec.attachedSplitShape, spec.attachedSplitShapeX, spec.attachedSplitShapeY, spec.attachedSplitShapeZ)
535 setJointPosition(spec.attachedSplitShapeJointIndex, 1, x,y,z)
536 end
537 end
538 end
539 end
540 end
541
542 -- effect and sound for cut and delimb
543 if self.isClient then
544 -- cut
545 if spec.cutAnimation.name ~= nil then
546 if self:getIsAnimationPlaying(spec.cutAnimation.name) and self:getAnimationTime(spec.cutAnimation.name) < spec.cutAnimation.cutTime then
547 if not spec.isCutSamplePlaying then
548 g_soundManager:playSample(spec.samples.cut)
549 spec.isCutSamplePlaying = true
550 end
551 g_effectManager:setFillType(spec.cutEffects, FillType.WOODCHIPS)
552 g_effectManager:startEffects(spec.cutEffects)
553 else
554 if spec.isCutSamplePlaying then
555 g_soundManager:stopSample(spec.samples.cut)
556 spec.isCutSamplePlaying = false
557 end
558 g_effectManager:stopEffects(spec.cutEffects)
559 end
560 end
561
562 -- delimb
563 if spec.isAttachedSplitShapeMoving then
564 if not spec.isDelimbSamplePlaying then
565 g_soundManager:playSample(spec.samples.delimb)
566 spec.isDelimbSamplePlaying = true
567 end
568 g_effectManager:setFillType(spec.delimbEffects, FillType.WOODCHIPS)
569 g_effectManager:startEffects(spec.delimbEffects)
570 g_animationManager:startAnimations(spec.forwardingNodes)
571 else
572 if spec.isDelimbSamplePlaying then
573 g_soundManager:stopSample(spec.samples.delimb)
574 spec.isDelimbSamplePlaying = false
575 end
576 g_effectManager:stopEffects(spec.delimbEffects)
577 g_animationManager:stopAnimations(spec.forwardingNodes)
578 end
579 end
580end

onUpdateTick

Description
Definition
onUpdateTick()
Code
584function WoodHarvester:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
585 local spec = self.spec_woodHarvester
586
587 spec.warnInvalidTree = false
588 spec.warnInvalidTreeRadius = false
589 spec.warnInvalidTreePosition = false
590 spec.warnTreeNotOwned = false
591
592 if self:getIsTurnedOn() then
593 if spec.attachedSplitShape == nil and spec.cutNode ~= nil then
594 local x,y,z = getWorldTranslation(spec.cutNode)
595 local nx,ny,nz = localDirectionToWorld(spec.cutNode, 1,0,0)
596 local yx,yy,yz = localDirectionToWorld(spec.cutNode, 0,1,0)
597
598 self:findSplitShapesInRange()
599
600 if spec.curSplitShape ~= nil then
601 local minY,maxY, minZ,maxZ = testSplitShape(spec.curSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, spec.cutSizeY, spec.cutSizeZ)
602 if minY == nil then
603 spec.curSplitShape = nil
604 else
605 -- check if cut would be below y=0 (tree CoSy)
606 local cutTooLow = false
607 local _
608 _,y,_ = localToLocal(spec.cutNode, spec.curSplitShape, 0,minY,minZ)
609 cutTooLow = cutTooLow or y < 0.01
610 _,y,_ = localToLocal(spec.cutNode, spec.curSplitShape, 0,minY,maxZ)
611 cutTooLow = cutTooLow or y < 0.01
612 _,y,_ = localToLocal(spec.cutNode, spec.curSplitShape, 0,maxY,minZ)
613 cutTooLow = cutTooLow or y < 0.01
614 _,y,_ = localToLocal(spec.cutNode, spec.curSplitShape, 0,maxY,maxZ)
615 cutTooLow = cutTooLow or y < 0.01
616 if cutTooLow then
617 spec.curSplitShape = nil
618 end
619 end
620 end
621
622 if spec.curSplitShape == nil and spec.cutTimer > -1 then
623 SpecializationUtil.raiseEvent(self, "onCutTree", 0, false)
624 if g_server ~= nil then
625 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent.new(self, 0), nil, nil, self)
626 end
627 end
628
629 end
630 end
631
632 if self.isServer then
633 if spec.attachedSplitShape == nil then
634 if spec.cutReleasedComponentJoint ~= nil and spec.cutReleasedComponentJointRotLimitX ~= 0 then
635 spec.cutReleasedComponentJointRotLimitX = math.max(0, spec.cutReleasedComponentJointRotLimitX - spec.cutReleasedComponentJointRotLimitXSpeed*dt)
636 setJointRotationLimit(spec.cutReleasedComponentJoint.jointIndex, 0, true, 0, spec.cutReleasedComponentJointRotLimitX)
637 end
638 if spec.cutReleasedComponentJoint2 ~= nil and spec.cutReleasedComponentJoint2RotLimitX ~= 0 then
639 spec.cutReleasedComponentJoint2RotLimitX = math.max(spec.cutReleasedComponentJoint2RotLimitX-spec.cutReleasedComponentJoint2RotLimitXSpeed*dt, 0)
640 setJointRotationLimit(spec.cutReleasedComponentJoint2.jointIndex, 0, true, -spec.cutReleasedComponentJoint2RotLimitX, spec.cutReleasedComponentJoint2RotLimitX)
641 end
642 end
643 end
644
645 if self.isServer then
646 if self.playDelayedGrabAnimationTime ~= nil then
647 if self.playDelayedGrabAnimationTime < g_currentMission.time then
648 self.playDelayedGrabAnimationTime = nil
649 if self:getAnimationTime(spec.grabAnimation.name) > 0 then
650 if spec.grabAnimation.name ~= nil and spec.attachedSplitShape == nil then
651 if spec.grabAnimation.speedScale > 0 then
652 self:setAnimationStopTime(spec.grabAnimation.name, 0)
653 else
654 self:setAnimationStopTime(spec.grabAnimation.name, 1)
655 end
656 self:playAnimation(spec.grabAnimation.name, -spec.grabAnimation.speedScale, self:getAnimationTime(spec.grabAnimation.name), false)
657 end
658 end
659 end
660 end
661 end
662
663 if self.isClient then
664 local actionEvent = spec.actionEvents[InputAction.IMPLEMENT_EXTRA2]
665 if actionEvent ~= nil then
666 local showAction = false
667 if spec.hasAttachedSplitShape then
668 if not spec.isAttachedSplitShapeMoving and self:getAnimationTime(spec.cutAnimation.name) == 1 then
669 showAction = true
670 end
671 elseif spec.curSplitShape ~= nil then
672 showAction = true
673 end
674
675 g_inputBinding:setActionEventActive(actionEvent.actionEventId, showAction)
676 end
677
678 actionEvent = spec.actionEvents[InputAction.IMPLEMENT_EXTRA3]
679 if actionEvent ~= nil then
680 g_inputBinding:setActionEventActive(actionEvent.actionEventId, not spec.isAttachedSplitShapeMoving)
681 if not spec.isAttachedSplitShapeMoving then
682 g_inputBinding:setActionEventText(actionEvent.actionEventId, string.format(spec.texts.actionChangeCutLength, string.format("%.1f", spec.currentCutLength)))
683 end
684 end
685
686 end
687end

onWriteStream

Description
Definition
onWriteStream()
Code
351function WoodHarvester:onWriteStream(streamId, connection)
352 local spec = self.spec_woodHarvester
353 streamWriteBool(streamId, spec.hasAttachedSplitShape)
354 streamWriteBool(streamId, spec.isAttachedSplitShapeMoving)
355end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
19function WoodHarvester.prerequisitesPresent(specializations)
20 return SpecializationUtil.hasSpecialization(TurnOnVehicle, specializations)
21end

registerEventListeners

Description
Definition
registerEventListeners()
Code
106function WoodHarvester.registerEventListeners(vehicleType)
107 SpecializationUtil.registerEventListener(vehicleType, "onLoad", WoodHarvester)
108 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", WoodHarvester)
109 SpecializationUtil.registerEventListener(vehicleType, "onLoadFinished", WoodHarvester)
110 SpecializationUtil.registerEventListener(vehicleType, "onDelete", WoodHarvester)
111 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", WoodHarvester)
112 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", WoodHarvester)
113 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", WoodHarvester)
114 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", WoodHarvester)
115 SpecializationUtil.registerEventListener(vehicleType, "onDraw", WoodHarvester)
116 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", WoodHarvester)
117 SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", WoodHarvester)
118 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", WoodHarvester)
119 SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", WoodHarvester)
120 SpecializationUtil.registerEventListener(vehicleType, "onStateChange", WoodHarvester)
121 SpecializationUtil.registerEventListener(vehicleType, "onCutTree", WoodHarvester)
122end

registerEvents

Description
Definition
registerEvents()
Code
81function WoodHarvester.registerEvents(vehicleType)
82 SpecializationUtil.registerEvent(vehicleType, "onCutTree")
83end

registerFunctions

Description
Definition
registerFunctions()
Code
87function WoodHarvester.registerFunctions(vehicleType)
88 SpecializationUtil.registerFunction(vehicleType, "woodHarvesterSplitShapeCallback", WoodHarvester.woodHarvesterSplitShapeCallback)
89 SpecializationUtil.registerFunction(vehicleType, "setLastTreeDiameter", WoodHarvester.setLastTreeDiameter)
90 SpecializationUtil.registerFunction(vehicleType, "findSplitShapesInRange", WoodHarvester.findSplitShapesInRange)
91 SpecializationUtil.registerFunction(vehicleType, "cutTree", WoodHarvester.cutTree)
92 SpecializationUtil.registerFunction(vehicleType, "onDelimbTree", WoodHarvester.onDelimbTree)
93 SpecializationUtil.registerFunction(vehicleType, "getCanSplitShapeBeAccessed", WoodHarvester.getCanSplitShapeBeAccessed)
94end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
98function WoodHarvester.registerOverwrittenFunctions(vehicleType)
99 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", WoodHarvester.getCanBeSelected)
100 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDoConsumePtoPower", WoodHarvester.getDoConsumePtoPower)
101 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsFoldAllowed", WoodHarvester.getIsFoldAllowed)
102end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
323function WoodHarvester:saveToXMLFile(xmlFile, key, usedModNames)
324 local spec = self.spec_woodHarvester
325
326 xmlFile:setValue(key.."#currentCutLength", spec.currentCutLength)
327
328 xmlFile:setValue(key.."#isTurnedOn", self:getIsTurnedOn() or spec.hasAttachedSplitShape)
329 xmlFile:setValue(key.."#hasAttachedSplitShape", spec.hasAttachedSplitShape)
330
331 if spec.hasAttachedSplitShape then
332 if spec.lastTreeSize ~= nil then
333 xmlFile:setValue(key.."#lastTreeSize", unpack(spec.lastTreeSize))
334 end
335 if spec.lastTreeJointPos ~= nil then
336 xmlFile:setValue(key.."#lastTreeJointPos", unpack(spec.lastTreeJointPos))
337 end
338 end
339end

setLastTreeDiameter

Description
Definition
setLastTreeDiameter()
Code
1022function WoodHarvester:setLastTreeDiameter(diameter)
1023 local spec = self.spec_woodHarvester
1024 spec.lastDiameter = diameter
1025end

woodHarvesterSplitShapeCallback

Description
Definition
woodHarvesterSplitShapeCallback()
Code
948function WoodHarvester:woodHarvesterSplitShapeCallback(shape, isBelow, isAbove, minY, maxY, minZ, maxZ)
949 local spec = self.spec_woodHarvester
950
951 g_currentMission:addKnownSplitShape(shape)
952 g_treePlantManager:addingSplitShape(shape, self.shapeBeingCut, self.shapeBeingCutIsTree)
953
954 if spec.attachedSplitShape == nil and isAbove and not isBelow and spec.cutAttachNode ~= nil and spec.cutAttachReferenceNode ~= nil then
955 spec.attachedSplitShape = shape
956 spec.lastTreeSize = {minY, maxY, minZ, maxZ}
957
958 -- Current tree center (mid of cut area)
959 local treeCenterX, treeCenterY, treeCenterZ = localToWorld(spec.cutNode, 0, (minY+maxY)*0.5, (minZ+maxZ)*0.5)
960
961 if spec.loadedSplitShapeFromSavegame then
962 if spec.lastTreeJointPos ~= nil then
963 treeCenterX, treeCenterY, treeCenterZ = localToWorld(shape, unpack(spec.lastTreeJointPos))
964 end
965
966 spec.loadedSplitShapeFromSavegame = false
967 end
968 spec.lastTreeJointPos = {worldToLocal(shape, treeCenterX, treeCenterY, treeCenterZ)}
969
970 -- Target tree center (half tree size in front of the reference node)
971 local x,y,z = localToWorld(spec.cutAttachReferenceNode, 0, 0, (maxZ-minZ)*0.5)
972
973 local dx,dy,dz = localDirectionToWorld(shape, 0,0,1)
974
975 local upx,upy,upz = localDirectionToWorld(spec.cutAttachReferenceNode, 0,1,0)
976 local sideX,sideY,sizeZ = MathUtil.crossProduct(upx,upy,upz, dx,dy,dz)
977 dx,dy,dz = MathUtil.crossProduct(sideX,sideY,sizeZ, upx,upy,upz) -- Note: we want the up axis to be exact, thus orthogonalize the direction here
978 I3DUtil.setWorldDirection(spec.cutAttachHelperNode, dx,dy,dz, upx,upy,upz, 2)
979
980 local constr = JointConstructor.new()
981 constr:setActors(spec.cutAttachNode, shape)
982 -- Note: we assume that the direction of the tree is equal to the y axis
983 constr:setJointTransforms(spec.cutAttachHelperNode, shape)
984 constr:setJointWorldPositions(x,y,z, treeCenterX,treeCenterY,treeCenterZ)
985
986 constr:setRotationLimit(0, 0, 0)
987 constr:setRotationLimit(1, 0, 0)
988 constr:setRotationLimit(2, 0, 0)
989
990 constr:setEnableCollision(false)
991
992 spec.attachedSplitShapeJointIndex = constr:finalize()
993
994 if spec.cutReleasedComponentJoint ~= nil then
995 spec.cutReleasedComponentJointRotLimitX = math.pi*0.9
996 if spec.cutReleasedComponentJoint.jointIndex ~= 0 then
997 setJointRotationLimit(spec.cutReleasedComponentJoint.jointIndex, 0, true, 0, spec.cutReleasedComponentJointRotLimitX)
998 end
999 end
1000 if spec.cutReleasedComponentJoint2 ~= nil then
1001 spec.cutReleasedComponentJoint2RotLimitX = math.pi*0.9
1002 if spec.cutReleasedComponentJoint2.jointIndex ~= 0 then
1003 setJointRotationLimit(spec.cutReleasedComponentJoint2.jointIndex, 0, true, -spec.cutReleasedComponentJoint2RotLimitX, spec.cutReleasedComponentJoint2RotLimitX)
1004 end
1005 end
1006
1007 spec.attachedSplitShapeX, spec.attachedSplitShapeY, spec.attachedSplitShapeZ = worldToLocal(shape, treeCenterX,treeCenterY,treeCenterZ)
1008 spec.attachedSplitShapeLastCutY = spec.attachedSplitShapeY
1009 spec.attachedSplitShapeStartY = spec.attachedSplitShapeY
1010 spec.attachedSplitShapeTargetY = spec.attachedSplitShapeY
1011
1012 local radius = ((maxY - minY) + (maxZ - minZ)) / 4
1013 SpecializationUtil.raiseEvent(self, "onCutTree", radius, self.shapeBeingCutIsNew)
1014 if g_server ~= nil then
1015 g_server:broadcastEvent(WoodHarvesterOnCutTreeEvent.new(self, radius), nil, nil, self)
1016 end
1017 end
1018end