26 | function 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() |
48 | end |
115 | function 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 |
211 | end |
218 | function 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 |
266 | end |