LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

RandomlyMovingParts

Description
Specialization for making parts randomly move during work using rotation changes
Functions

getIsRandomlyMovingPartActive

Description
Returns if randomly moving part is active
Definition
getIsRandomlyMovingPartActive(table part)
Arguments
tablepartpart to check
Return Values
booleanisActiveis active
Code
294function RandomlyMovingParts:getIsRandomlyMovingPartActive(part)
295 local retValue = true
296 if part.groundReferenceNode ~= nil then
297 retValue = self:getIsGroundReferenceNodeActive(part.groundReferenceNode)
298 end
299
300 return retValue
301end

initSpecialization

Description
Definition
initSpecialization()
Code
26function RandomlyMovingParts.initSpecialization()
27 local schema = Vehicle.xmlSchema
28 schema:setXMLSpecializationType("RandomlyMovingParts")
29
30 schema:register(XMLValueType.FLOAT, "vehicle.randomlyMovingParts#maxUpdateDistance", RandomlyMovingParts.DEFAULT_MAX_UPDATE_DISTANCE)
31
32 schema:register(XMLValueType.NODE_INDEX, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#node", "Node")
33 schema:register(XMLValueType.INT, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#refNodeIndex", "Ground reference node index")
34 schema:register(XMLValueType.VECTOR_ROT_2, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#rotMean", "Rotation mean")
35 schema:register(XMLValueType.INT, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#rotAxis", "Rotation axis")
36 schema:register(XMLValueType.VECTOR_ROT_2, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#rotVariance", "Rotation variance")
37 schema:register(XMLValueType.VECTOR_2, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#rotTimeMean", "Rotation time mean")
38 schema:register(XMLValueType.VECTOR_2, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#rotTimeVariance", "Rotation time variance")
39 schema:register(XMLValueType.VECTOR_2, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#pauseMean", "Pause time variance")
40 schema:register(XMLValueType.VECTOR_2, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#pauseVariance", "Pause time variance")
41 schema:register(XMLValueType.BOOL, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. "#isSpeedDependent", "Is speed dependent")
42
43 schema:register(XMLValueType.NODE_INDEX, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. ".node(?)#node", "Node to apply the same random angle")
44 schema:register(XMLValueType.INT, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. ".node(?)#rotAxis", "Rotation axis")
45 schema:register(XMLValueType.FLOAT, RandomlyMovingParts.RANDOMLY_MOVING_PART_XML_KEY .. ".node(?)#scale", "Rotation Scale")
46
47 schema:setXMLSpecializationType()
48end

loadRandomlyMovingPartFromXML

Description
Load randomly moving part from xml
Definition
loadRandomlyMovingPartFromXML(table part, integer xmlFile, string key)
Arguments
tablepartpart
integerxmlFileid of xml object
stringkeykey
Return Values
booleansuccess
Code
115function RandomlyMovingParts:loadRandomlyMovingPartFromXML(part, xmlFile, key)
116 if not self.xmlFile:hasProperty(key) then
117 return false
118 end
119
120 local isRotAxisValid = function(value)
121 return value ~= nil and value >= 1 and value <= 3
122 end
123
124 XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. "#index", key .. "#node") --FS17 to FS19
125
126 local node = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
127 if node == nil then
128 Logging.xmlWarning(self.xmlFile, "Unknown node for randomlyMovingPart in '%s'", key)
129 return false
130 end
131
132 part.node = node
133
134 if self.getGroundReferenceNodeFromIndex ~= nil then
135 local refNodeIndex = xmlFile:getValue(key .. "#refNodeIndex")
136 if refNodeIndex ~= nil then
137 if refNodeIndex ~= 0 then
138 local groundReferenceNode = self:getGroundReferenceNodeFromIndex(refNodeIndex)
139 if groundReferenceNode ~= nil then
140 part.groundReferenceNode = groundReferenceNode
141 end
142 else
143 Logging.xmlWarning(self.xmlFile, "Unknown ground reference node in '%s'! Indices start with '0'", key.."#refNodeIndex")
144 end
145 end
146 end
147
148 local rx, ry, rz = getRotation(part.node)
149 local rotMean = xmlFile:getValue(key .. "#rotMean", nil, true)
150 if rotMean then
151 part.rotOrig = {rx, ry, rz}
152 part.rotCur = {rx, ry, rz}
153
154 part.rotAxis = xmlFile:getValue(key .. "#rotAxis")
155 if not isRotAxisValid(part.rotAxis) then
156 Logging.xmlWarning(xmlFile, "Invalid rot axis '%s' given for node '%s'. Only '1', '2' or '3' are allowed!", part.rotAxis, key)
157 return false
158 end
159
160 part.rotMean = rotMean
161 part.rotVar = xmlFile:getValue(key .. "#rotVariance", nil, true)
162
163 part.rotTimeMean = xmlFile:getValue(key .. "#rotTimeMean", nil, true)
164 part.rotTimeVar = xmlFile:getValue(key .. "#rotTimeVariance", nil, true)
165
166 part.pauseMean = xmlFile:getValue(key .. "#pauseMean", nil, true)
167 part.pauseVar = xmlFile:getValue(key .. "#pauseVariance", nil, true)
168
169 for i=1,2 do
170 part.rotTimeMean[i] = part.rotTimeMean[i] * 1000
171 part.rotTimeVar[i] = part.rotTimeVar[i] * 1000
172 part.pauseMean[i] = part.pauseMean[i] * 1000
173 part.pauseVar[i] = part.pauseVar[i] * 1000
174 end
175
176 part.rotTarget = {}
177 part.rotSpeed = {}
178 part.pause = {}
179
180 part.isSpeedDependent = xmlFile:getValue(key .. "#isSpeedDependent", false)
181
182 self:updateRotationTargetValues(part)
183 end
184
185 part.nodes = {}
186 xmlFile:iterate(key .. ".node", function(index, nodeKey)
187 local entry = {}
188 entry.node = xmlFile:getValue(nodeKey .. "#node", nil, self.components, self.i3dMappings)
189 if entry.node ~= nil then
190 entry.rotAxis = xmlFile:getValue(nodeKey .. "#rotAxis")
191 if entry.rotAxis ~= nil then
192 if not isRotAxisValid(entry.rotAxis) then
193 Logging.xmlWarning(xmlFile, "Invalid rot axis '%s' given for node '%s'. Only '1', '2' or '3' are allowed!", entry.rotAxis, nodeKey)
194 return
195 else
196 entry.currentRot = {getRotation(entry.node)}
197 end
198 end
199
200 entry.scale = xmlFile:getValue(nodeKey .. "#scale", 1)
201
202 table.insert(part.nodes, entry)
203 end
204 end)
205
206 part.nextMoveTime = g_currentMission.time + part.pause[2]
207 part.curMoveDirection = 1
208 part.isActive = true
209
210 return true
211end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
69function RandomlyMovingParts:onLoad(savegame)
70 local spec = self.spec_randomlyMovingParts
71
72 spec.maxUpdateDistance = self.xmlFile:getValue("vehicle.randomlyMovingParts#maxUpdateDistance", RandomlyMovingParts.DEFAULT_MAX_UPDATE_DISTANCE)
73
74 spec.nodes = {}
75 local i = 0
76 while true do
77 local baseName = string.format("vehicle.randomlyMovingParts.randomlyMovingPart(%d)", i)
78 if not self.xmlFile:hasProperty(baseName) then
79 break
80 end
81
82 local randomlyMovingPart = {}
83 if self:loadRandomlyMovingPartFromXML(randomlyMovingPart, self.xmlFile, baseName) then
84 table.insert(spec.nodes, randomlyMovingPart)
85 end
86
87 i = i + 1
88 end
89
90 if not self.isClient or #spec.nodes == 0 then
91 SpecializationUtil.removeEventListener(self, "onUpdate", RandomlyMovingParts)
92 end
93end

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
100function RandomlyMovingParts:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
101 local spec = self.spec_randomlyMovingParts
102 if self.currentUpdateDistance < spec.maxUpdateDistance then
103 for _, part in pairs(spec.nodes) do
104 self:updateRandomlyMovingPart(part, dt)
105 end
106 end
107end

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 RandomlyMovingParts.prerequisitesPresent(specializations)
21 return true
22end

registerEventListeners

Description
Definition
registerEventListeners()
Code
61function RandomlyMovingParts.registerEventListeners(vehicleType)
62 SpecializationUtil.registerEventListener(vehicleType, "onLoad", RandomlyMovingParts)
63 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", RandomlyMovingParts)
64end

registerFunctions

Description
Definition
registerFunctions()
Code
52function RandomlyMovingParts.registerFunctions(vehicleType)
53 SpecializationUtil.registerFunction(vehicleType, "loadRandomlyMovingPartFromXML", RandomlyMovingParts.loadRandomlyMovingPartFromXML)
54 SpecializationUtil.registerFunction(vehicleType, "updateRandomlyMovingPart", RandomlyMovingParts.updateRandomlyMovingPart)
55 SpecializationUtil.registerFunction(vehicleType, "updateRotationTargetValues", RandomlyMovingParts.updateRotationTargetValues)
56 SpecializationUtil.registerFunction(vehicleType, "getIsRandomlyMovingPartActive", RandomlyMovingParts.getIsRandomlyMovingPartActive)
57end

updateRandomlyMovingPart

Description
Update randomly moving parts
Definition
updateRandomlyMovingPart(table part, float dt)
Arguments
tablepartpart to update
floatdttime since last call in ms
Return Values
booleanupdatedpart was updated
Code
218function RandomlyMovingParts:updateRandomlyMovingPart(part, dt)
219 if part.nextMoveTime < g_currentMission.time then
220 local speed = dt
221 if part.isSpeedDependent then
222 speed = speed * math.min(self:getLastSpeed() / self:getRawSpeedLimit(), 1)
223 end
224
225 part.isActive = self:getIsRandomlyMovingPartActive(part)
226 if part.curMoveDirection > 0 then
227 if part.isActive then
228 part.rotCur[part.rotAxis] = math.min(part.rotTarget[1], part.rotCur[part.rotAxis] + (part.rotSpeed[1] * speed))
229 if part.rotCur[part.rotAxis] == part.rotTarget[1] then
230 part.curMoveDirection = -1
231 part.nextMoveTime = g_currentMission.time + part.pause[1]
232 end
233 end
234 else
235 part.rotCur[part.rotAxis] = math.max(part.rotTarget[2], part.rotCur[part.rotAxis] + (part.rotSpeed[2] * speed))
236 if part.rotCur[part.rotAxis] == part.rotTarget[2] then
237 -- start next movement only if active
238 if part.isActive then
239 part.curMoveDirection = 1
240 part.nextMoveTime = g_currentMission.time + part.pause[2]
241 self:updateRotationTargetValues(part)
242 end
243 end
244 end
245
246 setRotation(part.node, part.rotCur[1], part.rotCur[2], part.rotCur[3])
247
248 for i=1, #part.nodes do
249 local nodeData = part.nodes[i]
250 if nodeData.rotAxis ~= nil then
251 nodeData.currentRot[nodeData.rotAxis] = part.rotCur[part.rotAxis] * nodeData.scale
252 setRotation(nodeData.node, nodeData.currentRot[1], nodeData.currentRot[2], nodeData.currentRot[3])
253 else
254 setRotation(nodeData.node, part.rotCur[1] * nodeData.scale, part.rotCur[2] * nodeData.scale, part.rotCur[3] * nodeData.scale)
255 end
256 end
257
258 if self.setMovingToolDirty ~= nil then
259 self:setMovingToolDirty(part.node)
260 end
261
262 return true
263 else
264 return false
265 end
266end

updateRotationTargetValues

Description
Update rotation target values
Definition
updateRotationTargetValues(table part)
Arguments
tablepartpart to update
Code
271function RandomlyMovingParts:updateRotationTargetValues(part)
272 for i=1,2 do
273 part.rotTarget[i] = part.rotMean[i] + (part.rotVar[i] * (-0.5 + math.random()))
274 end
275
276 for i=1,2 do
277 local rotTime = part.rotTimeMean[i] + (part.rotTimeVar[i] * (-0.5 + math.random()))
278 if i == 1 then
279 part.rotSpeed[i] = (part.rotTarget[1] - part.rotTarget[2]) / rotTime
280 else
281 part.rotSpeed[i] = (part.rotTarget[2] - part.rotTarget[1]) / rotTime
282 end
283 end
284
285 for i=1,2 do
286 part.pause[i] = part.pauseMean[i] + (part.pauseVar[i] * (-0.5 + math.random()))
287 end
288end