LUADOC - Farming Simulator 17

Printable Version

Cylindered

Description
This is the specialization for vehicles which have movable parts
Functions

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
17function Cylindered.prerequisitesPresent(specializations)
18 return SpecializationUtil.hasSpecialization(AttacherJoints, specializations);
19end

preLoad

Description
Called before loading
Definition
preLoad(table savegame)
Arguments
tablesavegamesavegame
Code
24function 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)
28end

load

Description
Called on loading
Definition
load(table savegame)
Arguments
tablesavegamesavegame
Code
33function 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
475end

postLoad

Description
Called after loading
Definition
postLoad(table savegame)
Arguments
tablesavegamesavegame
Code
480function 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);
553end

delete

Description
Called on deleting
Definition
delete()
Code
557function 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
568end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
574function 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;
609end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
615function 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;
632end

readUpdateStream

Description
Called on on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
639function 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
699end

writeUpdateStream

Description
Called on on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
706function 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
738end

loadDependentMovingTools

Description
Load dependent moving tools from xml
Definition
loadDependentMovingTools(integer xmlFile, string baseName, table entry)
Arguments
integerxmlFileid of xml object
stringbaseNamebase name
tableentryentry to add
Code
745function 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
774end

loadDependentParts

Description
Load dependent parts from xml
Definition
loadDependentParts(integer xmlFile, string baseName, table entry)
Arguments
integerxmlFileid of xml object
stringbaseNamebase name
tableentryentry to add
Code
781function 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
795end

loadComponentJoints

Description
Load component joints from xml
Definition
loadComponentJoints(integer xmlFile, string baseName, table entry)
Arguments
integerxmlFileid of xml object
stringbaseNamebase name
tableentryentry to add
Code
802function 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
842end

loadAttacherJoints

Description
Load attacher joints from xml
Definition
loadAttacherJoints(integer xmlFile, string baseName, table entry)
Arguments
integerxmlFileid of xml object
stringbaseNamebase name
tableentryentry to add
Code
849function 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);
874end

loadTranslatingParts

Description
Load translating parts
Definition
loadTranslatingParts(integer xmlFile, string baseName, table entry)
Arguments
integerxmlFileid of xml object
stringbaseNamebase name
tableentryentry to add
Code
881function 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
904end

loadCopyLocalDirectionParts

Description
Load copy local direction parts from xml
Definition
loadCopyLocalDirectionParts(integer xmlFile, string baseName, table entry)
Arguments
integerxmlFileid of xml object
stringbaseNamebase name
tableentryentry to add
Code
911function 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
932end

getSaveAttributesAndNodes

Description
Returns attributes and nodes to save
Definition
getSaveAttributesAndNodes(table nodeIdent)
Arguments
tablenodeIdentnode ident
Return Values
stringattributesattributes
stringnodesnodes
Code
939function 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;
965end

update

Description
Called on update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
976function 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
1265end

draw

Description
Called on draw
Definition
draw()
Code
1272function 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
1284end

setToolTranslation

Description
Set tool translation
Definition
setToolTranslation(table tool, float transSpeed, float dt)
Arguments
tabletooltool
floattransSpeedtranslation speed
floatdttime since last call in ms
Return Values
booleanchangedtranslation changed
Code
1292function 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;
1316end

setDelayedNodeTranslation

Description
Set translation of delayed node
Definition
setDelayedNodeTranslation(table tool)
Arguments
tabletooltool
Code
1321function 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
1332end

setToolRotation

Description
Set tool rotation
Definition
setToolRotation(table tool, float rotSpeed, float dt)
Arguments
tabletooltool
floatrotSpeedrotation speed
floatdttime since last call in ms
Return Values
booleanchangedrotation changed
Code
1340function 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;
1373end

setDelayedNodeRotation

Description
Set rotation of delayed node
Definition
setDelayedNodeRotation(table tool)
Arguments
tabletooltool
Code
1378function 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
1389end

setToolAnimation

Description
Set tool animation
Definition
setToolAnimation(table tool, float animSpeed, float dt)
Arguments
tabletooltool
floatanimSpeedanimation speed
floatdttime since last call in ms
Return Values
booleanchangedanimation changed
Code
1397function 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;
1417end

getMovingToolState

Description
Returns moving tool state
Definition
getMovingToolState(table tool)
Arguments
tabletooltool
Return Values
floatstatestate of moving tool [0..1]
Code
1423function 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;
1434end

setMovingToolDirty

Description
Set moving tool dirty
Definition
setMovingToolDirty(integer node)
Arguments
integernodenode id
Code
1439function 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
1452end

setDirty

Description
Set dirty
Definition
setDirty(table part)
Arguments
tablepartpart to set dirty
Code
1457function 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
1468end

updateWheels

Description
Update wheel of part
Definition
updateWheels(table part)
Arguments
tablepartpart
Code
1473function 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
1492end

updateMovingPart

Description
Update moving part
Definition
updateMovingPart(table part, boolean placeComponents, boolean updateDependentParts)
Arguments
tablepartpart
booleanplaceComponentsplace components
booleanupdateDependentPartsupdate dependent parts
Code
1499function 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;
1645end

updateComponentJoints

Description
Update component joints
Definition
updateComponentJoints(table entry, boolean placeComponents)
Arguments
tableentryentry
booleanplaceComponentsplace components
Code
1651function 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
1674end

updateAttacherJoints

Description
Update attacher joints
Definition
updateAttacherJoints(table entry)
Arguments
tableentryentry
Code
1679function 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
1698end

updateCylinderedInitial

Description
Initial update of cylindered
Definition
updateCylinderedInitial(boolean placeComponents)
Arguments
booleanplaceComponentsplace components
Code
1703function 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
1729end

onAttach

Description
Called if vehicle gets attached
Definition
onAttach(table attacherVehicle)
Arguments
tableattacherVehicleattacher vehicle
Code
1734function 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
1775end

onDeactivateSounds

Description
Called on deactivating sounds
Definition
onDeactivateSounds()
Code
1779function Cylindered:onDeactivateSounds()
1780 if self.isClient then
1781 SoundUtil.stopSample(self.sampleCylinderedHydraulic, true);
1782 end
1783end

isDetachAllowed

Description
Returns true if detach is allowed
Definition
isDetachAllowed()
Return Values
booleandetachAlloweddetach is allowed
Code
1788function 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;
1815end

setActiveControlGroup

Description
Changes active control group
Definition
setActiveControlGroup(integer index)
Arguments
integerindexindex of new control group
Code
1820function 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
1832end

getNextValidControlGroupIndex

Description
Returns next valid control group index
Definition
getNextValidControlGroupIndex()
Return Values
integerindexnext valid index
Code
1837function 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;
1844end

getIsControlGroupChangeAllowed

Description
Returns if control group change is allowed
Definition
getIsControlGroupChangeAllowed()
Return Values
booleanisAllowedcontrol group change is allowed
Code
1849function Cylindered:getIsControlGroupChangeAllowed()
1850 if self.numControlGroups > 1 then
1851 return true;
1852 else
1853 return false;
1854 end
1855end

loadObjectChangeValuesFromXML

Description
Load object change from xml
Definition
loadObjectChangeValuesFromXML(integer xmlFile, string key, integer node, table object)
Arguments
integerxmlFileid of xml object
stringkeykey
integernodenode id
tableobjectobject
Code
1863function 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
1871end

setObjectChangeValues

Description
Sets object change values
Definition
setObjectChangeValues(table object, boolean isActive)
Arguments
tableobjectobject
booleanisActiveis active
Code
1877function 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
1888end

allowLoadMovingToolStates

Description
Returns if loading of moving tool stats from savegame is allowed
Definition
allowLoadMovingToolStates()
Return Values
booleanisAllowedis allowed
Code
1893function Cylindered:allowLoadMovingToolStates(superFunc)
1894 if superFunc ~= nil then
1895 return superFunc(self);
1896 end
1897 return true;
1898end