LUADOC - Farming Simulator 17

Printable Version

Script v1.4.4.0

Engine v7.0.0.2

Foundation Reference

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