Script v1.4.4.0
Engine v7.0.0.2
- General
- Entity
- Node
- Scenegraph
- Lighting
- Camera
- Shape
- Particle System
- Physics
- Spline
- Animation
- Overlays
- Sound
- Input
- XML
- Network
- Callbacks
- Text Rendering
- Terrain Detail
- Tire Track
- Editor
- Rendering
- String
- Math
- I3D
- Fillplanes
Foundation Reference
Cylindered
DescriptionThis is the specialization for vehicles which have movable partsFunctions
- prerequisitesPresent
- preLoad
- load
- postLoad
- delete
- readStream
- writeStream
- readUpdateStream
- writeUpdateStream
- loadDependentMovingTools
- loadDependentParts
- loadComponentJoints
- loadAttacherJoints
- loadTranslatingParts
- loadCopyLocalDirectionParts
- getSaveAttributesAndNodes
- update
- draw
- setToolTranslation
- setDelayedNodeTranslation
- setToolRotation
- setDelayedNodeRotation
- setToolAnimation
- getMovingToolState
- setMovingToolDirty
- setDirty
- updateWheels
- updateMovingPart
- updateComponentJoints
- updateAttacherJoints
- updateCylinderedInitial
- onAttach
- onDeactivateSounds
- isDetachAllowed
- setActiveControlGroup
- getNextValidControlGroupIndex
- getIsControlGroupChangeAllowed
- loadObjectChangeValuesFromXML
- setObjectChangeValues
- allowLoadMovingToolStates
prerequisitesPresent
DescriptionChecks if all prerequisite specializations are loadedDefinition
prerequisitesPresent(table specializations)Arguments
table | specializations | specializations |
boolean | hasPrerequisite | true if all prerequisite specializations are loaded |
17 | function Cylindered.prerequisitesPresent(specializations) |
18 | return SpecializationUtil.hasSpecialization(AttacherJoints, specializations); |
19 | end |
preLoad
DescriptionCalled before loadingDefinition
preLoad(table savegame)Arguments
table | savegame | savegame |
24 | function Cylindered:preLoad(savegame) |
25 | self.loadObjectChangeValuesFromXML = Utils.overwrittenFunction(self.loadObjectChangeValuesFromXML, Cylindered.loadObjectChangeValuesFromXML) |
26 | self.setObjectChangeValues = Utils.overwrittenFunction(self.setObjectChangeValues, Cylindered.setObjectChangeValues) |
27 | self.allowLoadMovingToolStates = Utils.overwrittenFunction(self.allowLoadMovingToolStates, Cylindered.allowLoadMovingToolStates) |
28 | end |
load
DescriptionCalled on loadingDefinition
load(table savegame)Arguments
table | savegame | savegame |
33 | function Cylindered:load(savegame) |
34 | |
35 | self.setMovingToolDirty = SpecializationUtil.callSpecializationsFunction("setMovingToolDirty"); |
36 | self.updateCylinderedInitial = SpecializationUtil.callSpecializationsFunction("updateCylinderedInitial"); |
37 | self.isDetachAllowed = Utils.overwrittenFunction(self.isDetachAllowed, Cylindered.isDetachAllowed); |
38 | |
39 | self.setActiveControlGroup = Cylindered.setActiveControlGroup; |
40 | self.getNextValidControlGroupIndex = Cylindered.getNextValidControlGroupIndex; |
41 | self.getIsControlGroupChangeAllowed = Cylindered.getIsControlGroupChangeAllowed; |
42 | |
43 | if self.isClient then |
44 | self.sampleCylinderedHydraulic = SoundUtil.loadSample(self.xmlFile, {}, "vehicle.cylinderedHydraulicSound", nil, self.baseDirectory); |
45 | end |
46 | |
47 | local uiScale = g_gameSettings:getValue("uiScale") |
48 | |
49 | self.activeDirtyMovingParts = {}; |
50 | |
51 | if hasXMLProperty(self.xmlFile, "vehicle.mouseControls") then |
52 | print("Warning: 'vehicle.mouseControls' are not supported anymore. Use 'vehicle.movingTools.movingTool.controls#iconFilename' instead!") |
53 | end |
54 | |
55 | local referenceNodes = {}; |
56 | self.nodesToMovingParts = {}; |
57 | self.movingParts = {}; |
58 | self.detachLockNodes = nil; |
59 | local i=0; |
60 | while true do |
61 | local baseName = string.format("vehicle.movingParts.movingPart(%d)", i); |
62 | if not hasXMLProperty(self.xmlFile, baseName) then |
63 | break; |
64 | end |
65 | |
66 | local node = Utils.indexToObject(self.components, getXMLString(self.xmlFile, baseName.."#index")); |
67 | local referenceFrame = Utils.indexToObject(self.components, getXMLString(self.xmlFile, baseName.."#referenceFrame")); |
68 | if node ~= nil and referenceFrame ~= nil then |
69 | local entry = {}; |
70 | entry.referencePoint = Utils.indexToObject(self.components, getXMLString(self.xmlFile, baseName.."#referencePoint")); |
71 | entry.node = node; |
72 | entry.referenceFrame = referenceFrame; |
73 | entry.invertZ = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#invertZ"), false); |
74 | entry.scaleZ = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#scaleZ"), false); |
75 | entry.limitedAxis = getXMLInt(self.xmlFile, baseName.."#limitedAxis"); |
76 | local isActiveDirty = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#isActiveDirty"), false); |
77 | entry.playSound = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#playSound"), false) |
78 | |
79 | entry.moveToReferenceFrame = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#moveToReferenceFrame"), false); |
80 | if entry.moveToReferenceFrame then |
81 | local x,y,z = worldToLocal(referenceFrame, getWorldTranslation(node)); |
82 | entry.referenceFrameOffset = {x,y,z}; |
83 | end |
84 | |
85 | entry.doDirectionAlignment = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#doDirectionAlignment"), true); |
86 | entry.doRotationAlignment = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#doRotationAlignment"), false); |
87 | entry.rotMultiplier = Utils.getNoNil(getXMLFloat(self.xmlFile, baseName.."#rotMultiplier"), 0) |
88 | |
89 | local minRot = getXMLFloat(self.xmlFile, baseName.."#minRot"); |
90 | local maxRot = getXMLFloat(self.xmlFile, baseName.."#maxRot"); |
91 | if minRot ~= nil and maxRot ~= nil then |
92 | if entry.limitedAxis ~= nil then |
93 | entry.minRot = Utils.getValidLimit(math.rad(minRot)); |
94 | entry.maxRot = Utils.getValidLimit(math.rad(maxRot)); |
95 | else |
96 | print("Warning: minRot/maxRot requires the use of limitedAxis in '"..self.configFileName.."'"); |
97 | end |
98 | end |
99 | entry.alignToWorldY = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#alignToWorldY"), false); |
100 | |
101 | if entry.referencePoint ~= nil then |
102 | local localReferencePoint = Utils.indexToObject(self.components, getXMLString(self.xmlFile, baseName.."#localReferencePoint")); |
103 | local refX, refY, refZ = worldToLocal(node, getWorldTranslation(entry.referencePoint)); |
104 | if localReferencePoint ~= nil then |
105 | local x,y,z = worldToLocal(node, getWorldTranslation(localReferencePoint)); |
106 | |
107 | entry.referenceDistance = Utils.vector3Length(refX-x, refY-y, refZ-z); |
108 | entry.localReferencePoint = {x, y, z}; |
109 | |
110 | local side = y*(refZ-z) - z*(refY-y); |
111 | entry.localReferenceAngleSide = side; |
112 | entry.localReferencePointNode = localReferencePoint; |
113 | entry.updateLocalReferenceDistance = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#updateLocalReferenceDistance"), false); |
114 | entry.localReferenceTranslate = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#localReferenceTranslate"), false); |
115 | if entry.localReferenceTranslate then |
116 | entry.localReferenceTranslation = { getTranslation(entry.node) }; |
117 | end |
118 | else |
119 | entry.referenceDistance = 0; |
120 | entry.localReferencePoint = {refX, refY, refZ}; |
121 | end |
122 | entry.useLocalOffset = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#useLocalOffset"), false); |
123 | |
124 | entry.localReferenceDistance = Utils.vector2Length(entry.localReferencePoint[2], entry.localReferencePoint[3]); |
125 | |
126 | Cylindered.loadTranslatingParts(self, self.xmlFile, baseName, entry); |
127 | |
128 | end |
129 | entry.isDirty = false; |
130 | |
131 | |
132 | if referenceNodes[node] == nil then |
133 | referenceNodes[node] = {}; |
134 | end |
135 | table.insert(referenceNodes[node], entry); |
136 | |
137 | Cylindered.loadDependentParts(self, self.xmlFile, baseName, entry); |
138 | |
139 | Cylindered.loadComponentJoints(self, self.xmlFile, baseName, entry); |
140 | Cylindered.loadAttacherJoints(self, self.xmlFile, baseName, entry); |
141 | |
142 | Cylindered.loadCopyLocalDirectionParts(self, self.xmlFile, baseName, entry); |
143 | |
144 | table.insert(self.movingParts, entry); |
145 | |
146 | if isActiveDirty then |
147 | table.insert(self.activeDirtyMovingParts, entry); |
148 | end |
149 | |
150 | self.nodesToMovingParts[node] = entry; |
151 | end |
152 | i = i+1; |
153 | end |
154 | |
155 | self.isActiveDirtyTimeOffset = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.movingParts#isActiveDirtyTimeOffset"), 0) * 1000; |
156 | self.isActiveDirtyTime = g_currentMission.time; |
157 | |
158 | -- find dependencies |
159 | for _, part in pairs(self.movingParts) do |
160 | part.dependentParts = {}; |
161 | for _, ref in pairs(part.dependentPartNodes) do |
162 | if referenceNodes[ref] ~= nil then |
163 | for _, p in pairs(referenceNodes[ref]) do |
164 | part.dependentParts[p] = p; |
165 | end |
166 | end |
167 | end |
168 | end |
169 | |
170 | |
171 | function hasDependentPart(w1, w2) |
172 | if w1.dependentParts[w2] ~= nil then |
173 | return true; |
174 | else |
175 | for _, v in pairs(w1.dependentParts) do |
176 | if hasDependentPart(v, w2) then |
177 | return true; |
178 | end |
179 | end |
180 | end |
181 | return false; |
182 | end |
183 | |
184 | -- sort moving parts by dependencies |
185 | function movingPartsSort(w1,w2) |
186 | if hasDependentPart(w1, w2) then |
187 | return true; |
188 | end |
189 | if not hasDependentPart(w2, w1) then |
190 | return w1.node < w2.node; |
191 | end |
192 | return false; |
193 | end |
194 | |
195 | table.sort(self.movingParts, movingPartsSort); |
196 | |
197 | self.nodesToMovingTools = {}; |
198 | self.movingTools = {}; |
199 | self.controlGroups = {}; |
200 | local i=0; |
201 | while true do |
202 | local baseName = string.format("vehicle.movingTools.movingTool(%d)", i); |
203 | if not hasXMLProperty(self.xmlFile, baseName) then |
204 | break; |
205 | end |
206 | local node = Utils.indexToObject(self.components, getXMLString(self.xmlFile, baseName.."#index")); |
207 | if node ~= nil then |
208 | local entry = {}; |
209 | entry.node = node; |
210 | |
211 | entry.externalRotSpeed = 0; |
212 | entry.externalTransSpeed = 0; |
213 | entry.externalAnimSpeed = 0; |
214 | |
215 | -- rotation |
216 | if getXMLFloat(self.xmlFile, baseName.."#rotSpeed") ~= nil then |
217 | print("Warning: movingTool#rotSpeed in '".. self.configFileName .."' is not supported anymore. Use movingTool.rotation#rotSpeed instead."); |
218 | end |
219 | local rotSpeed = getXMLFloat(self.xmlFile, baseName..".rotation#rotSpeed"); |
220 | if rotSpeed ~= nil then |
221 | entry.rotSpeed = math.rad(rotSpeed)/1000; |
222 | end |
223 | local rotAcceleration = getXMLFloat(self.xmlFile, baseName..".rotation#rotAcceleration"); |
224 | if rotAcceleration ~= nil then |
225 | entry.rotAcceleration = math.rad(rotAcceleration)/(1000*1000); |
226 | end |
227 | entry.lastRotSpeed = 0; |
228 | local rotMax = getXMLFloat(self.xmlFile, baseName..".rotation#rotMax"); |
229 | if rotMax ~= nil then |
230 | entry.rotMax = math.rad(rotMax); |
231 | end |
232 | local rotMin = getXMLFloat(self.xmlFile, baseName..".rotation#rotMin"); |
233 | if rotMin ~= nil then |
234 | entry.rotMin = math.rad(rotMin); |
235 | end |
236 | entry.syncMaxRotLimits = Utils.getNoNil(getXMLBool(self.xmlFile, baseName..".rotation#syncMaxRotLimits"), false); |
237 | entry.syncMinRotLimits = Utils.getNoNil(getXMLBool(self.xmlFile, baseName..".rotation#syncMinRotLimits"), false); |
238 | entry.rotSendNumBits = Utils.getNoNil(getXMLInt(self.xmlFile, baseName..".rotation#rotSendNumBits"), 8); |
239 | local attachRotMax = getXMLFloat(self.xmlFile, baseName..".rotation#attachRotMax"); |
240 | if attachRotMax ~= nil then |
241 | entry.attachRotMax = math.rad(attachRotMax); |
242 | end |
243 | local attachRotMin = getXMLFloat(self.xmlFile, baseName..".rotation#attachRotMin"); |
244 | if attachRotMin ~= nil then |
245 | entry.attachRotMin = math.rad(attachRotMin); |
246 | end |
247 | |
248 | -- translation |
249 | if getXMLFloat(self.xmlFile, baseName.."#transSpeed") ~= nil then |
250 | print("Warning: movingTool#transSpeed in '" .. self.configFileName .. "' is not supported anymore. Use movingTool.translation#transSpeed instead."); |
251 | end |
252 | local transSpeed = getXMLFloat(self.xmlFile, baseName..".translation#transSpeed"); |
253 | if transSpeed ~= nil then |
254 | entry.transSpeed = transSpeed/1000; |
255 | end |
256 | local transAcceleration = getXMLFloat(self.xmlFile, baseName..".translation#transAcceleration"); |
257 | if transAcceleration ~= nil then |
258 | entry.transAcceleration = transAcceleration/(1000*1000); |
259 | end |
260 | entry.lastTransSpeed = 0; |
261 | entry.transMax = Utils.getNoNil(getXMLFloat(self.xmlFile, baseName..".translation#transMax"), 1); |
262 | entry.transMin = Utils.getNoNil(getXMLFloat(self.xmlFile, baseName..".translation#transMin"), 0); |
263 | entry.transSendNumBits = Utils.getNoNil(getXMLInt(self.xmlFile, baseName..".translation#transSendNumBits"), 8); |
264 | entry.attachTransMax = getXMLFloat(self.xmlFile, baseName..".translation#attachTransMax"); |
265 | entry.attachTransMin = getXMLFloat(self.xmlFile, baseName..".translation#attachTransMin"); |
266 | entry.playSound = Utils.getNoNil(getXMLBool(self.xmlFile, baseName.."#playSound"), false) |
267 | |
268 | -- animation |
269 | if SpecializationUtil.hasSpecialization(AnimatedVehicle, self.specializations) then |
270 | local animSpeed = getXMLFloat(self.xmlFile, baseName..".animation#animSpeed"); |
271 | if animSpeed ~= nil then |
272 | entry.animSpeed = animSpeed / 1000; |
273 | end |
274 | local animAcceleration = getXMLFloat(self.xmlFile, baseName..".animation#animAcceleration"); |
275 | if animAcceleration ~= nil then |
276 | entry.animAcceleration = animAcceleration / (1000*1000); |
277 | end |
278 | entry.curAnimTime = 0; |
279 | entry.lastAnimSpeed = 0; |
280 | entry.animName = getXMLString(self.xmlFile, baseName..".animation#animName"); |
281 | entry.animSendNumBits = Utils.getNoNil(getXMLInt(self.xmlFile, baseName..".animation#animSendNumBits"), 8); |
282 | entry.animMaxTime = math.min(Utils.getNoNil(getXMLFloat(self.xmlFile, baseName..".animation#animMaxTime"), 1.0), 1.0); |
283 | entry.animMinTime = math.max(Utils.getNoNil(getXMLFloat(self.xmlFile, baseName..".animation#animMinTime"), 0.0), 0.0); |
284 | |
285 | local animStartTime = getXMLFloat(self.xmlFile, baseName..".animation#animStartTime"); |
286 | if animStartTime ~= nil then |
287 | entry.curAnimTime = animStartTime; |
288 | self:setAnimationTime(entry.animName, animStartTime); |
289 | end |
290 | end |
291 | |
292 | -- |
293 | local iconFilename = getXMLString(self.xmlFile, baseName..".controls#iconFilename") |
294 | if iconFilename ~= nil then |
295 | iconFilename = Utils.getFilename(iconFilename, self.baseDirectory); |
296 | local iconWidth, iconHeight = getNormalizedScreenValues(40*uiScale, 40*uiScale); |
297 | entry.icon = Overlay:new("axisIcon", iconFilename, 0, 0, iconWidth, iconHeight); |
298 | entry.icon:setAlignment(Overlay.ALIGN_VERTICAL_MIDDLE, Overlay.ALIGN_HORIZONTAL_LEFT); |
299 | end |
300 | |
301 | local groupName = getXMLString(self.xmlFile, baseName .. ".controls#group"); |
302 | if groupName ~= nil then |
303 | entry.groupName = groupName; |
304 | local foundGroup = false; |
305 | for _,group in pairs(self.controlGroups) do |
306 | if group.groupName == groupName then |
307 | foundGroup = true; |
308 | break; |
309 | end |
310 | end |
311 | if not foundGroup then |
312 | local groupEntry = {}; |
313 | groupEntry.groupName = groupName; |
314 | |
315 | groupEntry.l10nName = groupName; |
316 | |
317 | local l10nName = getXMLString(self.xmlFile, baseName .. ".controls#l10nName"); |
318 | if l10nName ~= nil then |
319 | groupEntry.l10nName = g_i18n:getText(l10nName); |
320 | end |
321 | |
322 | table.insert(self.controlGroups, groupEntry); |
323 | end |
324 | end |
325 | |
326 | entry.axis = getXMLString(self.xmlFile, baseName..".controls#axis"); |
327 | if entry.axis ~= nil then |
328 | entry.axisActionIndex = InputBinding[entry.axis]; |
329 | |
330 | if entry.axisActionIndex ~= nil then |
331 | self:addConflictCheckedInput(entry.axisActionIndex); |
332 | end |
333 | end |
334 | entry.invertAxis = Utils.getNoNil(getXMLBool(self.xmlFile, baseName..".controls#invertAxis"), false); |
335 | entry.mouseSpeedFactor = Utils.getNoNil(getXMLFloat(self.xmlFile, baseName..".controls#mouseSpeedFactor"), 1.0); |
336 | entry.isDirty = false; |
337 | |
338 | entry.freezingPipeStates = { Utils.getVectorFromString(getXMLString(self.xmlFile, baseName.."#freezingPipeStates")) }; |
339 | entry.isFreezed = false; |
340 | |
341 | entry.rotationAxis = Utils.getNoNil(getXMLInt(self.xmlFile, baseName..".rotation#rotationAxis"), 1); |
342 | entry.translationAxis = Utils.getNoNil(getXMLInt(self.xmlFile, baseName..".translation#translationAxis"), 3); |
343 | |
344 | entry.foldMinLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, baseName .. "#foldMinLimit"), 0); |
345 | entry.foldMaxLimit = Utils.getNoNil(getXMLFloat(self.xmlFile, baseName .. "#foldMaxLimit"), 1); |
346 | |
347 | local detachingRotMaxLimit = getXMLFloat(self.xmlFile, baseName..".rotation#detachingRotMaxLimit"); |
348 | local detachingRotMinLimit = getXMLFloat(self.xmlFile, baseName..".rotation#detachingRotMinLimit"); |
349 | local detachingTransMaxLimit = getXMLFloat(self.xmlFile, baseName..".translation#detachingTransMaxLimit"); |
350 | local detachingTransMinLimit = getXMLFloat(self.xmlFile, baseName..".translation#detachingTransMinLimit"); |
351 | if detachingRotMaxLimit ~= nil or detachingRotMinLimit ~= nil or detachingTransMaxLimit ~= nil or detachingTransMinLimit ~= nil then |
352 | if self.detachLockNodes == nil then |
353 | self.detachLockNodes = {}; |
354 | end |
355 | |
356 | local detachLock = {}; |
357 | if detachingRotMaxLimit ~= nil then |
358 | detachLock.detachingRotMaxLimit = math.rad(detachingRotMaxLimit); |
359 | end |
360 | if detachingRotMinLimit ~= nil then |
361 | detachLock.detachingRotMinLimit = math.rad(detachingRotMinLimit); |
362 | end |
363 | detachLock.detachingTransMaxLimit = detachingTransMaxLimit; |
364 | detachLock.detachingTransMaxLimit = detachingTransMaxLimit; |
365 | |
366 | self.detachLockNodes[entry] = detachLock; |
367 | end |
368 | |
369 | |
370 | local rx,ry,rz = getRotation(node); |
371 | entry.curRot = {rx,ry,rz}; |
372 | local x,y,z = getTranslation(node); |
373 | entry.curTrans = {x,y,z}; |
374 | |
375 | entry.startRot = getXMLFloat(self.xmlFile, baseName..".rotation#startRot"); |
376 | if entry.startRot ~= nil then |
377 | entry.startRot = math.rad(entry.startRot); |
378 | end |
379 | entry.startTrans = getXMLFloat(self.xmlFile, baseName..".translation#startTrans"); |
380 | |
381 | -- |
382 | entry.delayedNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, baseName.."#delayedIndex")); |
383 | if entry.delayedNode ~= nil then |
384 | entry.curDelayedRot = {rx,ry,rz}; |
385 | entry.curDelayedRot[entry.rotationAxis] = Utils.getNoNil(entry.startRot, entry.curDelayedRot[entry.rotationAxis]); |
386 | entry.rotHistory = {entry.curDelayedRot[entry.rotationAxis], entry.curDelayedRot[entry.rotationAxis]}; |
387 | entry.curDelayedTrans = {x,y,z}; |
388 | entry.curDelayedTrans[entry.translationAxis] = Utils.getNoNil(entry.startTrans, entry.curDelayedTrans[entry.translationAxis]); |
389 | entry.transHistory = {entry.curDelayedTrans[entry.translationAxis], entry.curDelayedTrans[entry.translationAxis]}; |
390 | entry.delayedUpdates = 0; |
391 | end |
392 | |
393 | |
394 | if referenceNodes[node] == nil then |
395 | referenceNodes[node] = {}; |
396 | end |
397 | table.insert(referenceNodes[node], entry); |
398 | |
399 | local indices = Utils.getVectorNFromString(getXMLString(self.xmlFile, baseName.. "#wheelIndices")); |
400 | if indices ~= nil then |
401 | local wheels = {}; |
402 | for _,wheelIndex in pairs(indices) do |
403 | local wheel = self.wheels[wheelIndex]; |
404 | if wheel ~= nil then |
405 | table.insert(wheels, wheel); |
406 | else |
407 | print("Warning: Invalid wheelIndex '"..wheelIndex.."' in '"..self.configFileName.."'"); |
408 | end |
409 | end |
410 | if table.getn(wheels) > 0 then |
411 | entry.wheels = wheels; |
412 | end |
413 | end |
414 | |
415 | Cylindered.loadDependentMovingTools(self, self.xmlFile, baseName, entry); |
416 | |
417 | Cylindered.loadDependentParts(self, self.xmlFile, baseName, entry); |
418 | |
419 | Cylindered.loadComponentJoints(self, self.xmlFile, baseName, entry); |
420 | Cylindered.loadAttacherJoints(self, self.xmlFile, baseName, entry); |
421 | |
422 | entry.isActive = true; |
423 | table.insert(self.movingTools, entry); |
424 | self.nodesToMovingTools[node] = entry; |
425 | end |
426 | i = i+1; |
427 | end |
428 | |
429 | self.activeControlGroupIndex = 1; |
430 | self.numControlGroups = table.getn(self.controlGroups); |
431 | if self.numControlGroups then |
432 | self:setActiveControlGroup(self.activeControlGroupIndex); |
433 | end |
434 | |
435 | for _, part in pairs(self.movingTools) do |
436 | part.dependentParts = {}; |
437 | for _, ref in pairs(part.dependentPartNodes) do |
438 | if referenceNodes[ref] ~= nil then |
439 | for _, p in pairs(referenceNodes[ref]) do |
440 | part.dependentParts[p] = p; |
441 | end |
442 | end |
443 | end |
444 | for _, dependentTool in pairs(part.dependentMovingTools) do |
445 | dependentTool.movingTool = self.nodesToMovingTools[dependentTool.node]; |
446 | end |
447 | end |
448 | |
449 | for _, tool in pairs(self.movingTools) do |
450 | if tool.startRot ~= nil then |
451 | tool.curRot[tool.rotationAxis] = tool.startRot; |
452 | setRotation(tool.node, unpack(tool.curRot)); |
453 | if tool.delayedNode ~= nil then |
454 | Cylindered.setDelayedNodeRotation(self, tool); |
455 | end |
456 | end |
457 | if tool.startTrans ~= nil then |
458 | tool.curTrans[tool.translationAxis] = tool.startTrans; |
459 | setTranslation(tool.node, unpack(tool.curTrans)); |
460 | if tool.delayedNode ~= nil then |
461 | Cylindered.setDelayedNodeTranslation(self, tool); |
462 | end |
463 | end |
464 | Cylindered.setDirty(self, tool); |
465 | end |
466 | |
467 | self.cylinderedDirtyFlag = self:getNextDirtyFlag(); |
468 | |
469 | for _, tool in pairs(self.movingTools) do |
470 | if (tool.rotSpeed ~= nil or tool.transSpeed ~= nil) and tool.axisActionIndex ~= nil then |
471 | self.isSelectable = true; |
472 | break; |
473 | end |
474 | end |
475 | end |
postLoad
DescriptionCalled after loadingDefinition
postLoad(table savegame)Arguments
table | savegame | savegame |
480 | function Cylindered:postLoad(savegame) |
481 | if self:allowLoadMovingToolStates() then |
482 | if savegame ~= nil and not savegame.resetVehicles then |
483 | for i, tool in ipairs(self.movingTools) do |
484 | if tool.axisActionIndex ~= nil then |
485 | local toolKey = savegame.key..string.format(".movingTool%d",i); |
486 | local changed = false; |
487 | if tool.transSpeed ~= nil then |
488 | local newTrans = getXMLFloat(savegame.xmlFile, toolKey.."#translation"); |
489 | if newTrans ~= nil then |
490 | if tool.transMax ~= nil then |
491 | newTrans = math.min(newTrans, tool.transMax); |
492 | end |
493 | if tool.transMin ~= nil then |
494 | newTrans = math.max(newTrans, tool.transMin); |
495 | end |
496 | end |
497 | if newTrans ~= nil and math.abs(newTrans - tool.curTrans[tool.translationAxis]) > 0.0001 then |
498 | tool.curTrans[tool.translationAxis] = newTrans; |
499 | setTranslation(tool.node, unpack(tool.curTrans)); |
500 | if tool.delayedNode ~= nil then |
501 | tool.curDelayedTrans[tool.translationAxis] = newTrans; |
502 | tool.transHistory = {newTrans, newTrans}; |
503 | Cylindered.setDelayedNodeTranslation(self, tool); |
504 | end |
505 | changed = true; |
506 | end |
507 | end |
508 | if tool.rotSpeed ~= nil then |
509 | local newRot = getXMLFloat(savegame.xmlFile, toolKey.."#rotation"); |
510 | if newRot ~= nil then |
511 | if tool.rotMax ~= nil then |
512 | newRot = math.min(newRot, tool.rotMax); |
513 | end |
514 | if tool.rotMin ~= nil then |
515 | newRot = math.max(newRot, tool.rotMin); |
516 | end |
517 | end |
518 | if newRot ~= nil and math.abs(newRot - tool.curRot[tool.rotationAxis]) > 0.0001 then |
519 | tool.curRot[tool.rotationAxis] = newRot; |
520 | setRotation(tool.node, unpack(tool.curRot)); |
521 | if tool.delayedNode ~= nil then |
522 | tool.curDelayedRot[tool.rotationAxis] = newRot; |
523 | tool.rotHistory = {newRot, newRot}; |
524 | Cylindered.setDelayedNodeRotation(self, tool); |
525 | end |
526 | changed = true; |
527 | end |
528 | end |
529 | if tool.animSpeed ~= nil then |
530 | local animTime = getXMLFloat(savegame.xmlFile, toolKey.."#animationTime"); |
531 | if animTime ~= nil then |
532 | if tool.animMinTime ~= nil then |
533 | animTime = math.max(animTime, tool.animMinTime); |
534 | end |
535 | if tool.animMaxTime ~= nil then |
536 | animTime = math.min(animTime, tool.animMaxTime); |
537 | end |
538 | end |
539 | tool.animTimeToSet = animTime; |
540 | end |
541 | if changed then |
542 | Cylindered.setDirty(self, tool); |
543 | end |
544 | end |
545 | end |
546 | |
547 | self:updateCylinderedInitial(false); |
548 | end |
549 | end; |
550 | |
551 | -- force update after loading, e.g. savegame |
552 | self.isActiveDirtyTime = g_currentMission.time + math.max(self.isActiveDirtyTimeOffset, 1000); |
553 | end |
delete
DescriptionCalled on deletingDefinition
delete()Code
557 | function Cylindered:delete() |
558 | if self.isClient then |
559 | SoundUtil.deleteSample(self.sampleCylinderedHydraulic); |
560 | end |
561 | |
562 | for _,movingTool in pairs(self.movingTools) do |
563 | if movingTool.icon ~= nil then |
564 | movingTool.icon:delete() |
565 | movingTool.icon = nil |
566 | end |
567 | end |
568 | end |
readStream
DescriptionCalled on client side on joinDefinition
readStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
574 | function Cylindered:readStream(streamId, connection) |
575 | if self:allowLoadMovingToolStates() then |
576 | if connection:getIsServer() then |
577 | for i=1, table.getn(self.movingTools) do |
578 | local tool = self.movingTools[i]; |
579 | if tool.transSpeed ~= nil then |
580 | local newTrans = streamReadFloat32(streamId); |
581 | tool.curTrans[tool.translationAxis] = newTrans; |
582 | setTranslation(tool.node, unpack(tool.curTrans)); |
583 | end |
584 | if tool.rotSpeed ~= nil then |
585 | local newRot = streamReadFloat32(streamId) |
586 | tool.curRot[tool.rotationAxis] = newRot; |
587 | setRotation(tool.node, unpack(tool.curRot)); |
588 | end |
589 | if tool.animSpeed ~= nil then |
590 | local newAnimTime = streamReadFloat32(streamId); |
591 | tool.curAnimTime = newAnimTime; |
592 | self:setAnimationTime(tool.animName, tool.curAnimTime); |
593 | end |
594 | Cylindered.setDirty(self, tool); |
595 | if tool.delayedNode ~= nil then |
596 | if tool.transSpeed ~= nil then |
597 | tool.transHistory[2] = tool.curTrans[tool.translationAxis]; |
598 | tool.transHistory[1] = tool.curTrans[tool.translationAxis]; |
599 | Cylindered.setDelayedNodeTranslation(self, tool); |
600 | else |
601 | tool.rotHistory[2] = tool.curRot[tool.rotationAxis]; |
602 | tool.rotHistory[1] = tool.curRot[tool.rotationAxis]; |
603 | Cylindered.setDelayedNodeRotation(self, tool); |
604 | end |
605 | end |
606 | end |
607 | end |
608 | end; |
609 | end |
writeStream
DescriptionCalled on server side on joinDefinition
writeStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
615 | function Cylindered:writeStream(streamId, connection) |
616 | if self:allowLoadMovingToolStates() then |
617 | if not connection:getIsServer() then |
618 | for i=1, table.getn(self.movingTools) do |
619 | local tool = self.movingTools[i]; |
620 | if tool.transSpeed ~= nil then |
621 | streamWriteFloat32(streamId, tool.curTrans[tool.translationAxis]); |
622 | end |
623 | if tool.rotSpeed ~= nil then |
624 | streamWriteFloat32(streamId, tool.curRot[tool.rotationAxis]); |
625 | end |
626 | if tool.animSpeed ~= nil then |
627 | streamWriteFloat32(streamId, tool.curAnimTime); |
628 | end |
629 | end |
630 | end |
631 | end; |
632 | end |
readUpdateStream
DescriptionCalled on on updateDefinition
readUpdateStream(integer streamId, integer timestamp, table connection)Arguments
integer | streamId | stream ID |
integer | timestamp | timestamp |
table | connection | connection |
639 | function Cylindered:readUpdateStream(streamId, timestamp, connection) |
640 | local hasUpdate = streamReadBool(streamId); |
641 | if hasUpdate then |
642 | for i=1, table.getn(self.movingTools) do |
643 | local tool = self.movingTools[i]; |
644 | if tool.axisActionIndex ~= nil then |
645 | local changed = false; |
646 | if tool.transSpeed ~= nil then |
647 | local newTrans=Utils.readCompressedRange(streamId, tool.transMin, tool.transMax, tool.transSendNumBits); |
648 | if math.abs(newTrans - tool.curTrans[tool.translationAxis]) > 0.0001 then |
649 | tool.curTrans[tool.translationAxis] = newTrans; |
650 | setTranslation(tool.node, unpack(tool.curTrans)); |
651 | changed = true; |
652 | end |
653 | end |
654 | if tool.rotSpeed ~= nil then |
655 | local newRot; |
656 | if tool.rotMin == nil or tool.rotMax == nil then |
657 | newRot = Utils.readCompressedAngle(streamId); |
658 | else |
659 | if tool.syncMinRotLimits then |
660 | tool.rotMin = streamReadFloat32(streamId); |
661 | end |
662 | if tool.syncMaxRotLimits then |
663 | tool.rotMax = streamReadFloat32(streamId); |
664 | end |
665 | newRot = Utils.readCompressedRange(streamId, tool.rotMin, tool.rotMax, tool.rotSendNumBits); |
666 | end |
667 | if math.abs(newRot - tool.curRot[tool.rotationAxis]) > 0.0001 then |
668 | tool.curRot[tool.rotationAxis] = newRot; |
669 | setRotation(tool.node, unpack(tool.curRot)); |
670 | changed = true; |
671 | end |
672 | end |
673 | if tool.animSpeed ~= nil then |
674 | local newAnimTime = Utils.readCompressedRange(streamId, tool.animMinTime, tool.animMaxTime, tool.animSendNumBits); |
675 | if math.abs(newAnimTime - tool.curAnimTime) > 0.0001 then |
676 | tool.curAnimTime = newAnimTime; |
677 | self:setAnimationTime(tool.animName, newAnimTime); |
678 | changed = true; |
679 | end |
680 | end |
681 | if changed then |
682 | Cylindered.setDirty(self, tool); |
683 | if tool.delayedNode ~= nil then |
684 | tool.delayedUpdates = 2; |
685 | if tool.transSpeed ~= nil then |
686 | Cylindered.setDelayedNodeTranslation(self, tool); |
687 | else |
688 | Cylindered.setDelayedNodeRotation(self, tool); |
689 | end |
690 | end |
691 | end |
692 | end |
693 | end |
694 | if not connection:getIsServer() then |
695 | -- we are on the server, write the data to the clients |
696 | self:raiseDirtyFlags(self.cylinderedDirtyFlag); |
697 | end |
698 | end |
699 | end |
writeUpdateStream
DescriptionCalled on on updateDefinition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)Arguments
integer | streamId | stream ID |
table | connection | connection |
integer | dirtyMask | dirty mask |
706 | function Cylindered:writeUpdateStream(streamId, connection, dirtyMask) |
707 | if bitAND(dirtyMask, self.cylinderedDirtyFlag) ~= 0 and (connection:getIsServer() or connection ~= self:getOwner()) then |
708 | -- either we are on the client, or the target connection is not the owner |
709 | streamWriteBool(streamId, true); |
710 | for i=1, table.getn(self.movingTools) do |
711 | local tool = self.movingTools[i]; |
712 | if tool.axisActionIndex ~= nil then |
713 | if tool.transSpeed ~= nil then |
714 | Utils.writeCompressedRange(streamId, tool.curTrans[tool.translationAxis], tool.transMin, tool.transMax, tool.transSendNumBits); |
715 | end |
716 | if tool.rotSpeed ~= nil then |
717 | local rot = tool.curRot[tool.rotationAxis]; |
718 | if tool.rotMin == nil or tool.rotMax == nil then |
719 | Utils.writeCompressedAngle(streamId, rot); |
720 | else |
721 | if tool.syncMinRotLimits then |
722 | streamWriteFloat32(streamId, tool.rotMin); |
723 | end |
724 | if tool.syncMaxRotLimits then |
725 | streamWriteFloat32(streamId, tool.rotMax); |
726 | end |
727 | Utils.writeCompressedRange(streamId, rot, tool.rotMin, tool.rotMax, tool.rotSendNumBits); |
728 | end |
729 | end |
730 | if tool.animSpeed ~= nil then |
731 | Utils.writeCompressedRange(streamId, tool.curAnimTime, tool.animMinTime, tool.animMaxTime, tool.animSendNumBits); |
732 | end |
733 | end |
734 | end |
735 | else |
736 | streamWriteBool(streamId, false); |
737 | end |
738 | end |
loadDependentMovingTools
DescriptionLoad dependent moving tools from xmlDefinition
loadDependentMovingTools(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
745 | function Cylindered.loadDependentMovingTools(self, xmlFile, baseName, entry) |
746 | entry.dependentMovingTools = {}; |
747 | local j=0; |
748 | while true do |
749 | local refBaseName = baseName..string.format(".dependentMovingTool(%d)", j); |
750 | if not hasXMLProperty(xmlFile, refBaseName) then |
751 | break; |
752 | end |
753 | local node = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#index")); |
754 | local rotSpeedScale = getXMLFloat(xmlFile, refBaseName.."#rotSpeedScale"); |
755 | local transSpeedScale = getXMLFloat(xmlFile, refBaseName.."#transSpeedScale"); |
756 | local minTransLimits = getXMLString(xmlFile, refBaseName.."#minTransLimits") |
757 | local maxTransLimits = getXMLString(xmlFile, refBaseName.."#maxTransLimits") |
758 | local minRotLimits = getXMLString(xmlFile, refBaseName.."#minRotLimits") |
759 | local maxRotLimits = getXMLString(xmlFile, refBaseName.."#maxRotLimits") |
760 | if node ~= nil and (rotSpeedScale ~= nil or transSpeedScale ~= nil or minTransLimits ~= nil or maxTransLimits ~= nil or minRotLimits ~= nil or maxRotLimits ~= nil) then |
761 | local dependentTool = {}; |
762 | dependentTool.node = node; |
763 | dependentTool.rotSpeedScale = rotSpeedScale; |
764 | dependentTool.transSpeedScale = transSpeedScale; |
765 | dependentTool.minTransLimits = Utils.getVectorNFromString(minTransLimits, 2); |
766 | dependentTool.maxTransLimits = Utils.getVectorNFromString(maxTransLimits, 2); |
767 | dependentTool.minRotLimits = Utils.getRadiansFromString(minRotLimits, 2); |
768 | dependentTool.maxRotLimits = Utils.getRadiansFromString(maxRotLimits, 2); |
769 | table.insert(entry.dependentMovingTools, dependentTool); |
770 | end |
771 | |
772 | j = j+1; |
773 | end |
774 | end |
loadDependentParts
DescriptionLoad dependent parts from xmlDefinition
loadDependentParts(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
781 | function Cylindered.loadDependentParts(self, xmlFile, baseName, entry) |
782 | entry.dependentPartNodes = {}; |
783 | local j=0; |
784 | while true do |
785 | local refBaseName = baseName..string.format(".dependentPart(%d)", j); |
786 | if not hasXMLProperty(xmlFile, refBaseName) then |
787 | break; |
788 | end |
789 | local node = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#index")); |
790 | if node ~= nil then |
791 | table.insert(entry.dependentPartNodes, node); |
792 | end |
793 | j = j+1; |
794 | end |
795 | end |
loadComponentJoints
DescriptionLoad component joints from xmlDefinition
loadComponentJoints(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
802 | function Cylindered.loadComponentJoints(self, xmlFile, baseName, entry) |
803 | if not self.isServer then |
804 | return; |
805 | end |
806 | entry.componentJoints = {}; |
807 | |
808 | if getXMLInt(self.xmlFile, baseName.."#componentJointIndex") ~= nil then |
809 | print("Warning: movingTool#componentJointIndex in '".. self.configFileName .."' is not supported anymore. Use movingTool.componentJoint#index instead."); |
810 | end |
811 | if getXMLInt(self.xmlFile, baseName.."#anchorActor") ~= nil then |
812 | print("Warning: movingTool#anchorActor in '".. self.configFileName .."' is not supported anymore. Use movingTool.componentJoint#anchorActor instead."); |
813 | end |
814 | |
815 | local i=0; |
816 | while true do |
817 | local key = baseName .. string.format(".componentJoint(%d)", i); |
818 | if not hasXMLProperty(xmlFile, key) then |
819 | break; |
820 | end |
821 | local index = getXMLInt(xmlFile, key .. "#index"); |
822 | if index ~= nil and self.componentJoints[index+1] ~= nil then |
823 | local anchorActor = Utils.getNoNil(getXMLInt(xmlFile, key.."#anchorActor"), 0); |
824 | |
825 | local componentJoint = self.componentJoints[index+1]; |
826 | |
827 | local jointEntry = {}; |
828 | jointEntry.componentJoint = componentJoint; |
829 | jointEntry.anchorActor = anchorActor; |
830 | |
831 | local node = self.components[componentJoint.componentIndices[((anchorActor+1)%2)+1] ].node; |
832 | jointEntry.x, jointEntry.y, jointEntry.z = localToLocal(node, componentJoint.jointNode, 0,0,0); |
833 | jointEntry.upX, jointEntry.upY, jointEntry.upZ = localDirectionToLocal(node, componentJoint.jointNode, 0,1,0); |
834 | jointEntry.dirX, jointEntry.dirY, jointEntry.dirZ = localDirectionToLocal(node, componentJoint.jointNode, 0,0,1); |
835 | |
836 | table.insert(entry.componentJoints, jointEntry); |
837 | else |
838 | print("Warning: Invalid index for " .. key .. " in file " .. self.configFileName); |
839 | end |
840 | i=i+1; |
841 | end |
842 | end |
loadAttacherJoints
DescriptionLoad attacher joints from xmlDefinition
loadAttacherJoints(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
849 | function Cylindered.loadAttacherJoints(self, xmlFile, baseName, entry) |
850 | if getXMLString(self.xmlFile, baseName.."#jointIndices") ~= nil then |
851 | print("Warning: "..baseName.."#jointIndices in '".. self.configFileName .."' is not supported anymore. Use "..baseName..".attacherJoint#jointIndices instead."); |
852 | end |
853 | |
854 | local indices = Utils.getVectorNFromString(getXMLString(xmlFile, baseName.. ".attacherJoint#jointIndices")); |
855 | |
856 | if indices ~= nil then |
857 | local attacherJoints = {}; |
858 | for i=1, table.getn(indices) do |
859 | local attacherJoint = self.attacherJoints[indices[i]+1]; |
860 | if attacherJoint ~= nil then |
861 | table.insert(attacherJoints, attacherJoint); |
862 | end |
863 | end |
864 | if table.getn(attacherJoints) > 0 then |
865 | entry.attacherJoints = attacherJoints; |
866 | end |
867 | end |
868 | |
869 | if getXMLBool(self.xmlFile, baseName.."#inputAttacherJoint") ~= nil then |
870 | print("Warning: "..baseName.."#inputAttacherJoint in '".. self.configFileName .."' is not supported anymore. Use "..baseName..".inputAttacherJoint#value instead."); |
871 | end |
872 | |
873 | entry.inputAttacherJoint = Utils.getNoNil(getXMLBool(xmlFile, baseName.. ".inputAttacherJoint#value"), false); |
874 | end |
loadTranslatingParts
DescriptionLoad translating partsDefinition
loadTranslatingParts(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
881 | function Cylindered.loadTranslatingParts(self, xmlFile, baseName, entry) |
882 | entry.translatingParts = {}; |
883 | if entry.referencePoint ~= nil then |
884 | local j=0; |
885 | while true do |
886 | local refBaseName = baseName..string.format(".translatingPart(%d)", j); |
887 | if not hasXMLProperty(xmlFile, refBaseName) then |
888 | break; |
889 | end |
890 | local node = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#index")); |
891 | if node ~= nil then |
892 | local transEntry = {}; |
893 | transEntry.node = node; |
894 | local x,y,z = getTranslation(node); |
895 | transEntry.startPos = {x,y,z}; |
896 | local x,y,z = worldToLocal(node, getWorldTranslation(entry.referencePoint)); |
897 | transEntry.referenceDistance = z; |
898 | transEntry.referenceDistancePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#referenceDistancePoint")); |
899 | table.insert(entry.translatingParts, transEntry); |
900 | end |
901 | j = j+1; |
902 | end |
903 | end |
904 | end |
loadCopyLocalDirectionParts
DescriptionLoad copy local direction parts from xmlDefinition
loadCopyLocalDirectionParts(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
911 | function Cylindered.loadCopyLocalDirectionParts(self, xmlFile, baseName, entry) |
912 | entry.copyLocalDirectionParts = {}; |
913 | local j=0; |
914 | while true do |
915 | local refBaseName = baseName..string.format(".copyLocalDirectionPart(%d)", j); |
916 | if not hasXMLProperty(xmlFile, refBaseName) then |
917 | break; |
918 | end |
919 | local node = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#index")); |
920 | if node ~= nil then |
921 | local copyLocalDirectionPart = {}; |
922 | copyLocalDirectionPart.node = node; |
923 | copyLocalDirectionPart.dirScale = Utils.getVectorNFromString(getXMLString(xmlFile, refBaseName.."#dirScale"), 3); |
924 | copyLocalDirectionPart.upScale = Utils.getVectorNFromString(getXMLString(xmlFile, refBaseName.."#upScale"), 3); |
925 | |
926 | Cylindered.loadComponentJoints(self, xmlFile, refBaseName, copyLocalDirectionPart); |
927 | |
928 | table.insert(entry.copyLocalDirectionParts, copyLocalDirectionPart); |
929 | end |
930 | j = j + 1; |
931 | end |
932 | end |
getSaveAttributesAndNodes
DescriptionReturns attributes and nodes to saveDefinition
getSaveAttributesAndNodes(table nodeIdent)Arguments
table | nodeIdent | node ident |
string | attributes | attributes |
string | nodes | nodes |
939 | function Cylindered:getSaveAttributesAndNodes(nodeIdent) |
940 | local attributes = ""; |
941 | local nodes = ""; |
942 | local numNodes = 0; |
943 | for i, tool in ipairs(self.movingTools) do |
944 | if tool.axisActionIndex ~= nil and (tool.transSpeed ~= nil or tool.rotSpeed ~= nil or tool.animSpeed ~= nil) then |
945 | if numNodes > 0 then |
946 | nodes = nodes.."\n"; |
947 | end |
948 | numNodes = numNodes + 1; |
949 | |
950 | nodes = nodes.. nodeIdent..string.format('<movingTool%d', i); |
951 | if tool.transSpeed ~= nil then |
952 | nodes = nodes.. ' translation="'..tool.curTrans[tool.translationAxis]..'"'; |
953 | end |
954 | if tool.rotSpeed ~= nil then |
955 | nodes = nodes.. ' rotation="'..tool.curRot[tool.rotationAxis]..'"'; |
956 | end |
957 | if tool.animSpeed ~= nil then |
958 | nodes = nodes .. ' animationTime="' .. tool.curAnimTime .. '"'; |
959 | end |
960 | nodes = nodes..'/>'; |
961 | end |
962 | end |
963 | |
964 | return attributes, nodes; |
965 | end |
update
DescriptionCalled on updateDefinition
update(float dt)Arguments
float | dt | time since last call in ms |
976 | function Cylindered:update(dt) |
977 | -- fix |
978 | if not self.fixFoldableAnim then |
979 | for i, tool in ipairs(self.movingTools) do |
980 | if tool.axisActionIndex ~= nil then |
981 | local changed = false; |
982 | if tool.animSpeed ~= nil then |
983 | if tool.animTimeToSet ~= nil then |
984 | tool.curAnimTime = tool.animTimeToSet; |
985 | |
986 | local animation = self.animations[tool.animName]; |
987 | local realAnimTime = tool.animTimeToSet*animation.duration; |
988 | |
989 | if tool.animTimeToSet > 0.5 then |
990 | animation.currentTime = 0; |
991 | animation.currentSpeed = 1; |
992 | else |
993 | animation.currentTime = animation.duration; |
994 | animation.currentSpeed = -1; |
995 | end |
996 | |
997 | local dtToUse, _ = AnimatedVehicle.updateAnimationCurrentTime(self, animation, 99999999, realAnimTime); |
998 | AnimatedVehicle.updateAnimation(self, animation, dtToUse, false); |
999 | |
1000 | changed = true; |
1001 | tool.animTimeToSet = nil; |
1002 | end |
1003 | end |
1004 | if changed then |
1005 | Cylindered.setDirty(self, tool); |
1006 | end |
1007 | end |
1008 | end |
1009 | self.fixFoldableAnim = true |
1010 | end |
1011 | |
1012 | local movingToolNeedsSound = false |
1013 | local movingPartNeedsSound = false |
1014 | |
1015 | -- |
1016 | if self:getIsActive() then |
1017 | if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() then |
1018 | |
1019 | if InputBinding.hasEvent(InputBinding.TOGGLE_CONTROLGROUP) then |
1020 | if self:getIsControlGroupChangeAllowed() then |
1021 | local index = self:getNextValidControlGroupIndex(); |
1022 | if index ~= self.activeControlGroupIndex then |
1023 | self:setActiveControlGroup(index); |
1024 | end |
1025 | end |
1026 | end |
1027 | |
1028 | local foldAnimTime = self.foldAnimTime; |
1029 | for i=1, table.getn(self.movingTools) do |
1030 | local tool = self.movingTools[i]; |
1031 | local foldActive = (foldAnimTime == nil or (foldAnimTime <= tool.foldMaxLimit and foldAnimTime >= tool.foldMinLimit)); |
1032 | |
1033 | if self.hasPipe and table.getn(tool.freezingPipeStates) > 0 then |
1034 | local freezed = false; |
1035 | for _,state in pairs(tool.freezingPipeStates) do |
1036 | if self.pipeCurrentState == state or self.pipeTargetState == state or self.pipeCurrentState == 0 then |
1037 | freezed = true; |
1038 | end |
1039 | end |
1040 | if freezed ~= tool.isFreezed then |
1041 | tool.isFreezed = freezed; |
1042 | local x,y,z = getTranslation(tool.node); |
1043 | local rx,ry,rz = getRotation(tool.node); |
1044 | tool.curTrans = { x,y,z }; |
1045 | tool.curRot = { rx,ry,rz }; |
1046 | end |
1047 | if not tool.isFreezed then |
1048 | for _,pipeNode in pairs(self.pipeNodes) do |
1049 | if pipeNode.node == tool.node then |
1050 | pipeNode.curTranslation = {tool.curTrans[1], tool.curTrans[2], tool.curTrans[3]}; |
1051 | pipeNode.curRotation = {tool.curRot[1], tool.curRot[2], tool.curRot[3]}; |
1052 | end |
1053 | end |
1054 | end |
1055 | end |
1056 | |
1057 | if tool.isActive and foldActive and (not tool.isFreezed) and (tool.rotSpeed ~= nil or tool.transSpeed ~= nil or tool.animSpeed ~= nil) and tool.axisActionIndex ~= nil then |
1058 | if tool.icon ~= nil then |
1059 | g_currentMission:addHelpAxis(tool.axisActionIndex, tool.icon) |
1060 | end |
1061 | |
1062 | local move, axisType = InputBinding.getInputAxis(tool.axisActionIndex); |
1063 | if tool.invertAxis then |
1064 | move = -move; |
1065 | end |
1066 | if axisType == InputBinding.INPUTTYPE_MOUSE_AXIS then |
1067 | move = move * tool.mouseSpeedFactor; |
1068 | else |
1069 | move = move * g_gameSettings:getValue("vehicleArmSensitivity") |
1070 | end |
1071 | |
1072 | local isAxisZero = InputBinding.isAxisZero(move); |
1073 | |
1074 | local rotSpeed = 0; |
1075 | local transSpeed = 0; |
1076 | local animSpeed = 0; |
1077 | if not isAxisZero then |
1078 | if tool.rotSpeed ~= nil then |
1079 | rotSpeed = move*tool.rotSpeed; |
1080 | if tool.rotAcceleration ~= nil and math.abs(rotSpeed - tool.lastRotSpeed) >= tool.rotAcceleration*dt then |
1081 | if rotSpeed > tool.lastRotSpeed then |
1082 | rotSpeed = tool.lastRotSpeed + tool.rotAcceleration*dt; |
1083 | else |
1084 | rotSpeed = tool.lastRotSpeed - tool.rotAcceleration*dt; |
1085 | end |
1086 | end |
1087 | end |
1088 | if tool.transSpeed ~= nil then |
1089 | transSpeed = move*tool.transSpeed; |
1090 | if tool.transAcceleration ~= nil and math.abs(transSpeed - tool.lastTransSpeed) >= tool.transAcceleration*dt then |
1091 | if transSpeed > tool.lastTransSpeed then |
1092 | transSpeed = tool.lastTransSpeed + tool.transAcceleration*dt; |
1093 | else |
1094 | transSpeed = tool.lastTransSpeed - tool.transAcceleration*dt; |
1095 | end |
1096 | end |
1097 | end |
1098 | if tool.animSpeed ~= nil then |
1099 | animSpeed = move*tool.animSpeed; |
1100 | if tool.animAcceleration ~= nil and math.abs(animSpeed - tool.lastAnimSpeed) >= tool.animAcceleration*dt then |
1101 | if animSpeed > tool.lastAnimSpeed then |
1102 | animSpeed = tool.lastAnimSpeed + tool.animAcceleration*dt; |
1103 | else |
1104 | animSpeed = tool.lastAnimSpeed - tool.animAcceleration*dt; |
1105 | end |
1106 | end |
1107 | end |
1108 | else |
1109 | -- decelerate |
1110 | if tool.externalRotSpeed ~= 0 then |
1111 | rotSpeed = tool.externalRotSpeed; |
1112 | elseif tool.rotAcceleration ~= nil then |
1113 | if tool.lastRotSpeed < 0 then |
1114 | rotSpeed = math.min(tool.lastRotSpeed + tool.rotAcceleration*dt, 0); |
1115 | else |
1116 | rotSpeed = math.max(tool.lastRotSpeed - tool.rotAcceleration*dt, 0); |
1117 | end |
1118 | end |
1119 | if tool.externalTransSpeed ~= 0 then |
1120 | transSpeed = tool.externalTransSpeed; |
1121 | elseif tool.transAcceleration ~= nil then |
1122 | if tool.lastTransSpeed < 0 then |
1123 | transSpeed = math.min(tool.lastTransSpeed + tool.transAcceleration*dt, 0); |
1124 | else |
1125 | transSpeed = math.max(tool.lastTransSpeed - tool.transAcceleration*dt, 0); |
1126 | end |
1127 | end |
1128 | if tool.externalAnimSpeed ~= 0 then |
1129 | animSpeed = tool.externalAnimSpeed; |
1130 | elseif tool.animAcceleration ~= nil then |
1131 | if tool.lastAnimSpeed < 0 then |
1132 | animSpeed = math.min(tool.lastAnimSpeed + tool.animAcceleration*dt, 0); |
1133 | else |
1134 | animSpeed = math.max(tool.lastAnimSpeed - tool.animAcceleration*dt, 0); |
1135 | end |
1136 | end |
1137 | end |
1138 | |
1139 | local changed = false; |
1140 | if rotSpeed ~= 0 then |
1141 | changed = changed or Cylindered.setToolRotation(self, tool, rotSpeed, dt); |
1142 | else |
1143 | tool.lastRotSpeed = 0; |
1144 | end |
1145 | if transSpeed ~= 0 then |
1146 | changed = changed or Cylindered.setToolTranslation(self, tool, transSpeed, dt); |
1147 | else |
1148 | tool.lastTransSpeed = 0; |
1149 | end |
1150 | if animSpeed ~= 0 then |
1151 | changed = changed or Cylindered.setToolAnimation(self, tool, animSpeed, dt); |
1152 | else |
1153 | tool.lastAnimSpeed = 0; |
1154 | end |
1155 | |
1156 | for _, dependentTool in pairs(tool.dependentMovingTools) do |
1157 | if dependentTool.rotSpeedScale ~= nil and tool.lastRotSpeed ~= 0 then |
1158 | dependentTool.movingTool.externalRotSpeed = dependentTool.rotSpeedScale * tool.lastRotSpeed; |
1159 | end |
1160 | if dependentTool.transSpeedScale ~= nil and tool.lastTransSpeed ~= 0 then |
1161 | dependentTool.movingTool.externalTransSpeed = dependentTool.transSpeedScale * tool.lastTransSpeed; |
1162 | end |
1163 | if dependentTool.minTransLimits ~= nil or dependentTool.maxTransLimits ~= nil then |
1164 | |
1165 | local state = Cylindered.getMovingToolState(self, tool); |
1166 | if dependentTool.minTransLimits ~= nil then |
1167 | dependentTool.movingTool.transMin = Utils.lerp(dependentTool.minTransLimits[1], dependentTool.minTransLimits[2], 1-state); |
1168 | end |
1169 | if dependentTool.maxTransLimits ~= nil then |
1170 | dependentTool.movingTool.transMax = Utils.lerp(dependentTool.maxTransLimits[1], dependentTool.maxTransLimits[2], 1-state); |
1171 | end |
1172 | local transLimitChanged = Cylindered.setToolTranslation(self, dependentTool.movingTool, 0, 0); |
1173 | if transLimitChanged then |
1174 | Cylindered.setDirty(self, dependentTool.movingTool); |
1175 | end |
1176 | end |
1177 | if dependentTool.minRotLimits ~= nil or dependentTool.maxRotLimits ~= nil then |
1178 | |
1179 | local state = Cylindered.getMovingToolState(self, tool); |
1180 | if dependentTool.minRotLimits ~= nil then |
1181 | dependentTool.movingTool.rotMin = Utils.lerp(dependentTool.minRotLimits[1], dependentTool.minRotLimits[2], 1-state); |
1182 | end |
1183 | if dependentTool.maxRotLimits ~= nil then |
1184 | dependentTool.movingTool.rotMax = Utils.lerp(dependentTool.maxRotLimits[1], dependentTool.maxRotLimits[2], 1-state); |
1185 | end |
1186 | local rotLimitChanged = Cylindered.setToolRotation(self, dependentTool.movingTool, 0, 0); |
1187 | if rotLimitChanged then |
1188 | Cylindered.setDirty(self, dependentTool.movingTool); |
1189 | end |
1190 | end |
1191 | end |
1192 | |
1193 | if changed then |
1194 | if tool.playSound then |
1195 | movingToolNeedsSound = true |
1196 | end |
1197 | Cylindered.setDirty(self, tool); |
1198 | self:raiseDirtyFlags(self.cylinderedDirtyFlag); |
1199 | end |
1200 | |
1201 | end |
1202 | tool.externalRotSpeed = 0; |
1203 | tool.externalTransSpeed = 0; |
1204 | |
1205 | end |
1206 | end |
1207 | |
1208 | for i=1, table.getn(self.movingTools) do |
1209 | local tool = self.movingTools[i]; |
1210 | if tool.delayedUpdates ~= nil and tool.delayedUpdates > 0 then |
1211 | if tool.transSpeed ~= nil then |
1212 | Cylindered.setDelayedNodeTranslation(self, tool); |
1213 | end |
1214 | if tool.rotSpeed ~= nil then |
1215 | Cylindered.setDelayedNodeRotation(self, tool); |
1216 | end |
1217 | end |
1218 | end |
1219 | |
1220 | self.isActiveDirtyTime = g_currentMission.time + self.isActiveDirtyTimeOffset; |
1221 | end |
1222 | |
1223 | if self.isActiveDirtyTime >= g_currentMission.time then |
1224 | for _, part in pairs(self.activeDirtyMovingParts) do |
1225 | Cylindered.setDirty(self, part); |
1226 | end |
1227 | end |
1228 | |
1229 | for _, tool in pairs(self.movingTools) do |
1230 | if tool.isDirty then |
1231 | if tool.playSound then |
1232 | movingToolNeedsSound = true |
1233 | end |
1234 | if self.isServer then |
1235 | -- update component joint |
1236 | Cylindered.updateComponentJoints(self, tool, false); |
1237 | end |
1238 | tool.isDirty = false; |
1239 | end |
1240 | end |
1241 | |
1242 | for i, part in ipairs(self.movingParts) do |
1243 | if part.isDirty then |
1244 | Cylindered.updateMovingPart(self, part, false); |
1245 | if part.playSound then |
1246 | self.cylinderedHydraulicSoundPartNumber = i; |
1247 | movingPartNeedsSound = true |
1248 | end |
1249 | else |
1250 | if self.isClient and self.cylinderedHydraulicSoundPartNumber == i then |
1251 | movingPartNeedsSound = false |
1252 | end |
1253 | end |
1254 | end |
1255 | |
1256 | if self.isClient then |
1257 | if movingToolNeedsSound or movingPartNeedsSound then |
1258 | if self:getIsActiveForSound() and not self.sampleCylinderedHydraulic.isPlaying then |
1259 | SoundUtil.playSample(self.sampleCylinderedHydraulic, 0, 0, nil); |
1260 | end |
1261 | else |
1262 | SoundUtil.stopSample(self.sampleCylinderedHydraulic) |
1263 | end |
1264 | end |
1265 | end |
draw
DescriptionCalled on drawDefinition
draw()Code
1272 | function Cylindered:draw() |
1273 | if self.isClient then |
1274 | if self:getIsActiveForInput(true) then |
1275 | if self:getIsControlGroupChangeAllowed() then |
1276 | local index = self:getNextValidControlGroupIndex(); |
1277 | if index ~= self.activeControlGroupIndex then |
1278 | local activeControlGroup = self.controlGroups[self.activeControlGroupIndex]; |
1279 | g_currentMission:addHelpButtonText(string.format(g_i18n:getText("action_changeControlGroup"), activeControlGroup.l10nName), InputBinding.TOGGLE_CONTROLGROUP, nil, GS_PRIO_NORMAL); |
1280 | end |
1281 | end |
1282 | end |
1283 | end |
1284 | end |
setToolTranslation
DescriptionSet tool translationDefinition
setToolTranslation(table tool, float transSpeed, float dt)Arguments
table | tool | tool |
float | transSpeed | translation speed |
float | dt | time since last call in ms |
boolean | changed | translation changed |
1292 | function Cylindered.setToolTranslation(self, tool, transSpeed, dt) |
1293 | local curTrans = { getTranslation(tool.node) }; |
1294 | local newTrans = curTrans[tool.translationAxis] + transSpeed*dt; |
1295 | if tool.transMax ~= nil then |
1296 | newTrans = math.min(newTrans, tool.transMax); |
1297 | end |
1298 | if tool.transMin ~= nil then |
1299 | newTrans = math.max(newTrans, tool.transMin); |
1300 | end |
1301 | local diff = newTrans - curTrans[tool.translationAxis]; |
1302 | if dt ~= 0 then |
1303 | tool.lastTransSpeed = diff/dt; |
1304 | end |
1305 | if math.abs(diff) > 0.0001 then |
1306 | tool.curTrans[tool.translationAxis] = newTrans; |
1307 | setTranslation(tool.node, unpack(tool.curTrans)); |
1308 | if tool.delayedNode ~= nil then |
1309 | tool.delayedUpdates = 2; |
1310 | Cylindered.setDelayedNodeTranslation(self, tool); |
1311 | end |
1312 | return true; |
1313 | end |
1314 | |
1315 | return false; |
1316 | end |
setDelayedNodeTranslation
DescriptionSet translation of delayed nodeDefinition
setDelayedNodeTranslation(table tool)Arguments
table | tool | tool |
1321 | function Cylindered.setDelayedNodeTranslation(self, tool) |
1322 | tool.curDelayedTrans[tool.translationAxis] = tool.transHistory[2]; |
1323 | tool.transHistory[2] = tool.transHistory[1]; |
1324 | tool.transHistory[1] = tool.curTrans[tool.translationAxis]; |
1325 | setTranslation(tool.delayedNode, tool.curDelayedTrans[1],tool.curDelayedTrans[2],tool.curDelayedTrans[3]); |
1326 | tool.delayedUpdates = tool.delayedUpdates - 1; |
1327 | if self.nodesToMovingParts[tool.delayedNode] ~= nil then |
1328 | Cylindered.setDirty(self, self.nodesToMovingParts[tool.delayedNode]); |
1329 | elseif self.nodesToMovingTools[tool.delayedNode] ~= nil then |
1330 | Cylindered.setDirty(self, self.nodesToMovingTools[tool.delayedNode]); |
1331 | end |
1332 | end |
setToolRotation
DescriptionSet tool rotationDefinition
setToolRotation(table tool, float rotSpeed, float dt)Arguments
table | tool | tool |
float | rotSpeed | rotation speed |
float | dt | time since last call in ms |
boolean | changed | rotation changed |
1340 | function Cylindered.setToolRotation(self, tool, rotSpeed, dt) |
1341 | local curRot = { getRotation(tool.node) }; |
1342 | local newRot = curRot[tool.rotationAxis] + rotSpeed*dt; |
1343 | if tool.rotMax ~= nil then |
1344 | newRot = math.min(newRot, tool.rotMax); |
1345 | end |
1346 | if tool.rotMin ~= nil then |
1347 | newRot = math.max(newRot, tool.rotMin); |
1348 | end |
1349 | local diff = newRot - curRot[tool.rotationAxis]; |
1350 | if dt ~= 0 then |
1351 | tool.lastRotSpeed = diff/dt; |
1352 | end |
1353 | if math.abs(diff) > 0.0001 then |
1354 | -- wrap if not limited |
1355 | if tool.rotMin == nil and tool.rotMax == nil then |
1356 | if newRot > 2*math.pi then |
1357 | newRot = newRot - 2*math.pi; |
1358 | end |
1359 | if newRot < 0 then |
1360 | newRot = newRot + 2*math.pi; |
1361 | end |
1362 | end |
1363 | tool.curRot[tool.rotationAxis] = newRot; |
1364 | setRotation(tool.node, unpack(tool.curRot)); |
1365 | if tool.delayedNode ~= nil then |
1366 | tool.delayedUpdates = 2; |
1367 | Cylindered.setDelayedNodeRotation(self, tool); |
1368 | end |
1369 | return true; |
1370 | end |
1371 | |
1372 | return false; |
1373 | end |
setDelayedNodeRotation
DescriptionSet rotation of delayed nodeDefinition
setDelayedNodeRotation(table tool)Arguments
table | tool | tool |
1378 | function Cylindered.setDelayedNodeRotation(self, tool) |
1379 | tool.curDelayedRot[tool.rotationAxis] = tool.rotHistory[2]; |
1380 | tool.rotHistory[2] = tool.rotHistory[1]; |
1381 | tool.rotHistory[1] = tool.curRot[tool.rotationAxis]; |
1382 | setRotation(tool.delayedNode, tool.curDelayedRot[1],tool.curDelayedRot[2],tool.curDelayedRot[3]); |
1383 | tool.delayedUpdates = tool.delayedUpdates - 1; |
1384 | if self.nodesToMovingParts[tool.delayedNode] ~= nil then |
1385 | Cylindered.setDirty(self, self.nodesToMovingParts[tool.delayedNode]); |
1386 | elseif self.nodesToMovingTools[tool.delayedNode] ~= nil then |
1387 | Cylindered.setDirty(self, self.nodesToMovingTools[tool.delayedNode]); |
1388 | end |
1389 | end |
setToolAnimation
DescriptionSet tool animationDefinition
setToolAnimation(table tool, float animSpeed, float dt)Arguments
table | tool | tool |
float | animSpeed | animation speed |
float | dt | time since last call in ms |
boolean | changed | animation changed |
1397 | function Cylindered.setToolAnimation(self, tool, animSpeed, dt) |
1398 | local newAnimTime = tool.curAnimTime+animSpeed*dt; |
1399 | |
1400 | if tool.animMaxTime ~= nil then |
1401 | newAnimTime = math.min(newAnimTime, tool.animMaxTime); |
1402 | end |
1403 | if tool.animMinTime ~= nil then |
1404 | newAnimTime = math.max(newAnimTime, tool.animMinTime); |
1405 | end |
1406 | local diff = newAnimTime - tool.curAnimTime; |
1407 | if dt ~= 0 then |
1408 | tool.lastAnimSpeed = diff / dt; |
1409 | end |
1410 | if math.abs(diff) > 0.0001 then |
1411 | tool.curAnimTime = newAnimTime; |
1412 | self:setAnimationTime(tool.animName, newAnimTime); |
1413 | return true; |
1414 | end |
1415 | |
1416 | return false; |
1417 | end |
getMovingToolState
DescriptionReturns moving tool stateDefinition
getMovingToolState(table tool)Arguments
table | tool | tool |
float | state | state of moving tool [0..1] |
1423 | function Cylindered.getMovingToolState(self, tool) |
1424 | local state = 0; |
1425 | if tool.rotMax ~= nil and tool.rotMin ~= nil then |
1426 | state = (tool.curRot[tool.rotationAxis]-tool.rotMin) / (tool.rotMax-tool.rotMin); |
1427 | else |
1428 | if tool.transMax ~= nil and tool.transMin ~= nil then |
1429 | state = (tool.curTrans[tool.translationAxis]-tool.transMin) / (tool.transMax-tool.transMin); |
1430 | end |
1431 | end |
1432 | |
1433 | return state; |
1434 | end |
setMovingToolDirty
DescriptionSet moving tool dirtyDefinition
setMovingToolDirty(integer node)Arguments
integer | node | node id |
1439 | function Cylindered:setMovingToolDirty(node) |
1440 | local tool = self.nodesToMovingTools[node]; |
1441 | if tool ~= nil then |
1442 | local x,y,z = getRotation(tool.node); |
1443 | tool.curRot[1] = x; |
1444 | tool.curRot[2] = y; |
1445 | tool.curRot[3] = z; |
1446 | local x,y,z = getTranslation(tool.node); |
1447 | tool.curTrans[1] = x; |
1448 | tool.curTrans[2] = y; |
1449 | tool.curTrans[3] = z; |
1450 | Cylindered.setDirty(self, tool); |
1451 | end |
1452 | end |
setDirty
DescriptionSet dirtyDefinition
setDirty(table part)Arguments
table | part | part to set dirty |
1457 | function Cylindered.setDirty(self, part) |
1458 | if not part.isDirty then |
1459 | part.isDirty = true; |
1460 | |
1461 | Cylindered.updateAttacherJoints(self, part); |
1462 | Cylindered.updateWheels(self, part); |
1463 | |
1464 | for _, v in pairs(part.dependentParts) do |
1465 | Cylindered.setDirty(self, v); |
1466 | end |
1467 | end |
1468 | end |
updateWheels
DescriptionUpdate wheel of partDefinition
updateWheels(table part)Arguments
table | part | part |
1473 | function Cylindered.updateWheels(self, part) |
1474 | if part.wheels ~= nil then |
1475 | for _, wheel in pairs(part.wheels) do |
1476 | wheel.steeringCenterOffsetX, wheel.steeringCenterOffsetY, wheel.steeringCenterOffsetZ = localToLocal(wheel.driveNode, wheel.repr, 0, 0, 0) |
1477 | wheel.steeringCenterOffsetX = -wheel.steeringCenterOffsetX |
1478 | wheel.steeringCenterOffsetY = -wheel.steeringCenterOffsetY |
1479 | wheel.steeringCenterOffsetZ = -wheel.steeringCenterOffsetZ |
1480 | |
1481 | wheel.positionX, wheel.positionY, wheel.positionZ = localToLocal(getParent(wheel.repr), wheel.node, wheel.startPositionX-wheel.steeringCenterOffsetX, wheel.startPositionY-wheel.steeringCenterOffsetY, wheel.startPositionZ-wheel.steeringCenterOffsetZ); |
1482 | if wheel.useReprDirection then |
1483 | wheel.directionX, wheel.directionY, wheel.directionZ = localDirectionToLocal(getParent(wheel.repr), wheel.node, 0,-1,0); |
1484 | wheel.axleX, wheel.axleY, wheel.axleZ = localDirectionToLocal(getParent(wheel.repr), wheel.node, 1,0,0); |
1485 | elseif wheel.useDriveNodeDirection then |
1486 | wheel.directionX, wheel.directionY, wheel.directionZ = localDirectionToLocal(getParent(wheel.driveNode), wheel.node, 0,-1,0); |
1487 | wheel.axleX, wheel.axleY, wheel.axleZ = localDirectionToLocal(getParent(wheel.driveNode), wheel.node, 1,0,0); |
1488 | end |
1489 | self:updateWheelBase(wheel); |
1490 | end |
1491 | end |
1492 | end |
updateMovingPart
DescriptionUpdate moving partDefinition
updateMovingPart(table part, boolean placeComponents, boolean updateDependentParts)Arguments
table | part | part |
boolean | placeComponents | place components |
boolean | updateDependentParts | update dependent parts |
1499 | function Cylindered.updateMovingPart(self, part, placeComponents, updateDependentParts) |
1500 | |
1501 | -- the local reference point must be referenceDistance away from the referencePoint |
1502 | local refX,refY,refZ; |
1503 | local dirX, dirY, dirZ = 0,0,0; |
1504 | if part.referencePoint ~= nil then |
1505 | if part.moveToReferenceFrame then |
1506 | local x,y,z = localToLocal(part.referenceFrame, getParent(part.node), part.referenceFrameOffset[1], part.referenceFrameOffset[2], part.referenceFrameOffset[3]); |
1507 | setTranslation(part.node, x,y,z); |
1508 | end |
1509 | refX,refY,refZ = getWorldTranslation(part.referencePoint); |
1510 | if part.referenceDistance == 0 then |
1511 | if part.useLocalOffset then |
1512 | local lx, ly, lz = worldToLocal(part.node, refX, refY, refZ); |
1513 | dirX, dirY, dirZ = localDirectionToWorld(part.node, lx-part.localReferencePoint[1], ly-part.localReferencePoint[2], lz); |
1514 | else |
1515 | local x,y,z = getWorldTranslation(part.node); |
1516 | dirX, dirY, dirZ = refX - x, refY-y, refZ-z; |
1517 | end |
1518 | else |
1519 | if part.updateLocalReferenceDistance then |
1520 | local _,y,z = worldToLocal(part.node, getWorldTranslation(part.localReferencePointNode)); |
1521 | part.localReferenceDistance = Utils.vector2Length(y, z); |
1522 | end |
1523 | if part.referenceDistancePoint ~= nil then |
1524 | local _,_,z = worldToLocal(part.node, getWorldTranslation(part.referenceDistancePoint)); |
1525 | part.referenceDistance = z; |
1526 | end |
1527 | |
1528 | if part.localReferenceTranslate then |
1529 | local lx, ly, lz = worldToLocal(part.node, refX, refY, refZ); |
1530 | |
1531 | -- calculate line-circle intersection |
1532 | if math.abs(ly) < part.referenceDistance then |
1533 | local dz = math.sqrt(part.referenceDistance*part.referenceDistance - ly*ly); |
1534 | |
1535 | local z1 = (lz - dz) - part.localReferenceDistance; |
1536 | local z2 = (lz + dz) - part.localReferenceDistance; |
1537 | if math.abs(z2) < math.abs(z1) then |
1538 | z1 = z2; |
1539 | end |
1540 | local parentNode = getParent(part.node); |
1541 | local tx,ty,tz = unpack(part.localReferenceTranslation); |
1542 | local _, _, coz = localToLocal(parentNode, part.node, tx,ty,tz); |
1543 | local ox,oy,oz = localDirectionToLocal(part.node, parentNode, 0,0,z1-coz); |
1544 | setTranslation(part.node, tx+ox,ty+oy,tz+oz); |
1545 | end |
1546 | else |
1547 | |
1548 | local r1 = part.localReferenceDistance; |
1549 | local r2 = part.referenceDistance; |
1550 | local lx, ly, lz = worldToLocal(part.node, refX, refY, refZ); |
1551 | --print("intersect: "..ly .. " "..lz); |
1552 | local ix, iy, i2x, i2y = Utils.getCircleCircleIntersection(0,0, r1, ly, lz, r2); |
1553 | |
1554 | if ix ~= nil then |
1555 | if i2x ~= nil then |
1556 | -- use the point which as the same angle side as the original configuration |
1557 | local side = ix*(lz-iy) - iy*(ly-ix); |
1558 | if (side < 0) ~= (part.localReferenceAngleSide < 0) then |
1559 | iy = i2y; |
1560 | ix = i2x; |
1561 | end |
1562 | end |
1563 | dirX, dirY, dirZ = localDirectionToWorld(part.node, 0, ix, iy) |
1564 | end |
1565 | end |
1566 | end |
1567 | else |
1568 | if part.alignToWorldY then |
1569 | dirX, dirY, dirZ = localDirectionToWorld(getRootNode(), 0, 1, 0); |
1570 | else |
1571 | dirX, dirY, dirZ = localDirectionToWorld(part.referenceFrame, 0, 0, 1); |
1572 | end |
1573 | if part.moveToReferenceFrame then |
1574 | local x,y,z = localToLocal(part.referenceFrame, getParent(part.node), part.referenceFrameOffset[1], part.referenceFrameOffset[2], part.referenceFrameOffset[3]); |
1575 | setTranslation(part.node, x,y,z); |
1576 | end |
1577 | end |
1578 | if (dirX ~= 0 or dirY ~= 0 or dirZ ~= 0) and part.doDirectionAlignment then |
1579 | local upX, upY, upZ = localDirectionToWorld(part.referenceFrame, 0, 1, 0); |
1580 | if part.invertZ then |
1581 | dirX = -dirX; |
1582 | dirY = -dirY; |
1583 | dirZ = -dirZ; |
1584 | end |
1585 | |
1586 | Utils.setWorldDirection(part.node, dirX, dirY, dirZ, upX, upY, upZ, part.limitedAxis, part.minRot, part.maxRot); |
1587 | |
1588 | if part.scaleZ and part.localReferenceDistance ~= nil then |
1589 | local len = Utils.vector3Length(dirX, dirY, dirZ); |
1590 | setScale(part.node, 1, 1, len/part.localReferenceDistance); |
1591 | end |
1592 | end |
1593 | if part.doRotationAlignment then |
1594 | local x,y,z = getRotation(part.referenceFrame) |
1595 | setRotation(part.node, x*part.rotMultiplier, y*part.rotMultiplier, z*part.rotMultiplier) |
1596 | end |
1597 | |
1598 | if part.referencePoint ~= nil then |
1599 | local numTranslatingParts = table.getn(part.translatingParts) |
1600 | if numTranslatingParts > 0 then |
1601 | local _, _, dist = worldToLocal(part.node, refX, refY, refZ); |
1602 | for i=1,numTranslatingParts do |
1603 | local translatingPart = part.translatingParts[i]; |
1604 | local newZ = (dist - translatingPart.referenceDistance)/numTranslatingParts; |
1605 | setTranslation(translatingPart.node, translatingPart.startPos[1], translatingPart.startPos[2], newZ); |
1606 | end |
1607 | end |
1608 | end |
1609 | |
1610 | if part.copyLocalDirectionParts ~= nil then |
1611 | for _,copyLocalDirectionPart in pairs(part.copyLocalDirectionParts) do |
1612 | local dx,dy,dz = localDirectionToWorld(part.node, 0,0,1); |
1613 | dx,dy,dz = worldDirectionToLocal(getParent(part.node), dx,dy,dz); |
1614 | dx = dx * copyLocalDirectionPart.dirScale[1]; |
1615 | dy = dy * copyLocalDirectionPart.dirScale[2]; |
1616 | dz = dz * copyLocalDirectionPart.dirScale[3]; |
1617 | |
1618 | local ux,uy,uz = localDirectionToWorld(part.node, 0,1,0); |
1619 | ux,uy,uz = worldDirectionToLocal(getParent(part.node), ux,uy,uz); |
1620 | ux = ux * copyLocalDirectionPart.upScale[1]; |
1621 | uy = uy * copyLocalDirectionPart.upScale[2]; |
1622 | uz = uz * copyLocalDirectionPart.upScale[3]; |
1623 | |
1624 | setDirection(copyLocalDirectionPart.node, dx,dy,dz, ux,uy,uz); |
1625 | |
1626 | if self.isServer then |
1627 | Cylindered.updateComponentJoints(self, copyLocalDirectionPart, placeComponents); |
1628 | end |
1629 | end |
1630 | end |
1631 | |
1632 | -- update component joint |
1633 | if self.isServer then |
1634 | Cylindered.updateComponentJoints(self, part, placeComponents); |
1635 | Cylindered.updateAttacherJoints(self, part); |
1636 | end |
1637 | |
1638 | if updateDependentParts and part.dependentParts ~= nil then |
1639 | for _,part in pairs(part.dependentParts) do |
1640 | Cylindered.updateMovingPart(self, part, placeComponents, updateDependentParts); |
1641 | end |
1642 | end |
1643 | |
1644 | part.isDirty = false; |
1645 | end |
updateComponentJoints
DescriptionUpdate component jointsDefinition
updateComponentJoints(table entry, boolean placeComponents)Arguments
table | entry | entry |
boolean | placeComponents | place components |
1651 | function Cylindered.updateComponentJoints(self, entry, placeComponents) |
1652 | if self.isServer then |
1653 | if entry.componentJoints ~= nil then |
1654 | for _,joint in ipairs(entry.componentJoints) do |
1655 | local componentJoint = joint.componentJoint; |
1656 | |
1657 | local jointNode = componentJoint.jointNode; |
1658 | if joint.anchorActor == 1 then |
1659 | jointNode = componentJoint.jointNodeActor1; |
1660 | end |
1661 | if placeComponents then |
1662 | |
1663 | local node = self.components[componentJoint.componentIndices[((joint.anchorActor+1)%2)+1] ].node; |
1664 | local x,y,z = localToWorld(jointNode, joint.x, joint.y, joint.z); |
1665 | local upX,upY,upZ = localDirectionToWorld(jointNode, joint.upX,joint.upY,joint.upZ); |
1666 | local dirX,dirY,dirZ = localDirectionToWorld(jointNode, joint.dirX,joint.dirY,joint.dirZ); |
1667 | Utils.setWorldTranslation(node, x,y,z); |
1668 | Utils.setWorldDirection(node, dirX,dirY,dirZ, upX,upY,upZ); |
1669 | end |
1670 | self:setComponentJointFrame(componentJoint, joint.anchorActor) |
1671 | end |
1672 | end |
1673 | end |
1674 | end |
updateAttacherJoints
DescriptionUpdate attacher jointsDefinition
updateAttacherJoints(table entry)Arguments
table | entry | entry |
1679 | function Cylindered.updateAttacherJoints(self, entry) |
1680 | if self.isServer then |
1681 | if entry.attacherJoints ~= nil then |
1682 | for _,joint in ipairs(entry.attacherJoints) do |
1683 | if joint.jointIndex ~= 0 then |
1684 | setJointFrame(joint.jointIndex, 0, joint.jointTransform); |
1685 | end |
1686 | end |
1687 | end |
1688 | if entry.inputAttacherJoint and self.attacherVehicle ~= nil then |
1689 | local implement = self.attacherVehicle:getImplementByObject(self); |
1690 | if implement ~= nil then |
1691 | local jointDesc = self.attacherVehicle.attacherJoints[implement.jointDescIndex]; |
1692 | if jointDesc.jointIndex ~= 0 then |
1693 | setJointFrame(jointDesc.jointIndex, 1, self.attacherJoint.node); |
1694 | end |
1695 | end |
1696 | end |
1697 | end |
1698 | end |
updateCylinderedInitial
DescriptionInitial update of cylinderedDefinition
updateCylinderedInitial(boolean placeComponents)Arguments
boolean | placeComponents | place components |
1703 | function Cylindered:updateCylinderedInitial(placeComponents) |
1704 | if placeComponents == nil then |
1705 | placeComponents = true; |
1706 | end |
1707 | |
1708 | for _, part in pairs(self.activeDirtyMovingParts) do |
1709 | Cylindered.setDirty(self, part); |
1710 | end |
1711 | |
1712 | for _, tool in ipairs(self.movingTools) do |
1713 | if tool.isDirty then |
1714 | Cylindered.updateWheels(self, tool) |
1715 | if self.isServer then |
1716 | Cylindered.updateComponentJoints(self, tool, placeComponents); |
1717 | end |
1718 | tool.isDirty = false; |
1719 | end |
1720 | end |
1721 | |
1722 | for _, part in ipairs(self.movingParts) do |
1723 | if part.isDirty then |
1724 | Cylindered.updateWheels(self, part) |
1725 | Cylindered.updateMovingPart(self, part, placeComponents); |
1726 | part.isDirty = false; |
1727 | end |
1728 | end |
1729 | end |
onAttach
DescriptionCalled if vehicle gets attachedDefinition
onAttach(table attacherVehicle)Arguments
table | attacherVehicle | attacher vehicle |
1734 | function Cylindered:onAttach(attacherVehicle) |
1735 | for i, tool in ipairs(self.movingTools) do |
1736 | local changed = false; |
1737 | if tool.transSpeed ~= nil then |
1738 | local trans = tool.curTrans[tool.translationAxis]; |
1739 | |
1740 | local changedTrans = false; |
1741 | if tool.attachTransMax ~= nil and trans > tool.attachTransMax then |
1742 | trans = tool.attachTransMax; |
1743 | changedTrans = true; |
1744 | elseif tool.attachTransMin ~= nil and trans < tool.attachTransMin then |
1745 | trans = tool.attachTransMin; |
1746 | changedTrans = true; |
1747 | end |
1748 | if changedTrans then |
1749 | tool.curTrans[tool.translationAxis] = trans; |
1750 | setTranslation(tool.node, unpack(tool.curTrans)); |
1751 | changed = true; |
1752 | end |
1753 | end |
1754 | if tool.rotSpeed ~= nil then |
1755 | local rot = tool.curRot[tool.rotationAxis]; |
1756 | |
1757 | local changedRot = false; |
1758 | if tool.attachRotMax ~= nil and rot > tool.attachRotMax then |
1759 | rot = tool.attachRotMax; |
1760 | changedRot = true; |
1761 | elseif tool.attachRotMin ~= nil and rot < tool.attachRotMin then |
1762 | rot = tool.attachRotMin; |
1763 | changedRot = true; |
1764 | end |
1765 | if changedRot then |
1766 | tool.curRot[tool.rotationAxis] = rot; |
1767 | setRotation(tool.node, unpack(tool.curRot)); |
1768 | changed = true; |
1769 | end |
1770 | end |
1771 | if changed then |
1772 | Cylindered.setDirty(self, tool); |
1773 | end |
1774 | end |
1775 | end |
onDeactivateSounds
DescriptionCalled on deactivating soundsDefinition
onDeactivateSounds()Code
1779 | function Cylindered:onDeactivateSounds() |
1780 | if self.isClient then |
1781 | SoundUtil.stopSample(self.sampleCylinderedHydraulic, true); |
1782 | end |
1783 | end |
isDetachAllowed
DescriptionReturns true if detach is allowedDefinition
isDetachAllowed()Return Values
boolean | detachAllowed | detach is allowed |
1788 | function Cylindered:isDetachAllowed(superFunc) |
1789 | if self.detachLockNodes ~= nil then |
1790 | for entry, data in pairs(self.detachLockNodes) do |
1791 | local node = entry.node; |
1792 | local rot = {getRotation(node)}; |
1793 | |
1794 | if data.detachingRotMinLimit ~= nil and rot[entry.rotationAxis] < data.detachingRotMinLimit then |
1795 | return false; |
1796 | end |
1797 | if data.detachingRotMaxLimit ~= nil and rot[entry.rotationAxis] > data.detachingRotMaxLimit then |
1798 | return false; |
1799 | end |
1800 | |
1801 | local trans = {getTranslation(node)}; |
1802 | if data.detachingTransMinLimit ~= nil and trans[entry.translationAxis] < data.detachingTransMinLimit then |
1803 | return false; |
1804 | end |
1805 | if data.detachingTransMaxLimit ~= nil and trans[entry.translationAxis] > data.detachingTransMaxLimit then |
1806 | return false; |
1807 | end |
1808 | end |
1809 | end |
1810 | |
1811 | if superFunc ~= nil then |
1812 | return superFunc(self); |
1813 | end |
1814 | return true; |
1815 | end |
setActiveControlGroup
DescriptionChanges active control groupDefinition
setActiveControlGroup(integer index)Arguments
integer | index | index of new control group |
1820 | function Cylindered:setActiveControlGroup(index) |
1821 | if index > self.numControlGroups then |
1822 | index = 1; |
1823 | end |
1824 | self.activeControlGroupIndex = index; |
1825 | |
1826 | local activeGroup = self.controlGroups[index]; |
1827 | for i,tool in pairs(self.movingTools) do |
1828 | if tool.groupName ~= nil then |
1829 | tool.isActive = tool.groupName == activeGroup.groupName; |
1830 | end |
1831 | end |
1832 | end |
getNextValidControlGroupIndex
DescriptionReturns next valid control group indexDefinition
getNextValidControlGroupIndex()Return Values
integer | index | next valid index |
1837 | function Cylindered:getNextValidControlGroupIndex() |
1838 | local index = self.activeControlGroupIndex; |
1839 | index = index + 1; |
1840 | if index > self.numControlGroups then |
1841 | index = 1; |
1842 | end |
1843 | return index; |
1844 | end |
getIsControlGroupChangeAllowed
DescriptionReturns if control group change is allowedDefinition
getIsControlGroupChangeAllowed()Return Values
boolean | isAllowed | control group change is allowed |
1849 | function Cylindered:getIsControlGroupChangeAllowed() |
1850 | if self.numControlGroups > 1 then |
1851 | return true; |
1852 | else |
1853 | return false; |
1854 | end |
1855 | end |
loadObjectChangeValuesFromXML
DescriptionLoad object change from xmlDefinition
loadObjectChangeValuesFromXML(integer xmlFile, string key, integer node, table object)Arguments
integer | xmlFile | id of xml object |
string | key | key |
integer | node | node id |
table | object | object |
1863 | function Cylindered:loadObjectChangeValuesFromXML(superFunc, xmlFile, key, node, object) |
1864 | if self.nodesToMovingTools ~= nil and self.nodesToMovingTools[node] ~= nil then |
1865 | local movingTool = self.nodesToMovingTools[node] |
1866 | object.movingToolRotMaxActive = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#movingToolRotMaxActive"), movingTool.rotMax) |
1867 | object.movingToolRotMaxInactive = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#movingToolRotMaxInactive"), movingTool.rotMax) |
1868 | object.movingToolRotMinActive = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#movingToolRotMinActive"), movingTool.rotMin) |
1869 | object.movingToolRotMinInactive = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#movingToolRotMinInactive"), movingTool.rotMin) |
1870 | end |
1871 | end |
setObjectChangeValues
DescriptionSets object change valuesDefinition
setObjectChangeValues(table object, boolean isActive)Arguments
table | object | object |
boolean | isActive | is active |
1877 | function Cylindered:setObjectChangeValues(superFunc, object, isActive) |
1878 | if self.nodesToMovingTools ~= nil and self.nodesToMovingTools[object.node] ~= nil then |
1879 | local movingTool = self.nodesToMovingTools[object.node] |
1880 | if isActive then |
1881 | movingTool.rotMax = object.movingToolRotMaxActive |
1882 | movingTool.rotMin = object.movingToolRotMinActive |
1883 | else |
1884 | movingTool.rotMax = object.movingToolRotMaxInactive |
1885 | movingTool.rotMin = object.movingToolRotMinInactive |
1886 | end |
1887 | end |
1888 | end |
allowLoadMovingToolStates
DescriptionReturns if loading of moving tool stats from savegame is allowedDefinition
allowLoadMovingToolStates()Return Values
boolean | isAllowed | is allowed |
1893 | function Cylindered:allowLoadMovingToolStates(superFunc) |
1894 | if superFunc ~= nil then |
1895 | return superFunc(self); |
1896 | end |
1897 | return true; |
1898 | end |