LUADOC - Farming Simulator 17

Printable Version

Attachable

Description
This is the specialization for all vehicles that may be attached
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 Attachable.prerequisitesPresent(specializations)
18 return SpecializationUtil.hasSpecialization(Lights, specializations);
19end

preLoad

Description
Called before loading
Definition
preLoad(table savegame)
Arguments
tablesavegamesavegame
Code
24function Attachable:preLoad(savegame)
25 self.isDetachAllowed = Utils.overwrittenFunction(self.isDetachAllowed, Attachable.isDetachAllowed);
26 self.getIsInWorkPosition = Utils.overwrittenFunction(self.getIsInWorkPosition, Attachable.getIsInWorkPosition);
27 self.loadInputAttacherJoint = Utils.overwrittenFunction(self.loadInputAttacherJoint, Attachable.loadInputAttacherJoint);
28 self.getIsPowerTakeoffActive = Utils.overwrittenFunction(self.getIsPowerTakeoffActive, Attachable.getIsPowerTakeoffActive);
29 self.getIsInputAttacherActive = Utils.overwrittenFunction(self.getIsInputAttacherActive, Attachable.getIsInputAttacherActive);
30 self.getSteeringAxleBaseVehicle = Utils.overwrittenFunction(self.getSteeringAxleBaseVehicle, Attachable.getSteeringAxleBaseVehicle);
31 self.loadInputPowerTakeoff = Utils.overwrittenFunction(self.loadInputPowerTakeoff, Attachable.loadInputPowerTakeoff);
32 self.getIsOperating = Utils.overwrittenFunction(self.getIsOperating, Attachable.getIsOperating);
33 self.onAttach = SpecializationUtil.callSpecializationsFunction("onAttach");
34 self.onAttached = SpecializationUtil.callSpecializationsFunction("onAttached");
35 self.onPreAttach = SpecializationUtil.callSpecializationsFunction("onPreAttach");
36 self.onDetach = SpecializationUtil.callSpecializationsFunction("onDetach");
37 self.onDetached = SpecializationUtil.callSpecializationsFunction("onDetached");
38 self.onSelect = SpecializationUtil.callSpecializationsFunction("onSelect");
39 self.onDeselect = SpecializationUtil.callSpecializationsFunction("onDeselect");
40 self.onBrake = SpecializationUtil.callSpecializationsFunction("onBrake");
41 self.onReleaseBrake = SpecializationUtil.callSpecializationsFunction("onReleaseBrake");
42 self.onSetLowered = SpecializationUtil.callSpecializationsFunction("onSetLowered");
43 self.onLowerAll = SpecializationUtil.callSpecializationsFunction("onLowerAll");
44 self.attachableAddToolCameras = SpecializationUtil.callSpecializationsFunction("attachableAddToolCameras");
45 self.attachableRemoveToolCameras = SpecializationUtil.callSpecializationsFunction("attachableRemoveToolCameras");
46end

load

Description
Called on loading
Definition
load(table savegame)
Arguments
tablesavegamesavegame
Code
51function Attachable:load(savegame)
52
53 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.powerTakeoffInput", "vehicle.inputAttacherJoints.inputAttacherJoint#ptoInputNode")
54 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.attacherJoint", "vehicle.inputAttacherJoints.inputAttacherJoint")
55 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.needsLowering", "vehicle.inputAttacherJoints.inputAttacherJoint#needsLowering")
56 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.allowsLowering", "vehicle.inputAttacherJoints.inputAttacherJoint#allowsLowering")
57 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.isDefaultLowered", "vehicle.inputAttacherJoints.inputAttacherJoint#isDefaultLowered")
58 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.forceSelectionOnAttach#value", "vehicle.inputAttacherJoints.inputAttacherJoint#forceSelectionOnAttach")
59 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.topReferenceNode#index", "vehicle.attacherJoint#topReferenceNode")
60 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.attachRootNode#index", "vehicle.attacherJoint#rootNode")
61
62 self.attacherJoint = nil;
63
64 self.inputAttacherJoints = {};
65 local i = 0;
66 while true do
67 local key = string.format("vehicle.inputAttacherJoints.inputAttacherJoint(%d)", i);
68 if not hasXMLProperty(self.xmlFile, key) then
69 break;
70 end
71
72 local inputAttacherJoint = {};
73 if self:loadInputAttacherJoint(self.xmlFile, key, inputAttacherJoint, i) then
74 table.insert(self.inputAttacherJoints, inputAttacherJoint);
75 end
76
77 i = i + 1;
78 end
79
80 if self.configurations["inputAttacherJoint"] ~= nil then
81 local attacherConfigs = string.format("vehicle.inputAttacherJointConfigurations.inputAttacherJointConfiguration(%d)", self.configurations["inputAttacherJoint"]-1);
82 local i=0;
83 while true do
84 local baseName = string.format(attacherConfigs..".inputAttacherJoint(%d)", i);
85 if not hasXMLProperty(self.xmlFile, baseName) then
86 break;
87 end
88 local inputAttacherJoint = {};
89 if self:loadInputAttacherJoint(self.xmlFile, baseName, inputAttacherJoint, i) then
90 table.insert(self.inputAttacherJoints, inputAttacherJoint);
91 end
92 i = i + 1;
93 end
94 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.inputAttacherJointConfigurations.inputAttacherJointConfiguration", self.configurations["inputAttacherJoint"], self.components, self);
95 end
96
97 self.brakeForce = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.brakeForce"), 0)*10;
98 self.brakePedal = 0.0;
99 self.updateWheels = true;
100 self.updateSteeringAxleAngle = true;
101
102 self.isSelected = false;
103 self.attachTime = 0;
104
105 self.steeringAxleAngleScaleStart = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.steeringAxleAngleScale#startSpeed"), 10);
106 self.steeringAxleAngleScaleEnd = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.steeringAxleAngleScale#endSpeed"), 30);
107 self.steeringAxleUpdateBackwards = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.steeringAxleAngleScale#backwards"), false);
108 self.steeringAxleAngleSpeed = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.steeringAxleAngleScale#speed"), 0.001);
109 self.steeringAxleUseSuperAttachable = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.steeringAxleAngleScale#useSuperAttachable"), false);
110
111 self.supportAnimation = getXMLString(self.xmlFile, "vehicle.support#animationName");
112 self.lowerAnimation = getXMLString(self.xmlFile, "vehicle.lowerAnimation#name");
113 self.lowerAnimationSpeed = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.lowerAnimation#speed"), 1);
114 self.lowerAnimationDirectionOnDetach = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.lowerAnimation#directionOnDetach"), 0);
115
116 local defaultNeedsLowering = false;
117 for _, joint in pairs(self.inputAttacherJoints) do
118 if joint.needsLowering then
119 defaultNeedsLowering = true;
120 break;
121 end
122 end
123 self.aiNeedsLowering = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.ai.needsLowering#value"), defaultNeedsLowering);
124 self.aiLowerIfAnyIsLowerd = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.ai.needsLowering#lowerIfAnyIsLowerd"), false);
125 self.aiForceTurnNoBackward = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.ai.forceTurnNoBackward#value"), false);
126
127 self.aiToolReverserDirectionNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.ai.toolReverserDirectionNode#index"));
128 self.aiSkipWorkAreaLengthOnTurn = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.ai.skipWorkAreaLengthOnTurn#value"), false);
129
130 self.aiTurningRadiusLimitation = {};
131 self.aiTurningRadiusLimitation.rotationJoint = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.ai.turningRadiusLimitation#rotationJointNode"));
132 if self.aiTurningRadiusLimitation.rotationJoint == nil then
133 self.aiTurningRadiusLimitation.rotationJoint = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.ai.turningRadiusLimiation#rotationJointNode"));
134 end
135 if self.aiTurningRadiusLimitation.rotationJoint ~= nil then
136 self.aiTurningRadiusLimitation.wheelIndices = { Utils.getVectorFromString(getXMLString(self.xmlFile, "vehicle.ai.turningRadiusLimitation#wheelIndices")) };
137 if #self.aiTurningRadiusLimitation.wheelIndices == 0 then
138 self.aiTurningRadiusLimitation.wheelIndices = { Utils.getVectorFromString(getXMLString(self.xmlFile, "vehicle.ai.turningRadiusLimiation#wheelIndices")) };
139 end
140 end
141 self.aiTurningRadiusLimitation.radius = getXMLFloat(self.xmlFile, "vehicle.ai.turningRadiusLimitation#radius");
142 if self.aiTurningRadiusLimitation.radius == nil then
143 self.aiTurningRadiusLimitation.radius = getXMLFloat(self.xmlFile, "vehicle.ai.turningRadiusLimiation#radius");
144 end
145
146 if table.getn(self.inputAttacherJoints) > 0 then
147 -- all attachables are selectable, since they need to be detached
148 self.isSelectable = true
149 end
150
151 self.numToolCameras = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.toolCameras#count"), 0);
152 self.toolCameras = {};
153 for i=1, self.numToolCameras do
154 local cameraKey = string.format("vehicle.toolCameras.toolCamera%d", i);
155 local camera = VehicleCamera:new(self);
156 if camera:loadFromXML(self.xmlFile, cameraKey) then
157 table.insert(self.toolCameras, camera);
158 end
159 end
160
161 self.isHardAttached = false
162end

postLoad

Description
Called after loading
Definition
postLoad(table savegame)
Arguments
tablesavegamesavegame
Code
167function Attachable:postLoad(savegame)
168 if self.supportAnimation ~= nil and self.playAnimation ~= nil then
169 self:playAnimation(self.supportAnimation, 1, nil, true);
170 end
171
172 if savegame ~= nil and not savegame.resetVehicles then
173 if self.lowerAnimation ~= nil and self.playAnimation ~= nil then
174 local lowerAnimTime = getXMLFloat(savegame.xmlFile, savegame.key.."#lowerAnimTime");
175 if lowerAnimTime ~= nil then
176 local speed = 1;
177 if lowerAnimTime < 0.5 then
178 speed = -1;
179 end
180 self:playAnimation(self.lowerAnimation, speed, nil, true);
181 self:setAnimationTime(self.lowerAnimation, lowerAnimTime);
182
183 if self.updateCylinderedInitial ~= nil then
184 self:updateCylinderedInitial(false);
185 end
186 end
187 end
188 end
189
190 for _, inputAttacherJoint in pairs(self.inputAttacherJoints) do
191 if inputAttacherJoint.steeringBarLeftNode ~= nil then
192 if self.nodesToMovingParts ~= nil and self.nodesToMovingParts[inputAttacherJoint.steeringBarLeftNode] ~= nil then
193 inputAttacherJoint.steeringBarLeftMovingPart = self.nodesToMovingParts[inputAttacherJoint.steeringBarLeftNode]
194 inputAttacherJoint.steeringBarLeftMovingPart.referencePointBackup = inputAttacherJoint.steeringBarLeftMovingPart.referencePoint
195 else
196 inputAttacherJoint.steeringBarLeftNode = nil
197 end
198 end
199 if inputAttacherJoint.steeringBarRightNode ~= nil then
200 if self.nodesToMovingParts ~= nil and self.nodesToMovingParts[inputAttacherJoint.steeringBarRightNode] ~= nil then
201 inputAttacherJoint.steeringBarRightMovingPart = self.nodesToMovingParts[inputAttacherJoint.steeringBarRightNode]
202 inputAttacherJoint.steeringBarRightMovingPart.referencePointBackup = inputAttacherJoint.steeringBarRightMovingPart.referencePoint
203 else
204 inputAttacherJoint.steeringBarRightNode = nil
205 end
206 end
207 end
208
209 self:onBrake(1, true);
210end

loadInputAttacherJoint

Description
Called on loading
Definition
loadInputAttacherJoint(table savegame)
Arguments
tablesavegamesavegame
Code
215function Attachable:loadInputAttacherJoint(superFunc, xmlFile, key, inputAttacherJoint, index)
216 if superFunc ~= nil then
217 if not superFunc(self, xmlFile, key, inputAttacherJoint, index) then
218 return false;
219 end
220 end
221
222 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#index"));
223 if node ~= nil then
224 inputAttacherJoint.node = node;
225
226 local jointTypeStr = getXMLString(xmlFile, key .. "#jointType")
227 local jointType;
228 if jointTypeStr ~= nil then
229 jointType = AttacherJoints.jointTypeNameToInt[jointTypeStr];
230 if jointType == nil then
231 print("Warning: invalid jointType " .. jointTypeStr .. " for inputAttacherJoint "..(index+1).." in "..self.configFileName.."!");
232 end
233 else
234 print("Warning: missing jointType for inputAttacherJoint "..(index+1).."!");
235 end
236 if jointType == nil then
237 local needsTrailerJoint = Utils.getNoNil(getXMLBool(xmlFile, key .. "#needsTrailerJoint"), false);
238 local needsLowTrailerJoint = Utils.getNoNil(getXMLBool(xmlFile, key .. "#needsLowJoint"), false);
239 if needsTrailerJoint then
240 if needsLowTrailerJoint then
241 jointType = AttacherJoints.JOINTTYPE_TRAILERLOW;
242 else
243 jointType = AttacherJoints.JOINTTYPE_TRAILER;
244 end
245 else
246 jointType = AttacherJoints.JOINTTYPE_IMPLEMENT;
247 end
248 end
249 inputAttacherJoint.jointType = jointType;
250
251 inputAttacherJoint.jointOrigTrans = { getTranslation(inputAttacherJoint.node) };
252 inputAttacherJoint.topReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#topReferenceNode"));
253 inputAttacherJoint.rootNode = Utils.getNoNil(Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#rootNode")), self.components[1].node);
254 inputAttacherJoint.rootNodeBackup = inputAttacherJoint.rootNode
255 inputAttacherJoint.fixedRotation = Utils.getNoNil(getXMLBool(xmlFile, key .. "#fixedRotation"), false);
256 inputAttacherJoint.hardAttach = Utils.getNoNil(getXMLBool(xmlFile, key .. "#hardAttach"), false);
257 if inputAttacherJoint.hardAttach and #self.components > 1 then
258 print("Warning: hardAttach only available for single component vehicles in " .. self.configFileName.."!")
259 inputAttacherJoint.hardAttach = false
260 end
261 inputAttacherJoint.visualNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#indexVisual"));
262 if inputAttacherJoint.hardAttach and inputAttacherJoint.visualNode ~= nil then
263 inputAttacherJoint.visualNodeData = {
264 parent = getParent(inputAttacherJoint.visualNode),
265 translation = { getTranslation(inputAttacherJoint.visualNode) },
266 rotation = { getRotation(inputAttacherJoint.visualNode) },
267 index = getChildIndex(inputAttacherJoint.visualNode)
268 }
269 end
270
271
272 if jointType == AttacherJoints.JOINTTYPE_IMPLEMENT or jointType == AttacherJoints.JOINTTYPE_CUTTER then
273 if getXMLFloat(xmlFile, key .. "#lowerDistanceToGround") == nil then
274 print("Warning: Missing 'lowerDistanceToGround' for inputAttacherJoint "..(index+1).." in "..self.configFileName.."!");
275 end
276 if getXMLFloat(xmlFile, key .. "#upperDistanceToGround") == nil then
277 print("Warning: Missing 'upperDistanceToGround' for inputAttacherJoint "..(index+1).." in "..self.configFileName.."!");
278 end
279 end
280 inputAttacherJoint.lowerDistanceToGround = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#lowerDistanceToGround"), 0.7);
281 inputAttacherJoint.upperDistanceToGround = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#upperDistanceToGround"), 1.0);
282 inputAttacherJoint.lowerRotationOffset = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, key .. "#lowerRotationOffset"), 0));
283
284
285 local defaultUpperRotationOffset = 8
286 if jointType == AttacherJoints.JOINTTYPE_WHEELLOADER or jointType == AttacherJoints.JOINTTYPE_TELEHANDLER or jointType == AttacherJoints.JOINTTYPE_FRONTLOADER then
287 defaultUpperRotationOffset = 0
288 end
289
290 inputAttacherJoint.upperRotationOffset = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, key .. "#upperRotationOffset"), defaultUpperRotationOffset));
291
292 inputAttacherJoint.allowsJointRotLimitMovement = Utils.getNoNil(getXMLBool(xmlFile, key .. "#allowsJointRotLimitMovement"), true);
293 inputAttacherJoint.allowsJointTransLimitMovement = Utils.getNoNil(getXMLBool(xmlFile, key .. "#allowsJointTransLimitMovement"), true);
294
295 inputAttacherJoint.needsToolbar = Utils.getNoNil(getXMLBool(xmlFile, key .. "#needsToolbar"), false);
296 if inputAttacherJoint.needsToolbar and jointType ~= AttacherJoints.JOINTTYPE_IMPLEMENT then
297 print("Warning: 'needsToolbar' requires jointType 'implement' for inputAttacherJoint "..(index+1).." in "..self.configFileName.."!");
298 inputAttacherJoint.needsToolbar = false
299 end
300
301 inputAttacherJoint.steeringBarLeftNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#steeringBarLeftNode"));
302 inputAttacherJoint.steeringBarRightNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#steeringBarRightNode"));
303
304 --load joint limit scales
305 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key .. "#upperRotLimitScale"));
306 inputAttacherJoint.upperRotLimitScale = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) };
307 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key .. "#lowerRotLimitScale"));
308 if jointType == AttacherJoints.JOINTTYPE_IMPLEMENT then
309 inputAttacherJoint.lowerRotLimitScale = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 1) };
310 else
311 inputAttacherJoint.lowerRotLimitScale = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) };
312 end
313
314 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key .. "#upperTransLimitScale"));
315 inputAttacherJoint.upperTransLimitScale = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) };
316 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key .. "#lowerTransLimitScale"));
317 inputAttacherJoint.lowerTransLimitScale = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 1), Utils.getNoNil(z, 0) };
318
319 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotLimitSpring"));
320 inputAttacherJoint.rotLimitSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) };
321 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotLimitDamping"));
322 inputAttacherJoint.rotLimitDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) };
323 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotLimitForceLimit"));
324 inputAttacherJoint.rotLimitForceLimit = { Utils.getNoNil(x, -1), Utils.getNoNil(y, -1), Utils.getNoNil(z, -1) };
325
326 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#transLimitSpring"));
327 inputAttacherJoint.transLimitSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) };
328 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#transLimitDamping"));
329 inputAttacherJoint.transLimitDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) };
330 local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#transLimitForceLimit"));
331 inputAttacherJoint.transLimitForceLimit = { Utils.getNoNil(x, -1), Utils.getNoNil(y, -1), Utils.getNoNil(z, -1) };
332
333 inputAttacherJoint.attacherHeight = getXMLFloat(xmlFile, key .. "#attacherHeight");
334 if inputAttacherJoint.attacherHeight == nil then
335 if jointType == AttacherJoints.JOINTTYPE_TRAILER then
336 inputAttacherJoint.attacherHeight = 0.9;
337 elseif jointType == AttacherJoints.JOINTTYPE_TRAILERLOW then
338 inputAttacherJoint.attacherHeight = 0.55;
339 end
340 end
341
342 local defaultNeedsLowering = true;
343 local defaultAllowsLowering = false;
344 if inputAttacherJoint.jointType == AttacherJoints.JOINTTYPE_TRAILER or inputAttacherJoint.jointType == AttacherJoints.JOINTTYPE_TRAILERLOW then
345 defaultNeedsLowering = false;
346 end
347 if inputAttacherJoint.jointType ~= AttacherJoints.JOINTTYPE_TRAILER and inputAttacherJoint.jointType ~= AttacherJoints.JOINTTYPE_TRAILERLOW then
348 defaultAllowsLowering = true;
349 end
350 inputAttacherJoint.needsLowering = Utils.getNoNil(getXMLBool(xmlFile, key.. "#needsLowering"), defaultNeedsLowering);
351 inputAttacherJoint.allowsLowering = Utils.getNoNil(getXMLBool(xmlFile, key.. "#allowsLowering"), defaultAllowsLowering);
352 inputAttacherJoint.isDefaultLowered = Utils.getNoNil(getXMLBool(xmlFile, key.. "#isDefaultLowered"), false);
353 inputAttacherJoint.useFoldingLoweredState = Utils.getNoNil(getXMLBool(xmlFile, key.. "#useFoldingLoweredState"), false);
354 inputAttacherJoint.forceSelection = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#forceSelectionOnAttach"), true);
355
356 inputAttacherJoint.dependentAttacherJoints = {}
357 local k = 0
358 while true do
359 local dependentKey = string.format(key .. ".dependentAttacherJoint(%d)", k)
360 if not hasXMLProperty(xmlFile, dependentKey) then
361 break
362 end
363 local attacherJointIndex = getXMLInt(xmlFile, dependentKey.."#attacherJointIndex")
364 if attacherJointIndex ~= nil then
365 table.insert(inputAttacherJoint.dependentAttacherJoints, attacherJointIndex)
366 end
367 k = k + 1
368 end
369
370 -- reset values if hardAttach is active
371 if inputAttacherJoint.hardAttach then
372 inputAttacherJoint.needsLowering = false
373 inputAttacherJoint.allowsLowering = false
374 inputAttacherJoint.isDefaultLowered = false
375 inputAttacherJoint.upperRotationOffset = 0
376 end
377
378 inputAttacherJoint.changeObjects = {};
379 ObjectChangeUtil.loadObjectChangeFromXML(xmlFile, key, inputAttacherJoint.changeObjects, self.components, self);
380
381 self:loadInputPowerTakeoff(xmlFile, key, inputAttacherJoint, "pto");
382 self:loadInputPowerTakeoff(xmlFile, key, inputAttacherJoint, "pto2");
383
384 return true;
385 end
386
387 return false;
388end

loadInputPowerTakeoff

Description
Called on loading
Definition
loadInputPowerTakeoff(table savegame)
Arguments
tablesavegamesavegame
Code
393function Attachable:loadInputPowerTakeoff(superFunc, xmlFile, baseName, entry, name)
394 if superFunc ~= nil then
395 superFunc(self, xmlFile, baseName, entry, name)
396 end
397
398 if name == "pto" then
399 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#indexPTO", baseName.."#ptoInputNode")
400 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#rotSpeedPTO", baseName.."#ptoRotSpeed")
401 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#aboveAttacherPTO", baseName.."#ptoAboveAttacher")
402 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#sizePTO", baseName.."#ptoSize")
403 Utils.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#overrideFilenamePTO", baseName.."#ptoOverrideFilename")
404 end
405
406 local xmlKey = baseName .. "#"..name
407 local ptoInputNode = Utils.indexToObject(self.components, getXMLString(xmlFile, xmlKey.."InputNode"));
408 if ptoInputNode ~= nil then
409 if entry[name.."Input"] == nil then
410 entry[name.."Input"] = {}
411 end
412
413 entry[name.."Input"].node = ptoInputNode
414 entry[name.."Input"].aboveAttacher = Utils.getNoNil(getXMLBool(xmlFile, xmlKey.."AboveAttacher"), true)
415 entry[name.."Input"].size = Utils.getNoNil(getXMLFloat(xmlFile, xmlKey.."Size"), 0.09)
416
417 local rotSpeed = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, xmlKey.."RotSpeed"), 0)*0.001);
418 if math.abs(rotSpeed) < 0.00001 then
419 rotSpeed = 0;
420 end
421 entry[name.."Input"].rotSpeed = rotSpeed
422
423 local filename = getXMLString(xmlFile, xmlKey .. "OverrideFilename");
424 if filename ~= nil then
425 local i3dNode = Utils.loadSharedI3DFile(filename, self.baseDirectory, false, false, false);
426 if i3dNode ~= 0 then
427 local rootNode = getChildAt(i3dNode, 0);
428 unlink(rootNode);
429 delete(i3dNode);
430 setTranslation(rootNode, 0,0,0);
431 local dirAndScaleNode = getChildAt(rootNode, 0);
432 local attachNode = getChildAt(dirAndScaleNode, 0);
433 local attachRefNode = getChildAt(attachNode, 0);
434
435 local _,_,baseDistance = getTranslation(attachNode);
436 unlink(attachNode);
437 local ax, ay, az = getTranslation(attachRefNode);
438 setTranslation(attachNode, -ax, -ay, -az);
439
440 entry[name.."Input"].rootNode = rootNode;
441 entry[name.."Input"].dirAndScaleNode = dirAndScaleNode;
442 entry[name.."Input"].attachNode = attachNode;
443 entry[name.."Input"].baseDistance = baseDistance;
444
445 end
446 end
447 end
448end

preDelete

Description
Called on before deleting
Definition
preDelete()
Code
452function Attachable:preDelete()
453 if self.attacherVehicle ~= nil then
454 self.attacherVehicle:detachImplementByObject(self, true);
455 end
456end

delete

Description
Called on deleting
Definition
delete()
Code
460function Attachable:delete()
461 if self.ptoInput ~= nil and self.ptoInput.rootNode ~= nil then
462 delete(self.ptoInput.rootNode);
463 delete(self.ptoInput.attachNode);
464 end
465 if self.pto2Input ~= nil and self.pto2Input.rootNode ~= nil then
466 delete(self.pto2Input.rootNode);
467 delete(self.pto2Input.attachNode);
468 end
469end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
475function Attachable:readStream(streamId, connection)
476 if streamReadBool(streamId) then
477 local object = readNetworkNodeObject(streamId);
478 local inputJointDescIndex = streamReadInt8(streamId);
479 local jointDescIndex = streamReadInt8(streamId);
480 local moveDown = streamReadBool(streamId);
481 local implementIndex = streamReadInt8(streamId);
482 if object ~= nil then
483 object:attachImplement(self, inputJointDescIndex, jointDescIndex, true, implementIndex);
484 object:setJointMoveDown(jointDescIndex, moveDown, true);
485 end
486 end
487end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
493function Attachable:writeStream(streamId, connection)
494 streamWriteBool(streamId, self.attacherVehicle ~= nil);
495 if self.attacherVehicle ~= nil then
496 local implementIndex = self.attacherVehicle:getImplementIndexByObject(self);
497 local implement = self.attacherVehicle.attachedImplements[implementIndex];
498 local inputJointDescIndex = self.inputAttacherJointDescIndex;
499 local jointDescIndex = implement.jointDescIndex;
500 local jointDesc = self.attacherVehicle.attacherJoints[jointDescIndex];
501 local moveDown = jointDesc.moveDown;
502 writeNetworkNodeObject(streamId, self.attacherVehicle);
503 streamWriteInt8(streamId, inputJointDescIndex);
504 streamWriteInt8(streamId, jointDescIndex);
505 streamWriteBool(streamId, moveDown);
506 streamWriteInt8(streamId, implementIndex);
507 end
508end

getSaveAttributesAndNodes

Description
Returns attributes and nodes to save
Definition
getSaveAttributesAndNodes(table nodeIdent)
Arguments
tablenodeIdentnode ident
Return Values
stringattributesattributes
stringnodesnodes
Code
515function Attachable:getSaveAttributesAndNodes(nodeIdent)
516 local attributes = '';
517 if self.lowerAnimation ~= nil and self.playAnimation ~= nil then
518 local lowerAnimTime = self:getAnimationTime(self.lowerAnimation);
519 attributes = attributes..' lowerAnimTime="'..lowerAnimTime..'"';
520 end
521 local nodes = "";
522 return attributes, nodes;
523end

update

Description
Called on update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
534function Attachable:update(dt)
535 if self:getIsActive() then
536 if self.updateSteeringAxleAngle then
537 local baseVehicle = self:getSteeringAxleBaseVehicle()
538 if baseVehicle ~= nil and (self.movingDirection >= 0 or self.steeringAxleUpdateBackwards) then
539 local yRot = Utils.getYRotationBetweenNodes(self.steeringAxleNode, baseVehicle.steeringAxleNode);
540 if math.abs(yRot) > 1.57 then
541 if yRot > 0 then
542 yRot = yRot - 3.14;
543 else
544 yRot = yRot + 3.14;
545 end;
546 end;
547
548 local startSpeed = self.steeringAxleAngleScaleStart;
549 local endSpeed = self.steeringAxleAngleScaleEnd;
550 local scale = Utils.clamp(1 + (self:getLastSpeed()-startSpeed) * 1.0/(startSpeed-endSpeed), 0, 1);
551 self.steeringAxleTargetAngle = yRot*scale;
552 elseif self:getLastSpeed() > 0.2 then
553 self.steeringAxleTargetAngle = 0;
554 end
555
556 local dir = Utils.sign(self.steeringAxleTargetAngle-self.steeringAxleAngle);
557 if dir == 1 then
558 self.steeringAxleAngle = math.min(self.steeringAxleAngle + dir*dt*self.steeringAxleAngleSpeed, self.steeringAxleTargetAngle);
559 else
560 self.steeringAxleAngle = math.max(self.steeringAxleAngle + dir*dt*self.steeringAxleAngleSpeed, self.steeringAxleTargetAngle);
561 end
562 end
563
564 if self.firstTimeRun and self.updateWheels and self.isServer and self.isAddedToPhysics then
565 local brakeForce = self.brakeForce*self.brakePedal;
566 for _,wheel in pairs(self.wheels) do
567 setWheelShapeProps(wheel.node, wheel.wheelShape, 0, brakeForce*wheel.brakeFactor, wheel.steeringAngle, wheel.rotationDamping);
568 end
569 end
570 end
571end

onPreAttach

Description
Called before vehicle gets attached
Definition
onPreAttach(table attacherVehicle, integer inputAttacherJointDescIndex)
Arguments
tableattacherVehicleattacher vehicle
integerinputAttacherJointDescIndexindex of input attacher joint
Code
580function Attachable:onPreAttach(attacherVehicle, inputAttacherJointDescIndex)
581 self.ptoInput = self.inputAttacherJoints[inputAttacherJointDescIndex].ptoInput;
582 self.pto2Input = self.inputAttacherJoints[inputAttacherJointDescIndex].pto2Input;
583 self.attacherJoint = self.inputAttacherJoints[inputAttacherJointDescIndex];
584 self.inputAttacherJointDescIndex = inputAttacherJointDescIndex;
585end

onAttached

Description
Called after vehicle was attached
Definition
onAttached(table attacherVehicle, table implement)
Arguments
tableattacherVehicleattacher vehicle
tableimplementimplement to attach
Code
591function Attachable:onAttached(attacherVehicle, implement)
592 local jointDesc = attacherVehicle.attacherJoints[implement.jointDescIndex];
593
594 if jointDesc.steeringBarLeftNode ~= nil and self.attacherJoint.steeringBarLeftMovingPart ~= nil then
595 for _,movingPart in pairs(self.movingParts) do
596 if movingPart.referencePoint == self.attacherJoint.steeringBarLeftMovingPart.referencePoint and movingPart ~= self.attacherJoint.steeringBarLeftMovingPart then
597 movingPart.referencePoint = jointDesc.steeringBarLeftNode;
598 end
599 end
600 self.attacherJoint.steeringBarLeftMovingPart.referencePoint = jointDesc.steeringBarLeftNode
601 end
602 if jointDesc.steeringBarRightNode ~= nil and self.attacherJoint.steeringBarRightMovingPart ~= nil then
603 for _,movingPart in pairs(self.movingParts) do
604 if movingPart.referencePoint == self.attacherJoint.steeringBarRightMovingPart.referencePoint and movingPart ~= self.attacherJoint.steeringBarRightMovingPart then
605 movingPart.referencePoint = jointDesc.steeringBarRightNode;
606 end
607 end
608 self.attacherJoint.steeringBarRightMovingPart.referencePoint = jointDesc.steeringBarRightNode
609 end
610end

onAttach

Description
Called if vehicle gets attached
Definition
onAttach(table attacherVehicle, integer jointDescIndex)
Arguments
tableattacherVehicleattacher vehicle
integerjointDescIndexindex of attacher joint it gets attached to
Code
616function Attachable:onAttach(attacherVehicle, jointDescIndex)
617 self.attacherVehicle = attacherVehicle;
618 self:setLightsTypesMask(attacherVehicle.lightsTypesMask, true, true);
619 self:setBeaconLightsVisibility(attacherVehicle.beaconLightsActive, true, true);
620 self:setTurnLightState(attacherVehicle.turnLightState, true, true);
621
622 self.attachTime = g_currentMission.time;
623
624 self:onReleaseBrake();
625
626 if self.supportAnimation ~= nil and self.playAnimation ~= nil then
627 self:playAnimation(self.supportAnimation, -1, nil, true);
628 end
629
630 self:attachableAddToolCameras();
631
632 local rootAttacherVehicle = self:getRootAttacherVehicle();
633 if rootAttacherVehicle ~= nil and rootAttacherVehicle.aiToolsDirtyFlag ~= nil then
634 rootAttacherVehicle.aiToolsDirtyFlag = true;
635 end
636
637 ObjectChangeUtil.setObjectChanges(self.attacherJoint.changeObjects, true, self, self.setMovingToolDirty);
638end

onDetach

Description
Called if vehicle gets detached
Definition
onDetach(table attacherVehicle, integer jointDescIndex)
Arguments
tableattacherVehicleattacher vehicle
integerjointDescIndexindex of attacher joint it was attached to
Code
644function Attachable:onDetach(attacherVehicle, jointDescIndex)
645 self:onDeactivate();
646
647 ObjectChangeUtil.setObjectChanges(self.attacherJoint.changeObjects, false, self, self.setMovingToolDirty);
648
649
650 if self.supportAnimation ~= nil and self.playAnimation ~= nil then
651 self:playAnimation(self.supportAnimation, 1, nil, true);
652 end
653
654 if self.lowerAnimation ~= nil and self.lowerAnimationDirectionOnDetach ~= 0 then
655 self:playAnimation(self.lowerAnimation, self.lowerAnimationDirectionOnDetach, nil, true);
656 end
657
658 self:attachableRemoveToolCameras();
659
660 self.attacherVehicle = nil;
661end

onDetached

Description
Called after vehicle was detached
Definition
onDetached(table attacherVehicle, integer jointDescIndex)
Arguments
tableattacherVehicleattacher vehicle
integerjointDescIndexindex of attacher joint it was attached to
Code
667function Attachable:onDetached(attacherVehicle, jointDescIndex)
668 self.attacherJoint = nil;
669 self.attacherJointIndex = nil;
670end

onDeactivate

Description
Called on deactivate
Definition
onDeactivate()
Code
674function Attachable:onDeactivate()
675 self:onBrake(1, true);
676end

onSelect

Description
Called on select
Definition
onSelect()
Code
680function Attachable:onSelect()
681 self.isSelected = true;
682end

onDeselect

Description
Called on deselect
Definition
onDeselect()
Code
686function Attachable:onDeselect()
687 self.isSelected = false;
688end

onBrake

Description
Break the vehicle
Definition
onBrake(float brakePedal, boolean forced)
Arguments
floatbrakePedalforce of brake
booleanforcedforce action
Code
694function Attachable:onBrake(brakePedal, forced)
695 -- do not brake for the first 2 seconds after attaching, to allow balancing of the difference between the attacher joints
696 if self.attachTime+2000 < g_currentMission.time or forced then
697 self.brakePedal = brakePedal;
698 if self.isServer and self.isAddedToPhysics then
699 for _,wheel in pairs(self.wheels) do
700 setWheelShapeProps(wheel.node, wheel.wheelShape, 0, self.brakeForce*brakePedal*wheel.brakeFactor, wheel.steeringAngle, wheel.rotationDamping);
701 end
702 end
703 for _,implement in pairs(self.attachedImplements) do
704 if implement.object ~= nil then
705 implement.object:onBrake(brakePedal, forced);
706 end
707 end
708 end
709end

onReleaseBrake

Description
Release the brake
Definition
onReleaseBrake()
Code
713function Attachable:onReleaseBrake()
714 self.brakePedal = 0;
715 if self.isServer and self.isAddedToPhysics then
716 for _,wheel in pairs(self.wheels) do
717 setWheelShapeProps(wheel.node, wheel.wheelShape, 0, 0, wheel.steeringAngle, wheel.rotationDamping);
718 end
719 end
720 for _,implement in pairs(self.attachedImplements) do
721 if implement.object ~= nil then
722 implement.object:onReleaseBrake();
723 end
724 end
725end

onSetLowered

Description
Set attachables lowering state
Definition
onSetLowered(boolean lowered)
Arguments
booleanloweredattachable is lowered
Code
730function Attachable:onSetLowered(lowered)
731 if self.lowerAnimation ~= nil and self.playAnimation ~= nil then
732 if lowered then
733 self:playAnimation(self.lowerAnimation, self.lowerAnimationSpeed, nil, true);
734 else
735 self:playAnimation(self.lowerAnimation, -self.lowerAnimationSpeed, nil, true);
736 end
737 end
738
739 if self.attacherJoint ~= nil then
740 for _, dependentAttacherJointIndex in pairs(self.attacherJoint.dependentAttacherJoints) do
741 if self.attacherJoints[dependentAttacherJointIndex] ~= nil then
742 self:setJointMoveDown(dependentAttacherJointIndex, lowered, true);
743 end
744 end
745 end
746end

onLowerAll

Description
Lower all
Definition
onLowerAll(boolean doLowering, integer jointDescIndex)
Arguments
booleandoLoweringdo lowering
integerjointDescIndexindex of joint desc
Code
752function Attachable:onLowerAll(doLowering, jointDescIndex)
753 self.attacherVehicle:setJointMoveDown(jointDescIndex, doLowering, true);
754end

getIsInWorkPosition

Description
Returns true if it is in work position
Definition
getIsInWorkPosition()
Return Values
booleaninWorkPositionis in work position
Code
759function Attachable:getIsInWorkPosition(superFunc)
760 if superFunc ~= nil then
761 if not superFunc(self) then
762 return false;
763 end
764 end
765
766 return true;
767end

isDetachAllowed

Description
Returns true if detach is allowed
Definition
isDetachAllowed()
Return Values
booleandetachAlloweddetach is allowed
Code
772function Attachable:isDetachAllowed(superFunc)
773 if superFunc ~= nil then
774 if not superFunc(self) then
775 return false;
776 end
777 end
778
779 return Utils.getNoNil(self.allowsDetaching, true)
780end

getIsInputAttacherActive

Description
Returns true if input attacher is active and can be used to attach
Definition
getIsInputAttacherActive(table inputAttacherJoint)
Arguments
tableinputAttacherJointinput attacher joint
Return Values
booleanisActiveinput attacher is active
Code
786function Attachable:getIsInputAttacherActive(superFunc, inputAttacherJoint)
787 if superFunc ~= nil then
788 if not superFunc(self, inputAttacherJoint) then
789 return false;
790 end
791 end
792
793 return true;
794end

getSteeringAxleBaseVehicle

Description
Returns vehicle used to calculate steering axle
Definition
getSteeringAxleBaseVehicle()
Return Values
tablevehiclevehicle
Code
799function Attachable:getSteeringAxleBaseVehicle(superFunc)
800 if self.steeringAxleUseSuperAttachable then
801 if self.attacherVehicle ~= nil then
802 return self.attacherVehicle.attacherVehicle;
803 end;
804 end
805
806 return self.attacherVehicle;
807end

getIsPowerTakeoffActive

Description
Returns true if pto is active
Definition
getIsPowerTakeoffActive()
Return Values
booleanisActivepto is active
Code
812function Attachable:getIsPowerTakeoffActive(superFunc)
813 if superFunc ~= nil then
814 if not superFunc(self) then
815 return false;
816 end
817 end
818
819 if self:getIsTurnedOn() then
820 return true;
821 end
822
823 return false;
824end

attachableAddToolCameras

Description
Add tool cameras to root attacher vehicle
Definition
attachableAddToolCameras()
Code
828function Attachable:attachableAddToolCameras()
829 for _,implement in pairs(self.attachedImplements) do
830 if implement.object ~= nil then
831 implement.object:attachableAddToolCameras();
832 end
833 end
834 local rootAttacherVehicle = self:getRootAttacherVehicle();
835 if self.numToolCameras > 0 and rootAttacherVehicle.addToolCameras ~= nil then
836 rootAttacherVehicle:addToolCameras(self.toolCameras);
837 end
838end

attachableRemoveToolCameras

Description
Remove tool cameras from root attacher vehicle
Definition
attachableRemoveToolCameras()
Code
842function Attachable:attachableRemoveToolCameras()
843 for _,implement in pairs(self.attachedImplements) do
844 if implement.object ~= nil then
845 implement.object:attachableRemoveToolCameras();
846 end
847 end
848 local rootAttacherVehicle = self:getRootAttacherVehicle();
849 if self.numToolCameras > 0 and rootAttacherVehicle.removeToolCameras ~= nil then
850 rootAttacherVehicle:removeToolCameras(self.toolCameras);
851 end
852end

onAiRaise

Description
Called on ai raise
Definition
onAiRaise()
Code
856function Attachable:onAiRaise()
857 local implement = self.attacherVehicle:getImplementByObject(self);
858 local jointDesc = self.attacherVehicle.attacherJoints[implement.jointDescIndex];
859 if jointDesc.allowsLowering then
860 if self.aiNeedsLowering then
861 self.attacherVehicle:setJointMoveDown(implement.jointDescIndex, false, false);
862 end
863 end
864end

onAiLower

Description
Called on ai lower
Definition
onAiLower()
Code
868function Attachable:onAiLower()
869 local implement = self.attacherVehicle:getImplementByObject(self);
870 local jointDesc = self.attacherVehicle.attacherJoints[implement.jointDescIndex];
871 if jointDesc.allowsLowering then
872 if self.aiNeedsLowering then
873 self.attacherVehicle:setJointMoveDown(implement.jointDescIndex, true, false);
874 end
875 end
876end

getIsAIReadyForWork

Description
Returns true if vehicle is ready for ai work
Definition
getIsAIReadyForWork()
Return Values
booleanisReadyis ready for ai work
Code
881function Attachable:getIsAIReadyForWork()
882 local isReady = true;
883 if self.lowerAnimation ~= nil then
884 local t = self:getAnimationTime(self.lowerAnimation);
885 if self.lowerAnimationSpeed > 0 then
886 isReady = t == 1;
887 else
888 isReady = t == 0;
889 end
890 if not isReady then
891 if not self:getIsAnimationPlaying(self.lowerAnimation) then
892 self:playAnimation(self.lowerAnimation, self.lowerAnimationSpeed, self:getAnimationTime(self.lowerAnimation), false);
893 end
894 end
895 end
896
897 local implement = self.attacherVehicle:getImplementByObject(self);
898 local jointDesc = self.attacherVehicle.attacherJoints[implement.jointDescIndex];
899 if jointDesc.allowsLowering and self.aiNeedsLowering then
900 if jointDesc.moveDown then
901 return jointDesc.moveAlpha == jointDesc.lowerAlpha and isReady;
902 else
903 self.attacherVehicle:setJointMoveDown(implement.jointDescIndex, true, false);
904 return false;
905 end
906 else
907 return isReady;
908 end
909end

getIsOperating

Description
Returns if vehicle is operating
Definition
getIsOperating()
Return Values
booleanisOperatingis operating
Code
914function Attachable:getIsOperating(superFunc)
915 local isOperating = false
916 if superFunc ~= nil then
917 isOperating = superFunc(self)
918 end
919
920 if not isOperating and self.attacherVehicle ~= nil then
921 isOperating = self.attacherVehicle:getIsOperating()
922 end
923
924 return isOperating
925end