LUADOC - Farming Simulator 17

Printable Version

Motorized

Description
Class for all vehicles with motors
Functions

preLoad

Description
Called before loading
Definition
preLoad(table savegame)
Arguments
tablesavegamesavegame
Code
23function Motorized:preLoad(savegame)
24 self.addToPhysics = Utils.overwrittenFunction(self.addToPhysics, Motorized.addToPhysics);
25 self.removeFromPhysics = Utils.overwrittenFunction(self.removeFromPhysics, Motorized.removeFromPhysics);
26 self.getIsOperating = Utils.overwrittenFunction(self.getIsOperating, Motorized.getIsOperating);
27end

load

Description
Called on loading
Definition
load(table savegame)
Arguments
tablesavegamesavegame
Code
32function Motorized:load(savegame)
33
34 self.getIsMotorStarted = Utils.overwrittenFunction(self.getIsMotorStarted, Motorized.getIsMotorStarted);
35 self.getDeactivateOnLeave = Utils.overwrittenFunction(self.getDeactivateOnLeave, Motorized.getDeactivateOnLeave);
36 self.getDeactivateLights = Utils.overwrittenFunction(self.getDeactivateLights, Motorized.getDeactivateLights);
37 self.updateFuelUsage = Utils.overwrittenFunction(self.updateFuelUsage, Motorized.updateFuelUsage);
38 self.startMotor = SpecializationUtil.callSpecializationsFunction("startMotor");
39 self.stopMotor = SpecializationUtil.callSpecializationsFunction("stopMotor");
40 self.setIsFuelFilling = SpecializationUtil.callSpecializationsFunction("setIsFuelFilling");
41 self.setFuelFillLevel = SpecializationUtil.callSpecializationsFunction("setFuelFillLevel");
42 self.addFuelFillTrigger = Motorized.addFuelFillTrigger;
43 self.removeFuelFillTrigger = Motorized.removeFuelFillTrigger;
44
45 self.motorizedNode = nil;
46 for _, component in pairs(self.components) do
47 if component.motorized then
48 self.motorizedNode = component.node;
49 break;
50 end
51 end
52
53 Motorized.loadDifferentials(self, self.xmlFile, self.differentialIndex);
54 Motorized.loadMotor(self, self.xmlFile, self.configurations["motor"]);
55 Motorized.loadSounds(self, self.xmlFile, self.configurations["motor"]);
56
57 self.motorizedFillActivatable = MotorizedRefuelActivatable:new(self);
58
59 self.fuelFillTriggers = {};
60 self.isFuelFilling = false;
61 self.fuelFillLitersPerSecond = 10;
62 self.fuelFillLevel = 0;
63 self.lastFuelFillLevel = 0;
64 self:setFuelFillLevel(self.fuelCapacity);
65 self.sentFuelFillLevel = self.fuelFillLevel;
66 self.stopMotorOnLeave = true;
67
68 if self.isClient then
69 self.exhaustParticleSystems = {};
70 local exhaustParticleSystemCount = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.exhaustParticleSystems#count"), 0);
71 for i=1, exhaustParticleSystemCount do
72 local namei = string.format("vehicle.exhaustParticleSystems.exhaustParticleSystem%d", i);
73 local ps = {}
74 ParticleUtil.loadParticleSystem(self.xmlFile, ps, namei, self.components, false, nil, self.baseDirectory)
75 ps.minScale = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.exhaustParticleSystems#minScale"), 0.5);
76 ps.maxScale = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.exhaustParticleSystems#maxScale"), 1);
77 table.insert(self.exhaustParticleSystems, ps)
78 end
79 if #self.exhaustParticleSystems == 0 then
80 self.exhaustParticleSystems = nil
81 end
82
83 local exhaustFlapIndex = getXMLString(self.xmlFile, "vehicle.exhaustFlap#index");
84 if exhaustFlapIndex ~= nil then
85 self.exhaustFlap = {};
86 self.exhaustFlap.node = Utils.indexToObject(self.components, exhaustFlapIndex);
87 self.exhaustFlap.maxRot = Utils.degToRad(Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.exhaustFlap#maxRot"),0));
88 end
89
90 self.exhaustEffects = {};
91 Motorized.loadExhaustEffects(self, self.xmlFile, self.exhaustEffects);
92 if table.getn(self.exhaustEffects) == 0 then
93 self.exhaustEffects = nil;
94 end
95 end
96
97 self.motorStartDuration = 0;
98 if self.sampleMotorStart ~= nil then
99 self.motorStartDuration = self.sampleMotorStart.duration;
100 end
101 self.motorStartDuration = Utils.getNoNil( Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.motorStartDuration"), self.motorStartDuration), 0);
102 self.motorStartTime = 0;
103 self.lastRoundPerMinute = 0;
104 self.actualLoadPercentage = 0;
105 self.maxDecelerationDuringBrake = 0;
106 self.motorizedDirtyFlag = self:getNextDirtyFlag();
107
108 self.isMotorStarted = false;
109 self.motorStopTimerDuration = g_gameSettings:getValue("motorStopTimerDuration")
110 self.motorStopTimer = self.motorStopTimerDuration
111
112 self.fuelFillLevelHud = VehicleHudUtils.loadHud(self, self.xmlFile, "fuel");
113 self.rpmHud = VehicleHudUtils.loadHud(self, self.xmlFile, "rpm");
114 self.timeHud = VehicleHudUtils.loadHud(self, self.xmlFile, "time");
115 if self.timeHud ~= nil then
116 self.minuteChanged = Utils.appendedFunction(self.minuteChanged, Motorized.minuteChanged);
117 g_currentMission.environment:addMinuteChangeListener(self);
118 self:minuteChanged();
119 end
120 self.speedHud = VehicleHudUtils.loadHud(self, self.xmlFile, "speed");
121 self.fuelUsageHud = VehicleHudUtils.loadHud(self, self.xmlFile, "fuelUsage");
122
123 if savegame ~= nil then
124 local fuelFillLevel = getXMLFloat(savegame.xmlFile, savegame.key.."#fuelFillLevel");
125 if fuelFillLevel ~= nil then
126 if self.fuelCapacity ~= 0 then
127 local minFuelFillLevel = 0.1*self.fuelCapacity
128 local numToRefill = math.max(minFuelFillLevel - fuelFillLevel, 0);
129 if numToRefill > 0 then
130 fuelFillLevel = minFuelFillLevel;
131
132 local delta = numToRefill * g_currentMission.economyManager:getPricePerLiter(FillUtil.FILLTYPE_FUEL)
133 g_currentMission.missionStats:updateStats("expenses", delta);
134 g_currentMission:addSharedMoney(-delta, "purchaseFuel");
135 end
136 end
137 self:setFuelFillLevel(fuelFillLevel);
138 end
139 end
140
141 self.motorTurnedOnRotationNodes = Utils.loadRotationNodes(self.xmlFile, {}, "vehicle.turnedOnRotationNodes.turnedOnRotationNode", "motor", self.components);
142end

loadExhaustEffects

Description
Loading of exhaust effects from xml file
Definition
loadExhaustEffects(integer xmlFile, table exhaustEffects)
Arguments
integerxmlFileid of xml object
tableexhaustEffectstable to ass exhaustEffects
Code
148function Motorized:loadExhaustEffects(xmlFile, exhaustEffects)
149 local i = 0;
150 while true do
151 local key = string.format("vehicle.exhaustEffects.exhaustEffect(%d)", i);
152 if not hasXMLProperty(xmlFile, key) then
153 break;
154 end
155 local linkNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
156 local filename = getXMLString(xmlFile, key .. "#filename");
157 if filename ~= nil and linkNode ~= nil then
158 local i3dNode = Utils.loadSharedI3DFile(filename, self.baseDirectory, false, false, false);
159 if i3dNode ~= 0 then
160 local node = getChildAt(i3dNode, 0);
161 if getHasShaderParameter(node, "param") then
162 local effect = {};
163 effect.effectNode = node
164 effect.node = linkNode
165 effect.filename = filename;
166 link(effect.node, effect.effectNode);
167 setVisibility(effect.effectNode, false);
168 delete(i3dNode);
169
170 effect.minRpmColor = Utils.getVectorNFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#minRpmColor"), "0 0 0 1"), 4);
171 effect.maxRpmColor = Utils.getVectorNFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#maxRpmColor"), "0.0384 0.0359 0.0627 2.0"), 4);
172 effect.minRpmScale = Utils.getNoNil(getXMLFloat(xmlFile, key.."#minRpmScale"), 0.25);
173 effect.maxRpmScale = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxRpmScale"), 0.95);
174 effect.maxForwardSpeed = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxForwardSpeed"), math.ceil(self.motor:getMaximumForwardSpeed()*3.6));
175 effect.maxBackwardSpeed = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxBackwardSpeed"), math.ceil(self.motor:getMaximumBackwardSpeed()*3.6));
176
177 effect.xzRotationsOffset = Utils.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsOffset"), "0 0"), 2);
178 effect.xzRotationsForward = Utils.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsForward"), "0 0"), 2);
179 effect.xzRotationsBackward = Utils.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsBackward"), "0 0"), 2);
180 effect.xzRotationsLeft = Utils.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsLeft"), "0 0"), 2);
181 effect.xzRotationsRight = Utils.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsRight"), "0 0"), 2);
182
183 effect.xRot = 0;
184 effect.zRot = 0;
185
186 table.insert(exhaustEffects, effect);
187 end
188 end
189 end
190 i = i + 1;
191 end
192 self.exhaustEffectMaxSteeringSpeed = 0.001;
193end

loadDifferentials

Description
Load differentials from xml
Definition
loadDifferentials(integer xmlFile, integer configDifferentialIndex)
Arguments
integerxmlFileid of xml object
integerconfigDifferentialIndexindex of differential config
Code
199function Motorized:loadDifferentials(xmlFile, configDifferentialIndex)
200 local key,_ = Vehicle.getXMLConfigurationKey(xmlFile, configDifferentialIndex, "vehicle.differentialConfigurations.differentials", "vehicle.differentials", "differential");
201 self.differentials = {};
202 if self.isServer and self.motorizedNode ~= nil then
203 local i = 0;
204 while true do
205 local key = string.format(key..".differential(%d)", i);
206 if not hasXMLProperty(xmlFile, key) then
207 break;
208 end
209 local torqueRatio = Utils.getNoNil(getXMLFloat(xmlFile, key.."#torqueRatio"), 0.5);
210 local maxSpeedRatio = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxSpeedRatio"), 1.3);
211
212 local diffIndex1, diffIndex1IsWheel;
213 local diffIndex2, diffIndex2IsWheel;
214
215 local wheelIndex1 = getXMLInt(xmlFile, key.."#wheelIndex1");
216 if wheelIndex1 ~= nil then
217 local wheel = self.wheels[wheelIndex1+1];
218 if wheel ~= nil then
219 diffIndex1IsWheel = true;
220 diffIndex1 = wheelIndex1+1;
221 end
222 else
223 diffIndex1IsWheel = false;
224 diffIndex1 = getXMLInt(xmlFile, key.."#differentialIndex1");
225 end
226 local wheelIndex2 = getXMLInt(xmlFile, key.."#wheelIndex2");
227 if wheelIndex2 ~= nil then
228 local wheel = self.wheels[wheelIndex2+1];
229 if wheel ~= nil then
230 diffIndex2IsWheel = true;
231 diffIndex2 = wheelIndex2+1;
232 end
233 else
234 diffIndex2IsWheel = false;
235 diffIndex2 = getXMLInt(xmlFile, key.."#differentialIndex2");
236 end
237 if diffIndex1 ~= nil and diffIndex2 ~= nil then
238 table.insert(self.differentials, {torqueRatio=torqueRatio, maxSpeedRatio=maxSpeedRatio, diffIndex1=diffIndex1, diffIndex1IsWheel=diffIndex1IsWheel, diffIndex2=diffIndex2, diffIndex2IsWheel=diffIndex2IsWheel});
239 addDifferential(self.motorizedNode, diffIndex1IsWheel and self.wheels[diffIndex1].wheelShape or diffIndex1, diffIndex1IsWheel, diffIndex2IsWheel and self.wheels[diffIndex2].wheelShape or diffIndex2, diffIndex2IsWheel, torqueRatio, maxSpeedRatio);
240 else
241 print("Error: Invalid differential indices in '"..self.configFileName.."'");
242 end
243
244 i = i + 1;
245 end
246 end
247end

addToPhysics

Description
Add to physics
Definition
addToPhysics()
Return Values
booleansuccesssuccess
Code
252function Motorized:addToPhysics(superFunc)
253 if superFunc ~= nil then
254 if not superFunc(self) then
255 return false;
256 end
257 end
258
259 if self.isServer then
260 if self.motorizedNode ~= nil then
261 for _, differential in pairs(self.differentials) do
262 local diffIndex1IsWheel, diffIndex1, diffIndex2IsWheel, diffIndex2 = differential.diffIndex1IsWheel, differential.diffIndex1, differential.diffIndex2IsWheel, differential.diffIndex2;
263 if diffIndex1IsWheel then
264 diffIndex1 = self.wheels[diffIndex1].wheelShape;
265 end
266 if diffIndex2IsWheel then
267 diffIndex2 = self.wheels[diffIndex2].wheelShape;
268 end
269 addDifferential(self.motorizedNode, diffIndex1, diffIndex1IsWheel, diffIndex2, diffIndex2IsWheel, differential.torqueRatio, differential.maxSpeedRatio);
270 end
271 end
272 end
273
274 return true
275end

removeFromPhysics

Description
Remove from physics
Definition
removeFromPhysics()
Return Values
booleansuccesssuccess
Code
280function Motorized:removeFromPhysics(superFunc)
281 if superFunc ~= nil then
282 if not superFunc(self) then
283 print("false")
284 return false;
285 end
286 end
287 for _, trigger in pairs(self.fuelFillTriggers) do
288 self:removeFuelFillTrigger(trigger)
289 trigger:onVehicleDeleted(self)
290 end
291 g_currentMission:removeActivatableObject(self.motorizedFillActivatable);
292
293 return true
294end

loadMotor

Description
Load motor from xml file
Definition
loadMotor(integer xmlFile, integer motorId)
Arguments
integerxmlFileid of xml object
integermotorIdindex of motor configuration
Code
300function Motorized:loadMotor(xmlFile, motorId)
301 local key, motorId = Vehicle.getXMLConfigurationKey(xmlFile, motorId, "vehicle.motorConfigurations.motorConfiguration", "vehicle", "motor");
302
303 local fallbackConfigKey = "vehicle.motorConfigurations.motorConfiguration(0)";
304 local fallbackOldKey = "vehicle";
305
306 self.motorType = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#type", getXMLString, "vehicle", fallbackConfigKey, fallbackOldKey);
307
308 self.fuelCapacity = Vehicle.getConfigurationValue(xmlFile, key, ".fuelCapacity", "", getXMLFloat, 500, fallbackConfigKey, fallbackOldKey);
309
310 local wheelKey, _ = Vehicle.getXMLConfigurationKey(xmlFile, self.configurations["wheel"], "vehicle.wheelConfigurations.wheelConfiguration", "vehicle", "wheels");
311 self.fuelCapacity = Utils.getNoNil(Vehicle.getConfigurationValue(xmlFile, wheelKey, ".fuelCapacity", "", getXMLInt, nil, nil, ""), self.fuelCapacity);
312
313 local fuelUsage = Vehicle.getConfigurationValue(xmlFile, key, ".fuelUsage", "", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey);
314 if fuelUsage == nil then
315 fuelUsage = self.fuelCapacity / 5; -- default fuel usage: full->empty: 5h
316 end
317 self.fuelUsage = fuelUsage / (60*60*1000); -- from l/h to l/ms
318
319 ObjectChangeUtil.updateObjectChanges(xmlFile, "vehicle.motorConfigurations.motorConfiguration", motorId, self.components, self);
320
321 local motorMinRpm = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#minRpm", getXMLFloat, 1000, fallbackConfigKey, fallbackOldKey);
322 local motorMaxRpm = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#maxRpm", getXMLFloat, 1800, fallbackConfigKey, fallbackOldKey);
323 local minSpeed = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#minSpeed", getXMLFloat, 1, fallbackConfigKey, fallbackOldKey);
324 local maxForwardSpeed = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#maxForwardSpeed", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey);
325 local maxBackwardSpeed = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#maxBackwardSpeed", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey);
326 if maxForwardSpeed ~= nil then
327 maxForwardSpeed = maxForwardSpeed/3.6;
328 end
329 if maxBackwardSpeed ~= nil then
330 maxBackwardSpeed = maxBackwardSpeed/3.6;
331 end
332
333 local maxWheelSpeed = Vehicle.getConfigurationValue(xmlFile, wheelKey, ".wheels", "#maxForwardSpeed", getXMLFloat, nil, nil, "vehicle.wheels");
334 if maxWheelSpeed ~= nil then
335 maxForwardSpeed = maxWheelSpeed/3.6;
336 end
337
338 local brakeForce = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#brakeForce", getXMLFloat, 10, fallbackConfigKey, fallbackOldKey)*2;
339 local lowBrakeForceScale = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#lowBrakeForceScale", getXMLFloat, 0.5, fallbackConfigKey, fallbackOldKey);
340 local lowBrakeForceSpeedLimit = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#lowBrakeForceSpeedLimit", getXMLFloat, 20, fallbackConfigKey, fallbackOldKey)/3600;
341 local forwardGearRatio = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#forwardGearRatio", getXMLFloat, 2, fallbackConfigKey, fallbackOldKey);
342 local backwardGearRatio = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#backwardGearRatio", getXMLFloat, 1.5, fallbackConfigKey, fallbackOldKey);
343 local maxForwardGearRatio = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#maxForwardGearRatio", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey);
344 local minForwardGearRatio = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#minForwardGearRatio", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey);
345 local maxBackwardGearRatio = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#maxBackwardGearRatio", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey);
346 local minBackwardGearRatio = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#minBackwardGearRatio", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey);
347 local rpmFadeOutRange = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#rpmFadeOutRange", getXMLFloat, 20, fallbackConfigKey, fallbackOldKey);
348 local torqueScale = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#torqueScale", getXMLFloat, 1, fallbackConfigKey, fallbackOldKey);
349 local ptoMotorRpmRatio = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#ptoMotorRpmRatio", getXMLFloat, 4, fallbackConfigKey, fallbackOldKey);
350
351 --local maxTorque = 0;
352 local maxMotorPower = 0;
353 local torqueCurve = AnimCurve:new(linearInterpolator1);
354 local torqueI = 0;
355 local torqueBase = fallbackOldKey..".motor.torque"; -- fallback to old motor setup
356 if key ~= nil and hasXMLProperty(xmlFile, fallbackConfigKey..".motor.torque(0)") then -- using default motor configuration
357 torqueBase = fallbackConfigKey..".motor.torque";
358 end
359 if key ~= nil and hasXMLProperty(xmlFile, key..".motor.torque(0)") then -- using selected motor configuration
360 torqueBase = key..".motor.torque";
361 end
362
363 while true do
364 local torqueKey = string.format(torqueBase.."(%d)", torqueI);
365 local normRpm = getXMLFloat(xmlFile, torqueKey.."#normRpm");
366 local rpm;
367 if normRpm == nil then
368 rpm = getXMLFloat(xmlFile, torqueKey.."#rpm");
369 else
370 rpm = normRpm * motorMaxRpm;
371 end
372 local torque = getXMLFloat(xmlFile, torqueKey.."#torque");
373 if torque == nil or rpm == nil then
374 break;
375 end
376 torqueCurve:addKeyframe({v=torque*torqueScale, time = rpm});
377 torqueI = torqueI +1;
378
379 local motorPower = 1000 * ( rpm*math.pi/30*(torque*torqueScale) );
380 if motorPower > maxMotorPower then
381 maxMotorPower = motorPower;
382 end
383 end
384
385 if self.motorType == "locomotive" then
386 self.motor = LocomotiveMotor:new(self, motorMinRpm, motorMaxRpm, maxForwardSpeed, maxBackwardSpeed, torqueCurve, brakeForce, forwardGearRatio, backwardGearRatio, minForwardGearRatio, maxForwardGearRatio, minBackwardGearRatio, maxBackwardGearRatio, ptoMotorRpmRatio, rpmFadeOutRange, 0, maxMotorPower);
387 else
388 self.motor = VehicleMotor:new(self, motorMinRpm, motorMaxRpm, maxForwardSpeed, maxBackwardSpeed, torqueCurve, brakeForce, forwardGearRatio, backwardGearRatio, minForwardGearRatio, maxForwardGearRatio, minBackwardGearRatio, maxBackwardGearRatio, ptoMotorRpmRatio, rpmFadeOutRange, 0, maxMotorPower, minSpeed);
389 end
390
391 local rotInertia = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#rotInertia", getXMLFloat, self.motor:getRotInertia(), fallbackConfigKey, fallbackOldKey);
392 local dampingRate = Vehicle.getConfigurationValue(xmlFile, key, ".motor", "#dampingRate", getXMLFloat, self.motor:getDampingRate(), fallbackConfigKey, fallbackOldKey);
393 self.motor:setRotInertia(rotInertia);
394 self.motor:setDampingRate(dampingRate);
395 self.motor:setLowBrakeForce(lowBrakeForceScale, lowBrakeForceSpeedLimit);
396end

loadSounds

Description
Load sounds from xml file
Definition
loadSounds(integer xmlFile)
Arguments
integerxmlFileid of xml object
Code
401function Motorized:loadSounds(xmlFile, motorId)
402 if self.isClient then
403 self.sampleRefuel = SoundUtil.loadSample(xmlFile, {}, "vehicle.refuelSound", "$data/maps/sounds/refuel.wav", self.baseDirectory, self.components[1].node);
404 self.sampleMotorStart = SoundUtil.loadSample(xmlFile, {}, "vehicle.motorStartSound", nil, self.baseDirectory);
405 self.sampleMotorStop = SoundUtil.loadSample(xmlFile, {}, "vehicle.motorStopSound", nil, self.baseDirectory);
406 self.sampleMotor = SoundUtil.loadSample(xmlFile, {}, "vehicle.motorSound", nil, self.baseDirectory, self.components[1].node);
407 self.sampleMotorRun = SoundUtil.loadSample(xmlFile, {}, "vehicle.motorSoundRun", nil, self.baseDirectory, self.components[1].node);
408 self.sampleMotorLoad = SoundUtil.loadSample(xmlFile, {}, "vehicle.motorSoundLoad", nil, self.baseDirectory, self.components[1].node);
409 self.sampleGearbox = SoundUtil.loadSample(xmlFile, {}, "vehicle.gearboxSound", nil, self.baseDirectory, self.components[1].node);
410 self.sampleRetarder = SoundUtil.loadSample(xmlFile, {}, "vehicle.retarderSound", nil, self.baseDirectory, self.components[1].node);
411
412 self.sampleBrakeCompressorStart = SoundUtil.loadSample(xmlFile, {}, "vehicle.brakeCompressorStartSound", nil, self.baseDirectory);
413 self.sampleBrakeCompressorRun = SoundUtil.loadSample(xmlFile, {}, "vehicle.brakeCompressorRunSound", nil, self.baseDirectory);
414 self.sampleBrakeCompressorStop = SoundUtil.loadSample(xmlFile, {}, "vehicle.brakeCompressorStopSound", nil, self.baseDirectory);
415
416 self.sampleReverseDrive = SoundUtil.loadSample(xmlFile, {}, "vehicle.reverseDriveSound", nil, self.baseDirectory, self.components[1].node);
417
418 self.sampleCompressedAir = SoundUtil.loadSample(xmlFile, {}, "vehicle.compressedAirSound", nil, self.baseDirectory);
419 self.sampleAirReleaseValve = SoundUtil.loadSample(xmlFile, {}, "vehicle.airReleaseValveSound", nil, self.baseDirectory);
420
421 local maxRpmDelta = (self.motor:getMaxRpm() - self.motor:getMinRpm());
422 local maxRpsDelta = maxRpmDelta / 60;
423
424 if self.sampleMotor.sample ~= nil then
425 self.motorSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSound#pitchMax"), 2.0);
426 self.motorSoundPitchScale = getXMLFloat(xmlFile, "vehicle.motorSound#pitchScale");
427 if self.motorSoundPitchScale == nil then
428 self.motorSoundPitchScale = (self.motorSoundPitchMax - self.sampleMotor.pitchOffset) / maxRpsDelta;
429 end
430 self.motorSoundVolumeMin = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSound#volumeMin"), self.sampleMotor.volume);
431 self.motorSoundVolumeMinSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSound#volumeMinSpeed"), math.huge);
432 end
433
434 if self.sampleMotorRun.sample ~= nil then
435 self.motorSoundRunPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#pitchMax"), 2.0);
436 self.motorSoundRunPitchScale = getXMLFloat(xmlFile, "vehicle.motorSoundRun#pitchScale");
437 if self.motorSoundRunPitchScale == nil then
438 self.motorSoundRunPitchScale = (self.motorSoundRunPitchMax - self.sampleMotorRun.pitchOffset) / maxRpsDelta;
439 end
440 self.motorSoundRunMinimalVolumeFactor = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundRun#minimalVolumeFactor"), 0.0);
441 end
442
443 if self.sampleMotorLoad.sample ~= nil then
444 self.motorSoundLoadPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundLoad#pitchMax"), 2.0);
445 self.motorSoundLoadPitchScale = getXMLFloat(xmlFile, "vehicle.motorSoundLoad#pitchScale");
446 if self.motorSoundLoadPitchScale == nil then
447 self.motorSoundLoadPitchScale = (self.motorSoundLoadPitchMax - self.sampleMotorLoad.pitchOffset) / maxRpsDelta;
448 end
449 self.motorSoundLoadMinimalVolumeFactor = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorSoundLoad#minimalVolumeFactor"), 0.0);
450 self.motorSoundLoadFactor = 0;
451 end
452
453 if self.sampleGearbox.sample ~= nil then
454 self.gearboxSoundVolumeMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.gearboxSound#volumeMax"), 2.0);
455 self.gearboxSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.gearboxSound#pitchMax"), 2.0);
456 self.gearboxSoundReverseVolumeMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.gearboxSound#reverseVolumeMax"), self.gearboxSoundVolumeMax);
457 self.gearboxSoundReversePitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.gearboxSound#reversePitchMax"), self.gearboxSoundPitchMax);
458 self.gearboxSoundPitchExponent = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.gearboxSound#pitchExponent"), 1.0);
459 end
460
461 if self.sampleRetarder.sample ~= nil then
462 self.retarderSoundVolumeMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.retarderSound#volumeMax"), 2.0);
463 self.retarderSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.retarderSound#pitchMax"), 2.0);
464 self.retarderSoundMinSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.retarderSound#minSpeed"), 5.0);
465 self.retarderSoundActualVolume = 0.0;
466 end
467
468 self.pitchInfluenceFromWheels = 0;
469 self.volumeInfluenceFromWheels = 0;
470 self.wheelInfluenceOnGearboxSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.gearboxSound#wheelInfluenceOnVolume"), 0.1);
471 self.wheelInfluenceOnGearboxSoundPitch = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.gearboxSound#wheelInfluenceOnPitch"), 0.2);
472 self.wheelInfluenceOnRetarderSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.retarderSound#wheelInfluenceOnVolume"), 0.1);
473 self.wheelInfluenceOnRetarderSoundPitch = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.retarderSound#wheelInfluenceOnPitch"), 0.2);
474
475 if self.sampleBrakeCompressorRun.sample ~= nil then
476 self.brakeCompressorRunSoundPitchMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.brakeCompressorRunSound#pitchMax"), 2.0);
477 self.brakeCompressorRunSoundPitchScale = getXMLFloat(xmlFile, "vehicle.brakeCompressorRunSound#pitchScale");
478 if self.brakeCompressorRunSoundPitchScale == nil then
479 self.brakeCompressorRunSoundPitchScale = (self.brakeCompressorRunSoundPitchMax - self.sampleBrakeCompressorRun.pitchOffset) / maxRpsDelta;
480 end
481 end
482
483 self.brakeCompressor = {};
484 self.brakeCompressor.capacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.brakeCompressor#capacity"), 6);
485 self.brakeCompressor.refillFilllevel = math.min(self.brakeCompressor.capacity, Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.brakeCompressor#refillFillLevel"), self.brakeCompressor.capacity/2));
486 self.brakeCompressor.fillSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.brakeCompressor#fillSpeed"), 0.6) / 1000;
487 self.brakeCompressor.fillLevel = 0;
488 self.brakeCompressor.doFill = true;
489
490 self.soundsAdjustedToIndoorCamera = false;
491
492 self.compressedAirSoundEnabled = false;
493 self.compressionSoundTime = 0;
494 end
495end

delete

Description
Called on deleting
Definition
delete()
Code
499function Motorized:delete()
500
501 if self.timeHud ~= nil then
502 g_currentMission.environment:removeMinuteChangeListener(self);
503 end
504
505 for _, trigger in pairs(self.fuelFillTriggers) do
506 trigger:onVehicleDeleted(self);
507 end
508
509 g_currentMission:removeActivatableObject(self.motorizedFillActivatable);
510
511 if self.isClient then
512 if self.exhaustEffects ~= nil then
513 for _, effect in pairs(self.exhaustEffects) do
514 Utils.releaseSharedI3DFile(effect.filename, self.baseDirectory, true);
515 end
516 end
517 ParticleUtil.deleteParticleSystems(self.exhaustParticleSystems)
518
519 SoundUtil.deleteSample(self.sampleRefuel);
520 SoundUtil.deleteSample(self.sampleCompressedAir);
521 SoundUtil.deleteSample(self.sampleAirReleaseValve);
522 SoundUtil.deleteSample(self.sampleMotor);
523 SoundUtil.deleteSample(self.sampleMotorRun);
524 SoundUtil.deleteSample(self.sampleMotorLoad);
525 SoundUtil.deleteSample(self.sampleGearbox);
526 SoundUtil.deleteSample(self.sampleRetarder);
527 SoundUtil.deleteSample(self.sampleMotorStart);
528 SoundUtil.deleteSample(self.sampleMotorStop);
529 SoundUtil.deleteSample(self.sampleReverseDrive);
530 SoundUtil.deleteSample(self.sampleBrakeCompressorStart);
531 SoundUtil.deleteSample(self.sampleBrakeCompressorRun);
532 SoundUtil.deleteSample(self.sampleBrakeCompressorStop);
533 end
534end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
540function Motorized:readStream(streamId, connection)
541 local isMotorStarted = streamReadBool(streamId);
542 if isMotorStarted then
543 self:startMotor(true);
544 else
545 self:stopMotor(true);
546 end
547 local isFuelFilling = streamReadBool(streamId);
548 self:setIsFuelFilling(isFuelFilling, true);
549
550 local newFuelFillLevel=streamReadFloat32(streamId);
551 self:setFuelFillLevel(newFuelFillLevel);
552end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
558function Motorized:writeStream(streamId, connection)
559 streamWriteBool(streamId, self.isMotorStarted);
560 streamWriteBool(streamId, self.isFuelFilling);
561 streamWriteFloat32(streamId, self.fuelFillLevel);
562end

readUpdateStream

Description
Called on on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
569function Motorized:readUpdateStream(streamId, timestamp, connection)
570 if connection.isServer then
571 local rpm = streamReadUIntN(streamId, 11);
572 rpm = rpm / 2047;
573 local rpmRange = self.motor:getMaxRpm()- self.motor:getMinRpm();
574 self.motor:setEqualizedMotorRpm( (rpm * rpmRange) + self.motor:getMinRpm() );
575
576 local loadPercentage = streamReadUIntN(streamId, 7);
577 self.actualLoadPercentage = loadPercentage / 127;
578
579 if streamReadBool(streamId) then
580 local fuelFillLevel = streamReadUIntN(streamId, 15)/32767*self.fuelCapacity;
581 self:setFuelFillLevel(fuelFillLevel);
582 end
583 end
584end

writeUpdateStream

Description
Called on on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
591function Motorized:writeUpdateStream(streamId, connection, dirtyMask)
592 if not connection.isServer then
593 local rpmRange = self.motor:getMaxRpm() - self.motor:getMinRpm();
594 local rpm = (self.motor:getEqualizedMotorRpm() - self.motor:getMinRpm()) / rpmRange;
595
596 rpm = math.floor(rpm * 2047);
597 streamWriteUIntN(streamId, rpm, 11);
598
599 streamWriteUIntN(streamId, 127 * self.actualLoadPercentage, 7);
600
601 if streamWriteBool(streamId, bitAND(dirtyMask, self.motorizedDirtyFlag) ~= 0) then
602 local percent = 0;
603 if self.fuelCapacity ~= 0 then
604 percent = Utils.clamp(self.fuelFillLevel / self.fuelCapacity, 0, 1);
605 end
606 streamWriteUIntN(streamId, math.floor(percent*32767), 15);
607 end
608 end
609end

getSaveAttributesAndNodes

Description
Returns attributes and nodes to save
Definition
getSaveAttributesAndNodes(table nodeIdent)
Arguments
tablenodeIdentnode ident
Return Values
stringattributesattributes
stringnodesnodes
Code
616function Motorized:getSaveAttributesAndNodes(nodeIdent)
617 local attributes = 'fuelFillLevel="'..self.fuelFillLevel..'"';
618 return attributes, nil;
619end

update

Description
Called on update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
630function Motorized:update(dt)
631
632 if self.isClient then
633 if self.isEntered and self:getIsActiveForInput(false) and not g_currentMission.missionInfo.automaticMotorStartEnabled then
634 if InputBinding.hasEvent(InputBinding.TOGGLE_MOTOR_STATE) then
635 if not self:getIsHired() then
636 if self.isMotorStarted then
637 self:stopMotor()
638 else
639 self:startMotor()
640 end
641 end
642 end
643 end
644 end
645
646 Utils.updateRotationNodes(self, self.motorTurnedOnRotationNodes, dt, self:getIsMotorStarted());
647
648 if self:getIsMotorStarted() then
649 local accInput = 0;
650 if self.axisForward ~= nil then
651 accInput = -self.axisForward;
652 end
653 if self.cruiseControl ~= nil and self.cruiseControl.state ~= Drivable.CRUISECONTROL_STATE_OFF then
654 accInput = 1;
655 end
656 if self.isClient then
657 if self:getIsActiveForSound() then
658 if not SoundUtil.isSamplePlaying(self.sampleMotorStart, 1.5*dt) then
659 SoundUtil.playSample(self.sampleMotor, 0, 0, nil);
660 SoundUtil.playSample(self.sampleMotorRun, 0, 0, 0);
661 SoundUtil.playSample(self.sampleMotorLoad, 0, 0, 0);
662 SoundUtil.playSample(self.sampleGearbox, 0, 0, 0);
663 SoundUtil.playSample(self.sampleRetarder, 0, 0, 0);
664
665 if self.brakeLightsVisibility then
666 self.brakeLightsVisibilityWasActive = true;
667 self.maxDecelerationDuringBrake = math.max(self.maxDecelerationDuringBrake, math.abs(accInput));
668 end
669 if self.brakeLightsVisibilityWasActive and not self.brakeLightsVisibility then
670 self.brakeLightsVisibilityWasActive = false;
671
672 local factor = self.maxDecelerationDuringBrake;
673 self.maxDecelerationDuringBrake = 0;
674
675 local airConsumption = self:getMaximalAirConsumptionPerFullStop();
676 -- print( string.format(" -----> factor = %.2f // %.2f ", factor, airConsumption) );
677 airConsumption = factor * airConsumption;
678 self.brakeCompressor.fillLevel = math.max(0, self.brakeCompressor.fillLevel - airConsumption); --implementCount * self.brakeCompressor.capacity * 0.05);
679 end
680
681 if self.brakeCompressor.fillLevel < self.brakeCompressor.refillFilllevel then
682 self.brakeCompressor.doFill = true;
683 end
684 if self.brakeCompressor.doFill and self.brakeCompressor.fillLevel == self.brakeCompressor.capacity then
685 self.brakeCompressor.doFill = false;
686 end
687 if self.brakeCompressor.doFill then
688 self.brakeCompressor.fillLevel = math.min(self.brakeCompressor.capacity, self.brakeCompressor.fillLevel + self.brakeCompressor.fillSpeed * dt);
689 end
690
691 if Vehicle.debugRendering then
692 renderText(0.3, 0.16, getCorrectTextSize(0.02), string.format("brakeCompressor.fillLevel = %.1f", 100*(self.brakeCompressor.fillLevel / self.brakeCompressor.capacity) ));
693 end
694
695 if not self.brakeCompressor.doFill then
696 if self.brakeCompressor.runSoundActive then
697 SoundUtil.stopSample(self.sampleBrakeCompressorRun, true);
698 SoundUtil.playSample(self.sampleBrakeCompressorStop, 1, 0, nil);
699 self.brakeCompressor.startSoundPlayed = false;
700 self.brakeCompressor.runSoundActive = false;
701 end
702 elseif not SoundUtil.isSamplePlaying(self.sampleBrakeCompressorStop, 1.5*dt) then
703 if not self.brakeCompressor.startSoundPlayed then
704 self.brakeCompressor.startSoundPlayed = true;
705 SoundUtil.playSample(self.sampleBrakeCompressorStart, 1, 0, nil);
706 else
707 if not SoundUtil.isSamplePlaying(self.sampleBrakeCompressorStart, 1.5*dt) and not self.brakeCompressor.runSoundActive then
708 self.brakeCompressor.runSoundActive = true;
709 SoundUtil.playSample(self.sampleBrakeCompressorRun, 0, 0, nil);
710 end
711 end
712 end
713 end
714
715 if self.compressionSoundTime <= g_currentMission.time then
716 SoundUtil.playSample(self.sampleAirReleaseValve, 1, 0, nil);
717 self.compressionSoundTime = g_currentMission.time + math.random(10000, 40000);
718 end
719
720 if self.sampleCompressedAir.sample ~= nil then
721 if self.movingDirection > 0 and self.lastSpeed > self.motor:getMaximumForwardSpeed()*0.0002 then -- faster than 20% of max speed
722 if accInput < -0.05 then
723 -- play the compressor sound if we drive fast enough and brake
724 if not self.compressedAirSoundEnabled then
725 SoundUtil.playSample(self.sampleCompressedAir, 1, 0, nil);
726 self.compressedAirSoundEnabled = true;
727 end
728 else
729 self.compressedAirSoundEnabled = false;
730 end
731 end
732 end
733
734 SoundUtil.stop3DSample(self.sampleMotor);
735 SoundUtil.stop3DSample(self.sampleMotorRun);
736 SoundUtil.stop3DSample(self.sampleGearbox);
737 SoundUtil.stop3DSample(self.sampleRetarder);
738 else
739 SoundUtil.play3DSample(self.sampleMotor);
740 SoundUtil.play3DSample(self.sampleMotorRun);
741 end
742
743 -- adjust pitch and volume of samples
744 if (self.wheels ~= nil and table.getn(self.wheels) > 0) or (self.dummyWheels ~= nil and table.getn(self.dummyWheels) > 0) then
745
746 if self.sampleReverseDrive.sample ~= nil then
747 if (accInput < 0 or accInput == 0) and (self:getLastSpeed() > 3 and self.movingDirection ~= self.reverserDirection) then
748 if self:getIsActiveForSound() then
749 SoundUtil.playSample(self.sampleReverseDrive, 0, 0, nil);
750 SoundUtil.stop3DSample(self.sampleReverseDrive);
751 else
752 SoundUtil.play3DSample(self.sampleReverseDrive);
753 SoundUtil.stopSample(self.sampleReverseDrive);
754 end
755 else
756 SoundUtil.stopSample(self.sampleReverseDrive);
757 SoundUtil.stop3DSample(self.sampleReverseDrive);
758 end
759 end
760
761 local minRpm = self.motor:getMinRpm();
762 local maxRpm = self.motor:getMaxRpm();
763
764 local maxSpeed;
765 if self.movingDirection >= 0 then
766 maxSpeed = self.motor:getMaximumForwardSpeed()*0.001;
767 else
768 maxSpeed = self.motor:getMaximumBackwardSpeed()*0.001;
769 end
770
771 local motorRpm = self.motor:getEqualizedMotorRpm();
772 -- Increase the motor rpm to the max rpm if faster than 75% of the full speed
773 if self.movingDirection > 0 and self.lastSpeed > 0.75*maxSpeed and motorRpm < maxRpm then
774 motorRpm = motorRpm + (maxRpm - motorRpm) * math.min((self.lastSpeed-0.75*maxSpeed) / (0.25*maxSpeed), 1);
775 end
776 -- The actual rpm offset is 50% from the motor and 50% from the speed
777 local targetRpmOffset = (motorRpm - minRpm)*0.5 + math.min(self.lastSpeed/maxSpeed, 1)*(maxRpm-minRpm)*0.5;
778
779 if Vehicle.debugRendering then
780 renderText(0.3, 0.14, getCorrectTextSize(0.02), string.format("getLastMotorRpm() = %.2f", self.motor:getLastMotorRpm() ));
781 renderText(0.3, 0.12, getCorrectTextSize(0.02), string.format("getEqualziedMotorRpm() = %.2f", self.motor:getEqualizedMotorRpm() ));
782 renderText(0.3, 0.10, getCorrectTextSize(0.02), string.format("targetRpmOffset = %.2f", targetRpmOffset ));
783 end
784
785
786 local alpha = math.pow(0.01, dt*0.001);
787 local roundPerMinute = targetRpmOffset + alpha*(self.lastRoundPerMinute-targetRpmOffset);
788
789 self.lastRoundPerMinute = roundPerMinute;
790
791 local roundPerSecondSmoothed = roundPerMinute / 60;
792
793 if self.sampleMotor.sample ~= nil then
794 local motorSoundPitch = math.min(self.sampleMotor.pitchOffset + self.motorSoundPitchScale*math.abs(roundPerSecondSmoothed), self.motorSoundPitchMax);
795 SoundUtil.setSamplePitch(self.sampleMotor, motorSoundPitch);
796
797 local deltaVolume = (self.sampleMotor.volume - self.motorSoundVolumeMin) * math.max(0.0, math.min(1.0, self:getLastSpeed()/self.motorSoundVolumeMinSpeed))
798 SoundUtil.setSampleVolume(self.sampleMotor, math.max(self.motorSoundVolumeMin, self.sampleMotor.volume - deltaVolume));
799 end;
800
801 if self.sampleMotorRun.sample ~= nil then
802 local motorSoundRunPitch = math.min(self.sampleMotorRun.pitchOffset + self.motorSoundRunPitchScale*math.abs(roundPerSecondSmoothed), self.motorSoundRunPitchMax);
803 SoundUtil.setSamplePitch(self.sampleMotorRun, motorSoundRunPitch);
804
805 local runVolume = roundPerMinute/(maxRpm - minRpm);
806 if math.abs(accInput) < 0.01 or Utils.sign(accInput) ~= self.movingDirection or ptoVolume == 0 then
807 runVolume = runVolume * 0.9;
808 end;
809 runVolume = Utils.clamp(runVolume, 0.0, 1.0);
810
811 if Vehicle.debugRendering then
812 renderText(0.3, 0.08, getCorrectTextSize(0.02), string.format("runVolume = %.2f", runVolume) );
813 end
814
815 if self.sampleMotorLoad.sample == nil then
816 SoundUtil.setSampleVolume(self.sampleMotorRun, runVolume * self.sampleMotorRun.volume);
817 else
818 local motorSoundLoadPitch = math.min(self.sampleMotorLoad.pitchOffset + self.motorSoundLoadPitchScale*math.abs(roundPerSecondSmoothed), self.motorSoundLoadPitchMax);
819 SoundUtil.setSamplePitch(self.sampleMotorLoad, motorSoundLoadPitch);
820
821 if self.motorSoundLoadFactor < self.actualLoadPercentage then
822 self.motorSoundLoadFactor = math.min(self.actualLoadPercentage, self.motorSoundLoadFactor + dt/500);
823 elseif self.motorSoundLoadFactor > self.actualLoadPercentage then
824 self.motorSoundLoadFactor = math.max(self.actualLoadPercentage, self.motorSoundLoadFactor - dt/750);
825 end
826 if Vehicle.debugRendering then
827 renderText(0.3, 0.06, getCorrectTextSize(0.02), string.format("motorSoundLoadFactor = %.2f", self.motorSoundLoadFactor) );
828 end
829
830 SoundUtil.setSampleVolume(self.sampleMotorRun, math.max(self.motorSoundRunMinimalVolumeFactor, (1.0 - self.motorSoundLoadFactor) * runVolume * self.sampleMotorRun.volume) );
831 SoundUtil.setSampleVolume(self.sampleMotorLoad, math.max(self.motorSoundLoadMinimalVolumeFactor, self.motorSoundLoadFactor * runVolume * self.sampleMotorLoad.volume) );
832 end
833 end
834
835 if self.sampleGearbox.sample ~= nil then
836 local speedFactor = Utils.clamp( (self:getLastSpeed() - 1) / math.ceil(self.motor:getMaximumForwardSpeed()*3.6), 0, 1);
837 local pitchGearbox = Utils.lerp(self.sampleGearbox.pitchOffset, self.gearboxSoundPitchMax, speedFactor^self.gearboxSoundPitchExponent);
838 local volumeGearbox = Utils.lerp(self.sampleGearbox.volume, self.gearboxSoundVolumeMax, speedFactor);
839
840 if self.reverserDirection ~= self.movingDirection then
841 speedFactor = Utils.clamp( (self:getLastSpeed() - 1) / math.ceil(self.motor:getMaximumBackwardSpeed()*3.6), 0, 1);
842 pitchGearbox = Utils.lerp(self.sampleGearbox.pitchOffset, self.gearboxSoundReversePitchMax, speedFactor^self.gearboxSoundPitchExponent);
843 volumeGearbox = Utils.lerp(self.sampleGearbox.volume, self.gearboxSoundReverseVolumeMax, speedFactor);
844 end
845
846 SoundUtil.setSamplePitch(self.sampleGearbox, pitchGearbox);
847 SoundUtil.setSampleVolume(self.sampleGearbox, volumeGearbox);
848 end
849
850 if self.sampleRetarder.sample ~= nil then
851 local speedFactor = Utils.clamp( (self:getLastSpeed() - self.retarderSoundMinSpeed) / math.ceil(self.motor:getMaximumForwardSpeed()*3.6), 0, 1);
852 local pitchGearbox = Utils.lerp(self.sampleRetarder.pitchOffset, self.retarderSoundPitchMax, speedFactor);
853 SoundUtil.setSamplePitch(self.sampleRetarder, pitchGearbox);
854
855 local volumeRetarder = Utils.lerp(self.sampleRetarder.volume, self.retarderSoundVolumeMax, speedFactor);
856 local targetVolume = 0.0;
857 if accInput <= 0.0 and self:getLastSpeed() > self.retarderSoundMinSpeed and self.reverserDirection == self.movingDirection then
858 if accInput > -0.9 then
859 targetVolume = volumeRetarder;
860 else
861 targetVolume = self.sampleRetarder.volume;
862 end
863 end
864
865 if self.retarderSoundActualVolume < targetVolume then
866 self.retarderSoundActualVolume = math.min(targetVolume, self.retarderSoundActualVolume + dt/self.axisSmoothTime);
867 elseif self.retarderSoundActualVolume > targetVolume then
868 self.retarderSoundActualVolume = math.max(targetVolume, self.retarderSoundActualVolume - dt/self.axisSmoothTime);
869 end
870 SoundUtil.setSampleVolume(self.sampleRetarder, self.retarderSoundActualVolume);
871
872 if Vehicle.debugRendering then
873 renderText(0.8, 0.44, getCorrectTextSize(0.02), string.format("retarderSoundActualVolume = %.2f", self.retarderSoundActualVolume ));
874 renderText(0.8, 0.42, getCorrectTextSize(0.02), string.format("getLastSpeed() = %.2f", self:getLastSpeed() ));
875 end
876 end
877
878 if self.sampleBrakeCompressorRun.sample ~= nil then
879 local pitchCompressor = math.min(self.sampleBrakeCompressorRun.pitchOffset + self.brakeCompressorRunSoundPitchScale*math.abs(roundPerSecondSmoothed), self.brakeCompressorRunSoundPitchMax);
880 SoundUtil.setSamplePitch(self.sampleBrakeCompressorRun, pitchCompressor);
881 end
882
883 end
884 end
885
886 if self.isServer then
887 if not self:getIsHired() then
888 if self.lastMovedDistance > 0 then
889 g_currentMission.missionStats:updateStats("traveledDistance", self.lastMovedDistance*0.001);
890 end
891 end
892
893 self:updateFuelUsage(dt)
894 end
895 end
896end

updateTick

Description
Called on update tick
Definition
updateTick(float dt)
Arguments
floatdttime since last call in ms
Code
901function Motorized:updateTick(dt)
902 if self.isServer then
903 -- compare power
904 --local torque,_ = self.motor:getTorque(1, false)*1000;
905 --local motorPower = self.motor:getNonClampedMotorRpm()*math.pi/30*torque -- [kW]
906 --
907 --self.actualLoadPercentage = motorPower / self.motor.maxMotorPower;
908
909 -- compare torque I
910 self.actualLoadPercentage = self.motor:getMotorLoad() / self.motor.maxMotorTorque;
911
912 -- compare torque II
913 --local torque,_ = self.motor:getTorque(1, false)*1000;
914 --self.actualLoadPercentage = (self.motor:getMotorLoad() * 1000 / torque);
915
916 if self:getIsActive() then
917 --print(" --------------------- ");
918 --print( string.format(" %.2f <= %.2f / %.2f", self.actualLoadPercentage, motorPower, self.motor.maxMotorPower) );
919 --print( string.format(" %.2f <= %.2f / %.2f", self.actualLoadPercentage, self.motor:getMotorLoad(), self.motor.maxMotorTorque) );
920 --print( string.format(" %.2f <= %.2f / %.2f", self.actualLoadPercentage, self.motor:getMotorLoad() * 1000, torque) );
921 end
922
923 local neededPtoTorque = PowerConsumer.getTotalConsumedPtoTorque(self);
924 if neededPtoTorque > 0 then
925 local ptoLoad = (neededPtoTorque / self.motor.ptoMotorRpmRatio) / self.motor.maxMotorTorque;
926 self.actualLoadPercentage = math.min(1.0, self.actualLoadPercentage + ptoLoad);
927 end
928
929 if math.abs(self.fuelFillLevel-self.sentFuelFillLevel) > 0.001 then
930 self:raiseDirtyFlags(self.motorizedDirtyFlag);
931 self.sentFuelFillLevel = self.fuelFillLevel;
932 end
933
934 if self.isMotorStarted and not self.isControlled and not self.isEntered and not self:getIsHired() and not g_currentMission.missionInfo.automaticMotorStartEnabled then
935 local isPlayerInRange = false
936 local vx, vy, vz = getWorldTranslation(self.rootNode);
937
938 for _, player in pairs(g_currentMission.players) do
939 if player.isControlled then
940 local px, py, pz = getWorldTranslation(player.rootNode);
941 local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
942 if distance < 250 then
943 isPlayerInRange = true
944 break
945 end
946 end;
947 end;
948 if not isPlayerInRange then
949 for _, steerable in pairs(g_currentMission.steerables) do
950 if steerable.isControlled then
951 local px, py, pz = getWorldTranslation(steerable.rootNode);
952 local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
953 if distance < 250 then
954 isPlayerInRange = true
955 break
956 end
957 end;
958 end;
959 end
960
961 if isPlayerInRange then
962 self.motorStopTimer = self.motorStopTimerDuration
963 else
964 self.motorStopTimer = self.motorStopTimer - dt
965 if self.motorStopTimer <= 0 then
966 self:stopMotor()
967 end
968 end
969 end
970 end
971
972 if self.isClient then
973 if self:getIsMotorStarted() then
974 if self.rpmHud ~= nil then
975 VehicleHudUtils.setHudValue(self, self.rpmHud, self.motor:getLastMotorRpm(), self.motor:getMaxRpm());
976 end
977 if self.speedHud ~= nil then
978 local maxSpeed = 30;
979 if self.cruiseControl ~= nil then
980 maxSpeed = self.cruiseControl.maxSpeed;
981 end
982 VehicleHudUtils.setHudValue(self, self.speedHud, g_i18n:getSpeed(self:getLastSpeed() * self.speedDisplayScale), g_i18n:getSpeed(maxSpeed));
983 end
984
985 if self.exhaustParticleSystems ~= nil then
986 for _, ps in pairs(self.exhaustParticleSystems) do
987 local scale = Utils.lerp(self.exhaustParticleSystems.minScale, self.exhaustParticleSystems.maxScale, self.motor:getEqualizedMotorRpm() / self.motor:getMaxRpm());
988 ParticleUtil.setEmitCountScale(self.exhaustParticleSystems, scale);
989 ParticleUtil.setParticleLifespan(ps, ps.originalLifespan * scale)
990 end
991 end
992
993 if self.exhaustFlap ~= nil then
994 local minRandom = -0.1;
995 local maxRandom = 0.1;
996 local angle = Utils.lerp(minRandom, maxRandom, math.random()) + self.exhaustFlap.maxRot * (self.motor:getEqualizedMotorRpm() / self.motor:getMaxRpm());
997 angle = Utils.clamp(angle, 0, self.exhaustFlap.maxRot);
998 setRotation(self.exhaustFlap.node, angle, 0, 0);
999 end
1000
1001 if self.exhaustEffects ~= nil then
1002 local lastSpeed = self:getLastSpeed();
1003
1004 self.currentDirection = {localDirectionToWorld(self.rootNode, 0, 0, 1)};
1005 if self.lastDirection == nil then
1006 self.lastDirection = self.currentDirection;
1007 end
1008
1009 local x,_,z = worldDirectionToLocal(self.rootNode, self.lastDirection[1], self.lastDirection[2], self.lastDirection[3]);
1010 local dot = z;
1011 dot = dot / Utils.vector2Length(x,z);
1012 local angle = math.acos(dot);
1013 if x < 0 then
1014 angle = -angle;
1015 end
1016 local steeringPercent = math.abs((angle / dt) / self.exhaustEffectMaxSteeringSpeed);
1017 self.lastDirection = self.currentDirection;
1018
1019 for _, effect in pairs(self.exhaustEffects) do
1020 local rpmScale = self.motor:getEqualizedMotorRpm() / self.motor:getMaxRpm();
1021 local scale = Utils.lerp(effect.minRpmScale, effect.maxRpmScale, rpmScale);
1022 local forwardXRot = 0;
1023 local forwardZRot = 0;
1024 local steerXRot = 0;
1025 local steerZRot = 0;
1026
1027 local r = Utils.lerp(effect.minRpmColor[1], effect.maxRpmColor[1], rpmScale);
1028 local g = Utils.lerp(effect.minRpmColor[2], effect.maxRpmColor[2], rpmScale);
1029 local b = Utils.lerp(effect.minRpmColor[3], effect.maxRpmColor[3], rpmScale);
1030 local a = Utils.lerp(effect.minRpmColor[4], effect.maxRpmColor[4], rpmScale);
1031 setShaderParameter(effect.effectNode, "exhaustColor", r, g, b, a, false);
1032
1033 -- speed rotation
1034 if self.movingDirection == 1 then
1035 local percent = Utils.clamp(lastSpeed/effect.maxForwardSpeed, 0, 1);
1036 forwardXRot = effect.xzRotationsForward[1] * percent;
1037 forwardZRot = effect.xzRotationsForward[2] * percent;
1038 elseif self.movingDirection == -1 then
1039 local percent = Utils.clamp(lastSpeed/effect.maxBackwardSpeed, 0, 1);
1040 forwardXRot = effect.xzRotationsBackward[1] * percent;
1041 forwardZRot = effect.xzRotationsBackward[2] * percent;
1042 end
1043
1044 -- steering rotation
1045 if angle > 0 then
1046 steerXRot = effect.xzRotationsRight[1] * steeringPercent;
1047 steerZRot = effect.xzRotationsRight[2] * steeringPercent;
1048 elseif angle < 0 then
1049 steerXRot = effect.xzRotationsLeft[1] * steeringPercent;
1050 steerZRot = effect.xzRotationsLeft[2] * steeringPercent;
1051 end
1052 -- target rotations
1053 local targetXRot = effect.xzRotationsOffset[1] + forwardXRot + steerXRot;
1054 local targetZRot = effect.xzRotationsOffset[2] + forwardZRot + steerZRot;
1055
1056 -- damping
1057 if targetXRot > effect.xRot then
1058 effect.xRot = math.min(effect.xRot + 0.003*dt, targetXRot);
1059 else
1060 effect.xRot = math.max(effect.xRot - 0.003*dt, targetXRot);
1061 end
1062 if targetZRot > effect.xRot then
1063 effect.zRot = math.min(effect.zRot + 0.003*dt, targetZRot);
1064 else
1065 effect.zRot = math.max(effect.zRot - 0.003*dt, targetZRot);
1066 end
1067 setShaderParameter(effect.effectNode, "param", effect.xRot, effect.zRot, 0, scale, false);
1068 end
1069 end
1070 end
1071 end
1072
1073 if self.isFuelFilling then
1074 if self.isServer then
1075 local delta = 0;
1076 if self.fuelFillTrigger ~= nil then
1077 delta = self.fuelFillLitersPerSecond*dt*0.001;
1078 delta = self.fuelFillTrigger:fillFuel(self, delta);
1079 end
1080 if delta <= 0.001 then
1081 self:setIsFuelFilling(false);
1082 end
1083 end
1084 end
1085end

draw

Description
Called on draw
Definition
draw()
Code
1089function Motorized:draw()
1090 if self.isEntered and self.isClient and not self:getIsHired() then
1091 if not g_currentMission.missionInfo.automaticMotorStartEnabled then
1092 if self.isMotorStarted then
1093 g_currentMission:addHelpButtonText(g_i18n:getText("action_stopMotor"), InputBinding.TOGGLE_MOTOR_STATE, nil, GS_PRIO_LOW);
1094 else
1095 g_currentMission:addHelpButtonText(g_i18n:getText("action_startMotor"), InputBinding.TOGGLE_MOTOR_STATE, nil, GS_PRIO_VERY_HIGH);
1096 end
1097 end
1098 end
1099end

startMotor

Description
Start motor
Definition
startMotor(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
1104function Motorized:startMotor(noEventSend)
1105 if noEventSend == nil or noEventSend == false then
1106 if g_server ~= nil then
1107 g_server:broadcastEvent(SetMotorTurnedOnEvent:new(self, true), nil, nil, self);
1108 else
1109 g_client:getServerConnection():sendEvent(SetMotorTurnedOnEvent:new(self, true));
1110 end
1111 end
1112 if not self.isMotorStarted then
1113 self.isMotorStarted = true;
1114
1115 if self.isClient then
1116 if self.exhaustParticleSystems ~= nil then
1117 for _, ps in pairs(self.exhaustParticleSystems) do
1118 ParticleUtil.setEmittingState(ps, true)
1119 end
1120 end
1121 if self:getIsActiveForSound() then
1122 SoundUtil.playSample(self.sampleMotorStart, 1, 0, nil);
1123 end
1124 if self.exhaustEffects ~= nil then
1125 for _, effect in pairs(self.exhaustEffects) do
1126 setVisibility(effect.effectNode, true);
1127 effect.xRot = effect.xzRotationsOffset[1];
1128 effect.zRot = effect.xzRotationsOffset[2];
1129 setShaderParameter(effect.effectNode, "param", effect.xRot, effect.zRot, 0, 0, false);
1130
1131 local color = effect.minRpmColor;
1132 setShaderParameter(effect.effectNode, "exhaustColor", color[1], color[2], color[3], color[4], false);
1133 end
1134 end
1135 end
1136
1137 self.motorStartTime = g_currentMission.time + self.motorStartDuration;
1138 self.compressionSoundTime = g_currentMission.time + math.random(5000, 20000);
1139 self.lastRoundPerMinute=0;
1140
1141 if self.fuelFillLevelHud ~= nil then
1142 VehicleHudUtils.setHudValue(self, self.fuelFillLevelHud, self.fuelFillLevel, self.fuelCapacity);
1143 end
1144 end
1145end

stopMotor

Description
Stop motor
Definition
stopMotor(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
1150function Motorized:stopMotor(noEventSend)
1151 if noEventSend == nil or noEventSend == false then
1152 if g_server ~= nil then
1153 g_server:broadcastEvent(SetMotorTurnedOnEvent:new(self, false), nil, nil, self);
1154 else
1155 g_client:getServerConnection():sendEvent(SetMotorTurnedOnEvent:new(self, false));
1156 end
1157 end
1158
1159 self.isMotorStarted = false;
1160
1161 Motorized.onDeactivateSounds(self);
1162
1163 if self.isClient then
1164 if self.exhaustParticleSystems ~= nil then
1165 for _, ps in pairs(self.exhaustParticleSystems) do
1166 ParticleUtil.setEmittingState(ps, false)
1167 end
1168 end
1169 if self:getIsActiveForSound() then
1170 SoundUtil.playSample(self.sampleMotorStop, 1, 0, nil);
1171 SoundUtil.playSample(self.sampleBrakeCompressorStop, 1, 0, nil);
1172 end
1173
1174 local airConsumption = self:getMaximalAirConsumptionPerFullStop();
1175 self.brakeCompressor.fillLevel = math.max(0, self.brakeCompressor.fillLevel - airConsumption);
1176 self.brakeCompressor.startSoundPlayed = false;
1177 self.brakeCompressor.runSoundActive = false;
1178
1179 if self.exhaustEffects ~= nil then
1180 for _, effect in pairs(self.exhaustEffects) do
1181 setVisibility(effect.effectNode, false);
1182 end
1183 end
1184 if self.exhaustFlap ~= nil then
1185 setRotation(self.exhaustFlap.node, 0, 0, 0);
1186 end
1187
1188 if self.rpmHud ~= nil then
1189 VehicleHudUtils.setHudValue(self, self.rpmHud, 0, self.motor:getMaxRpm());
1190 end
1191 if self.speedHud ~= nil then
1192 VehicleHudUtils.setHudValue(self, self.speedHud, 0, g_i18n:getSpeed(self.motor:getMaximumForwardSpeed()));
1193 end
1194 if self.fuelFillLevelHud ~= nil then
1195 VehicleHudUtils.setHudValue(self, self.fuelFillLevelHud, 0, self.fuelCapacity);
1196 end
1197 end
1198
1199 Motorized.turnOffImplement(self);
1200end

turnOffImplement

Description
Turn off implement and childs of implement
Definition
turnOffImplement(table object)
Arguments
tableobjectobject to turn off
Code
1205function Motorized.turnOffImplement(object)
1206 if object.setIsTurnedOn ~= nil then
1207 object:setIsTurnedOn(false, true);
1208 end
1209 for _,implement in pairs(object.attachedImplements) do
1210 if implement.object ~= nil then
1211 Motorized.turnOffImplement(implement.object);
1212 end
1213 end
1214end

onDeactivateSounds

Description
Called on deactivating sounds
Definition
onDeactivateSounds()
Code
1218function Motorized:onDeactivateSounds()
1219 if self.isClient then
1220 SoundUtil.stopSample(self.sampleMotor, true);
1221 SoundUtil.stopSample(self.sampleMotorRun, true);
1222 SoundUtil.stopSample(self.sampleMotorLoad, true);
1223 SoundUtil.stopSample(self.sampleGearbox, true);
1224 SoundUtil.stopSample(self.sampleRetarder, true);
1225 SoundUtil.stopSample(self.sampleMotorStart, true);
1226 SoundUtil.stopSample(self.sampleBrakeCompressorStart, true);
1227 SoundUtil.stopSample(self.sampleBrakeCompressorRun, true);
1228 SoundUtil.stopSample(self.sampleAirReleaseValve, true);
1229 SoundUtil.stopSample(self.sampleReverseDrive, true);
1230
1231 SoundUtil.stop3DSample(self.sampleMotor, true);
1232 SoundUtil.stop3DSample(self.sampleMotorRun, true);
1233 SoundUtil.stop3DSample(self.sampleReverseDrive, true);
1234 end
1235end

onEnter

Description
Called on enter vehicle
Definition
onEnter(boolean isControlling)
Arguments
booleanisControllingis player controlling the vehicle
Code
1240function Motorized:onEnter(isControlling)
1241 if g_currentMission.missionInfo.automaticMotorStartEnabled then
1242 self:startMotor(true)
1243 end
1244end

onLeave

Description
Called on leaving the vehicle
Definition
onLeave()
Code
1248function Motorized:onLeave()
1249 if self.stopMotorOnLeave and g_currentMission.missionInfo.automaticMotorStartEnabled then
1250 self:stopMotor(true);
1251 end
1252 Motorized.onDeactivateSounds(self);
1253end

setFuelFillLevel

Description
Set fuel fill level
Definition
setFuelFillLevel(float newFillLevel)
Arguments
floatnewFillLevelnew fuel fill level
Code
1258function Motorized:setFuelFillLevel(newFillLevel)
1259 self.fuelFillLevel = math.max(math.min(newFillLevel, self.fuelCapacity), 0);
1260
1261 if self.fuelFillLevelHud ~= nil and math.abs(self.lastFuelFillLevel-self.fuelFillLevel) > 0.1 then
1262 VehicleHudUtils.setHudValue(self, self.fuelFillLevelHud, self.fuelFillLevel, self.fuelCapacity);
1263 self.lastFuelFillLevel = self.fuelFillLevel;
1264 end
1265
1266 if self.fuelFillLevel == 0 and self:getIsHired() then
1267 self:stopAIVehicle(AIVehicle.STOP_REASON_OUT_OF_FUEL)
1268 end
1269end

updateFuelUsage

Description
Update fuel usage
Definition
updateFuelUsage(float dt)
Arguments
floatdttime since last call in ms
Return Values
booleansuccesssuccess
Code
1275function Motorized:updateFuelUsage(superFunc, dt)
1276 if superFunc ~= nil then
1277 if not superFunc(self, dt) then
1278 return false
1279 end
1280 end
1281
1282 local rpmFactor = math.max(0.02, (self.motor:getLastMotorRpm()-self.motor:getMinRpm())/(self.motor:getMaxRpm()-self.motor:getMinRpm()));
1283 local fuelUsageFactor = 1
1284 if g_currentMission.missionInfo.fuelUsageLow then
1285 fuelUsageFactor = 0.7
1286 end
1287
1288 local fuelUsed = fuelUsageFactor * rpmFactor * (self.fuelUsage * dt);
1289
1290 if fuelUsed > 0 then
1291 if not self:getIsHired() or not g_currentMission.missionInfo.helperBuyFuel then
1292 self:setFuelFillLevel(self.fuelFillLevel-fuelUsed);
1293 g_currentMission.missionStats:updateStats("fuelUsage", fuelUsed);
1294 elseif self:getIsHired() and g_currentMission.missionInfo.helperBuyFuel then
1295 local delta = fuelUsed * g_currentMission.economyManager:getPricePerLiter(FillUtil.FILLTYPE_FUEL)
1296 g_currentMission.missionStats:updateStats("expenses", delta);
1297 g_currentMission:addSharedMoney(-delta, "purchaseFuel");
1298 end
1299 end
1300
1301 if self.fuelUsageHud ~= nil then
1302 VehicleHudUtils.setHudValue(self, self.fuelUsageHud, fuelUsed*1000/dt*60*60);
1303 end
1304
1305 return true
1306end

setIsFuelFilling

Description
Set is fuel filling
Definition
setIsFuelFilling(boolean isFilling, boolean noEventSend)
Arguments
booleanisFillingnew is filling state
booleannoEventSendno event send
Code
1312function Motorized:setIsFuelFilling(isFilling, noEventSend)
1313 if isFilling ~= self.isFuelFilling then
1314 if noEventSend == nil or noEventSend == false then
1315 if g_server ~= nil then
1316 g_server:broadcastEvent(SteerableToggleRefuelEvent:new(self, isFilling), nil, nil, self);
1317 else
1318 g_client:getServerConnection():sendEvent(SteerableToggleRefuelEvent:new(self, isFilling));
1319 end
1320 end
1321 self.isFuelFilling = isFilling;
1322 if isFilling then
1323 -- find the first trigger which is activable
1324 self.fuelFillTrigger = nil;
1325 for i=1, table.getn(self.fuelFillTriggers) do
1326 local trigger = self.fuelFillTriggers[i];
1327 if trigger:getIsActivatable(self) then
1328 self.fuelFillTrigger = trigger;
1329 break;
1330 end
1331 end
1332 end
1333 if self.isClient and self.sampleRefuel ~= nil then
1334 if isFilling then
1335 SoundUtil.play3DSample(self.sampleRefuel);
1336 else
1337 SoundUtil.stop3DSample(self.sampleRefuel);
1338 end
1339 end
1340 end
1341end

addFuelFillTrigger

Description
Adds fuel fill trigger if vehicle enters one
Definition
addFuelFillTrigger(table trigger)
Arguments
tabletriggertrigger
Code
1346function Motorized:addFuelFillTrigger(trigger)
1347 if table.getn(self.fuelFillTriggers) == 0 then
1348 g_currentMission:addActivatableObject(self.motorizedFillActivatable);
1349 end
1350 table.insert(self.fuelFillTriggers, trigger);
1351end

removeFuelFillTrigger

Description
Removes fuel fill trigger if vehicle leaves one
Definition
removeFuelFillTrigger(table trigger)
Arguments
tabletriggertrigger
Code
1356function Motorized:removeFuelFillTrigger(trigger)
1357 for i=1, table.getn(self.fuelFillTriggers) do
1358 if self.fuelFillTriggers[i] == trigger then
1359 table.remove(self.fuelFillTriggers, i);
1360 break;
1361 end
1362 end
1363 if table.getn(self.fuelFillTriggers) == 0 or trigger == self.fuelFillTrigger then
1364 if self.isServer then
1365 self:setIsFuelFilling(false);
1366 end
1367 if table.getn(self.fuelFillTriggers) == 0 then
1368 g_currentMission:removeActivatableObject(self.motorizedFillActivatable);
1369 end
1370 end
1371end

getIsOperating

Description
Returns if vehicle is operating
Definition
getIsOperating()
Return Values
booleanisOperatingis operating
Code
1376function Motorized:getIsOperating(superFunc)
1377 local isOperating = false
1378 if superFunc ~= nil then
1379 isOperating = superFunc(self)
1380 end
1381
1382 return isOperating or self:getIsMotorStarted();
1383end

getIsMotorStarted

Description
Returns if motor is stated
Definition
getIsMotorStarted()
Return Values
booleanisStartedmotor is started
Code
1388function Motorized:getIsMotorStarted(superFunc)
1389 local parent = true;
1390 if superFunc ~= nil then
1391 parent = parent and superFunc(self);
1392 end
1393
1394 return parent and self.isMotorStarted
1395end;

getDeactivateOnLeave

Description
Returns if vehicle deactivates on leave
Definition
getDeactivateOnLeave()
Return Values
booleandeactivatevehicle deactivates on leave
Code
1400function Motorized:getDeactivateOnLeave(superFunc)
1401 local deactivate = true
1402 if superFunc ~= nil then
1403 deactivate = deactivate and superFunc(self)
1404 end
1405
1406 return deactivate and g_currentMission.missionInfo.automaticMotorStartEnabled
1407end;

getDeactivateLights

Description
Returns if light deactivate on leaving
Definition
getDeactivateLights()
Return Values
booleandeactivatedeactivate on leaving
Code
1412function Motorized:getDeactivateLights(superFunc)
1413 local deactivate = true
1414 if superFunc ~= nil then
1415 deactivate = deactivate and superFunc(self)
1416 end
1417
1418 return deactivate and g_currentMission.missionInfo.automaticMotorStartEnabled
1419end;

minuteChanged

Description
Called if ingame minute changes
Definition
minuteChanged()
Code
1423function Motorized:minuteChanged()
1424 local minutes = g_currentMission.environment.currentMinute;
1425 local hours = g_currentMission.environment.currentHour;
1426 local minutesString = string.format("%02d", minutes);
1427 VehicleHudUtils.setHudValue(self, self.timeHud, tonumber(hours.."."..minutesString), 9999);
1428end