LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

Motorized

Description
Specialization for all vehicles with motors/engines. Simulates engine, transmission/gears, fuel usage, air brakes
Functions

actionEventToggleMotorState

Description
Definition
actionEventToggleMotorState()
Code
1784function Motorized.actionEventToggleMotorState(self, actionName, inputValue, callbackState, isAnalog)
1785 if not self:getIsAIActive() then
1786 local spec = self.spec_motorized
1787 if spec.isMotorStarted then
1788 self:stopMotor()
1789 else
1790 if self:getCanMotorRun() then
1791 self:startMotor()
1792 else
1793 local warning = self:getMotorNotAllowedWarning()
1794 if warning ~= nil then
1795 g_currentMission:showBlinkingWarning(warning, 2000)
1796 end
1797 end
1798 end
1799 end
1800end

addToPhysics

Description
Add to physics
Definition
addToPhysics()
Return Values
booleansuccesssuccess
Code
1561function Motorized:addToPhysics(superFunc)
1562 if not superFunc(self) then
1563 return false
1564 end
1565
1566 if self.isServer then
1567 local spec = self.spec_motorized
1568
1569 if spec.motorizedNode ~= nil then
1570 if next(spec.differentials) ~= nil then
1571
1572 for _, differential in pairs(spec.differentials) do
1573 local diffIndex1 = differential.diffIndex1
1574 local diffIndex2 = differential.diffIndex2
1575
1576 if differential.diffIndex1IsWheel then
1577 diffIndex1 = self:getWheelFromWheelIndex(diffIndex1).wheelShape
1578 end
1579 if differential.diffIndex2IsWheel then
1580 diffIndex2 = self:getWheelFromWheelIndex(diffIndex2).wheelShape
1581 end
1582
1583 addDifferential( spec.motorizedNode,
1584 diffIndex1,
1585 differential.diffIndex1IsWheel,
1586 diffIndex2,
1587 differential.diffIndex2IsWheel,
1588 differential.torqueRatio,
1589 differential.maxSpeedRatio )
1590 end
1591
1592 self:updateMotorProperties()
1593
1594 controlVehicle(spec.motorizedNode, 0.0, 0.0, 0.0, 0.0, math.huge, 0.0, 0.0, 0.0, 0.0, 0.0)
1595 end
1596 end
1597 end
1598 return true
1599end

getAirConsumerUsage

Description
Definition
getAirConsumerUsage()
Code
1475function Motorized:getAirConsumerUsage()
1476 local spec = self.spec_motorized
1477 local consumer = spec.consumersByFillTypeName.air
1478 if consumer ~= nil then
1479 return consumer.usage
1480 end
1481
1482 return 0
1483end

getBrakeForce

Description
Definition
getBrakeForce()
Code
1488function Motorized:getBrakeForce(superFunc)
1489 local brakeForce = superFunc(self)
1490 return math.max(brakeForce, self.spec_motorized.motor:getBrakeForce())
1491end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
1760function Motorized:getCanBeSelected(superFunc)
1761 -- if automatic motor start is disabled we need to choose which vehicle we need to turn on/off
1762 if not g_currentMission.missionInfo.automaticMotorStartEnabled then
1763 local vehicles = {}
1764 self:getRootVehicle():getChildVehicles(vehicles)
1765
1766 for _, vehicle in pairs(vehicles) do
1767 if vehicle.spec_motorized ~= nil then
1768 return true
1769 end
1770 end
1771 end
1772
1773 return superFunc(self)
1774end

getCanMotorRun

Description
Definition
getCanMotorRun()
Code
1122function Motorized:getCanMotorRun()
1123 local spec = self.spec_motorized
1124
1125 local canRun = true
1126 if spec.consumersByFillTypeName.diesel ~= nil then
1127 canRun = self:getFillUnitFillLevel(spec.consumersByFillTypeName.diesel.fillUnitIndex) > 0
1128 end
1129
1130 if canRun and spec.consumersByFillTypeName.def ~= nil then
1131 canRun = self:getFillUnitFillLevel(spec.consumersByFillTypeName.def.fillUnitIndex) > 0
1132 end
1133
1134 return canRun
1135end

getCanStartAIVehicle

Description
Definition
getCanStartAIVehicle()
Code
1495function Motorized:getCanStartAIVehicle(superFunc)
1496 return superFunc(self) and self:getIsMotorStarted()
1497end

getConsumerFillUnitIndex

Description
Definition
getConsumerFillUnitIndex()
Code
1463function Motorized:getConsumerFillUnitIndex(fillTypeIndex)
1464 local spec = self.spec_motorized
1465 local consumer = spec.consumersByFillType[fillTypeIndex]
1466 if consumer ~= nil then
1467 return consumer.fillUnitIndex
1468 end
1469
1470 return nil
1471end

getDashboardSpeedDir

Description
Definition
getDashboardSpeedDir()
Code
1778function Motorized:getDashboardSpeedDir()
1779 return self:getLastSpeed() * self.movingDirection
1780end

getDeactivateLightsOnLeave

Description
Returns if vehicle deactivates lights on leave
Definition
getDeactivateLightsOnLeave()
Return Values
booleandeactivatevehicle deactivates on leave
Code
1628function Motorized:getDeactivateLightsOnLeave(superFunc)
1629 return superFunc(self) and g_currentMission.missionInfo.automaticMotorStartEnabled
1630end

getDeactivateOnLeave

Description
Returns if vehicle deactivates on leave
Definition
getDeactivateOnLeave()
Return Values
booleandeactivatevehicle deactivates on leave
Code
1621function Motorized:getDeactivateOnLeave(superFunc)
1622 return superFunc(self) and g_currentMission.missionInfo.automaticMotorStartEnabled
1623end

getIsActiveForInteriorLights

Description
Definition
getIsActiveForInteriorLights()
Code
1540function Motorized:getIsActiveForInteriorLights(superFunc)
1541 if self.spec_motorized.isMotorStarted then
1542 return true
1543 end
1544
1545 return superFunc(self)
1546end

getIsActiveForWipers

Description
Definition
getIsActiveForWipers()
Code
1550function Motorized:getIsActiveForWipers(superFunc)
1551 if not self.spec_motorized.isMotorStarted then
1552 return false
1553 end
1554
1555 return superFunc(self)
1556end

getIsDashboardGroupActive

Description
Definition
getIsDashboardGroupActive()
Code
1514function Motorized:getIsDashboardGroupActive(superFunc, group)
1515 local spec = self.spec_motorized
1516
1517 if group.isMotorRunning and group.isMotorStarting then
1518 if not spec.isMotorStarted then
1519 return false
1520 end
1521 end
1522
1523 if group.isMotorStarting and not group.isMotorRunning then
1524 if not spec.isMotorStarted or spec.motorStartTime < g_currentMission.time then
1525 return false
1526 end
1527 end
1528
1529 if group.isMotorRunning and not group.isMotorStarting then
1530 if not spec.isMotorStarted or spec.motorStartTime > g_currentMission.time then
1531 return false
1532 end
1533 end
1534
1535 return superFunc(self, group)
1536end

getIsMotorStarted

Description
Returns if motor is stated
Definition
getIsMotorStarted()
Return Values
booleanisStartedmotor is started
Code
1116function Motorized:getIsMotorStarted()
1117 return self.spec_motorized.isMotorStarted
1118end

getIsOperating

Description
Returns if vehicle is operating
Definition
getIsOperating()
Return Values
booleanisOperatingis operating
Code
1614function Motorized:getIsOperating(superFunc)
1615 return superFunc(self) or self:getIsMotorStarted()
1616end

getMotor

Description
Definition
getMotor()
Code
1418function Motorized:getMotor()
1419 return self.spec_motorized.motor
1420end

getMotorBrakeTime

Description
Definition
getMotorBrakeTime()
Code
1451function Motorized:getMotorBrakeTime()
1452 local sample = self.spec_motorized.samples.compressedAir
1453 if sample ~= nil then
1454 return sample.lastBrakeTime / 1000
1455 end
1456
1457 return 0
1458end

getMotorLoadPercentage

Description
Definition
getMotorLoadPercentage()
Code
1444function Motorized:getMotorLoadPercentage()
1445 return self.spec_motorized.smoothedLoadPercentage * (math.min(self:getMotorRpmPercentage() * 3, 1))
1446end

getMotorNotAllowedWarning

Description
Definition
getMotorNotAllowedWarning()
Code
1145function Motorized:getMotorNotAllowedWarning()
1146 local spec = self.spec_motorized
1147
1148 if spec.consumersByFillTypeName.diesel ~= nil then
1149 if self:getFillUnitFillLevel(spec.consumersByFillTypeName.diesel.fillUnitIndex) <= 0 then
1150 return spec.consumersEmptyWarning
1151 end
1152 end
1153
1154 if spec.consumersByFillTypeName.def ~= nil then
1155 if self:getFillUnitFillLevel(spec.consumersByFillTypeName.def.fillUnitIndex) <= 0 then
1156 return spec.consumersEmptyWarning
1157 end
1158 end
1159
1160 return nil
1161end

getMotorRpmPercentage

Description
Definition
getMotorRpmPercentage()
Code
1436function Motorized:getMotorRpmPercentage()
1437 local motor = self.spec_motorized.motor
1438 return (motor:getEqualizedMotorRpm() - motor:getMinRpm()) / (motor:getMaxRpm() - motor:getMinRpm())
1439end

getMotorStartTime

Description
Definition
getMotorStartTime()
Code
1424function Motorized:getMotorStartTime()
1425 return self.spec_motorized.motorStartTime
1426end

getMotorType

Description
Definition
getMotorType()
Code
1430function Motorized:getMotorType()
1431 return self.spec_motorized.motorType
1432end

getName

Description
Definition
getName()
Code
1743function Motorized:getName(superFunc)
1744 local name = superFunc(self)
1745
1746 local item = g_storeManager:getItemByXMLFilename(self.configFileName)
1747 if item ~= nil and item.configurations ~= nil then
1748 local configId = self.configurations["motor"]
1749 local config = item.configurations["motor"][configId]
1750 if config.name ~= "" then
1751 name = config.name
1752 end
1753 end
1754
1755 return name
1756end

getSpecValueFuel

Description
Definition
getSpecValueFuel()
Code
1882function Motorized.getSpecValueFuel(storeItem, realItem)
1883 local consumerIndex = 1
1884 local motorConfigId = 1
1885 if realItem ~= nil and storeItem.configurations ~= nil and realItem.configurations["motor"] ~= nil and storeItem.configurations["motor"] ~= nil then
1886 motorConfigId = realItem.configurations["motor"]
1887 consumerIndex = Utils.getNoNil(storeItem.configurations["motor"][motorConfigId].consumerConfigurationIndex, consumerIndex)
1888 end
1889
1890 local fuel, def = nil, nil
1891
1892 local fuelFillUnitIndex = 0
1893 local defFillUnitIndex = 0
1894
1895 local consumerConfiguration = storeItem.specs.fuel.consumers[consumerIndex]
1896 if consumerConfiguration ~= nil then
1897 for _, unitConsumers in ipairs(consumerConfiguration) do
1898 if g_fillTypeManager:getFillTypeIndexByName(unitConsumers.fillType) == FillType.DIESEL then
1899 fuelFillUnitIndex = unitConsumers.fillUnitIndex
1900 end
1901
1902 if g_fillTypeManager:getFillTypeIndexByName(unitConsumers.fillType) == FillType.DEF then
1903 defFillUnitIndex = unitConsumers.fillUnitIndex
1904 end
1905 end
1906 end
1907
1908 local fuelConfigIndex = 1
1909 if realItem ~= nil and storeItem.configurations ~= nil and realItem.configurations["fillUnit"] ~= nil and storeItem.configurations["fillUnit"] ~= nil then
1910 fuelConfigIndex = realItem.configurations["fillUnit"]
1911 end
1912
1913 if storeItem.specs.fuel.fillUnits[fuelConfigIndex] ~= nil then
1914 local fuelFillUnit = storeItem.specs.fuel.fillUnits[fuelConfigIndex][fuelFillUnitIndex]
1915 if fuelFillUnit ~= nil then
1916 fuel = math.max(fuelFillUnit.capacity, fuel or 0)
1917 end
1918
1919 local defFillUnit = storeItem.specs.fuel.fillUnits[fuelConfigIndex][defFillUnitIndex]
1920 if defFillUnit ~= nil then
1921 def = math.max(defFillUnit.capacity, def or 0)
1922 end
1923 end
1924
1925 if fuel ~= nil then
1926 if def ~= nil and def > 0 then
1927 return string.format(g_i18n:getText("shop_fuelDefValue"), fuel, g_i18n:getText("unit_literShort"), def, g_i18n:getText("unit_literShort"), g_i18n:getText("fillType_def_short"))
1928 else
1929 return string.format(g_i18n:getText("shop_fuelValue"), fuel, g_i18n:getText("unit_literShort"))
1930 end
1931 end
1932
1933 return nil
1934end

getSpecValueMaxSpeed

Description
Definition
getSpecValueMaxSpeed()
Code
1969function Motorized.getSpecValueMaxSpeed(storeItem, realItem)
1970 local maxSpeed = nil
1971 if realItem ~= nil and storeItem.configurations ~= nil and realItem.configurations["motor"] ~= nil and storeItem.configurations["motor"] ~= nil then
1972 local configId = realItem.configurations["motor"]
1973 maxSpeed = Utils.getNoNil(storeItem.configurations["motor"][configId].maxSpeed, maxSpeed)
1974 end
1975 if maxSpeed == nil then
1976 maxSpeed = storeItem.specs.maxSpeed
1977 end
1978 if maxSpeed ~= nil then
1979 return string.format(g_i18n:getText("shop_maxSpeed"), string.format("%1d", g_i18n:getSpeed(maxSpeed)), g_i18n:getSpeedMeasuringUnit())
1980 end
1981 return nil
1982end

getSpecValuePower

Description
Definition
getSpecValuePower()
Code
1992function Motorized.getSpecValuePower(storeItem, realItem)
1993 local power = nil
1994 if realItem ~= nil and storeItem.configurations ~= nil and realItem.configurations["motor"] ~= nil and storeItem.configurations["motor"] ~= nil then
1995 local configId = realItem.configurations["motor"]
1996 power = Utils.getNoNil(storeItem.configurations["motor"][configId].power, power)
1997 end
1998 if power == nil then
1999 power = storeItem.specs.power
2000 end
2001 if power ~= nil then
2002 local hp, kw = g_i18n:getPower(power)
2003 return string.format(g_i18n:getText("shop_maxPowerValue"), MathUtil.round(kw), MathUtil.round(hp))
2004 end
2005 return nil
2006end

getStopMotorOnLeave

Description
Definition
getStopMotorOnLeave()
Code
1139function Motorized:getStopMotorOnLeave()
1140 return self.spec_motorized.stopMotorOnLeave
1141end

getStoreAddtionalConfigData

Description
Definition
getStoreAddtionalConfigData()
Code
1805function Motorized.getStoreAddtionalConfigData(xmlFile, baseXMLName, baseDir, customEnvironment, isMod, configItem)
1806 configItem.power = getXMLInt(xmlFile, baseXMLName.."#hp")
1807 configItem.maxSpeed = getXMLInt(xmlFile, baseXMLName.."#maxSpeed")
1808 configItem.consumerConfigurationIndex = getXMLInt(xmlFile, baseXMLName.."#consumerConfigurationIndex")
1809end

initSpecialization

Description
Definition
initSpecialization()
Code
18function Motorized.initSpecialization()
19 g_configurationManager:addConfigurationType("motor", g_i18n:getText("configuration_motorSetup"), "motorized", nil, Motorized.getStoreAddtionalConfigData, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
20
21 g_storeManager:addSpecType("fuel", "shopListAttributeIconFuel", Motorized.loadSpecValueFuel, Motorized.getSpecValueFuel)
22 g_storeManager:addSpecType("maxSpeed", "shopListAttributeIconMaxSpeed", Motorized.loadSpecValueMaxSpeed, Motorized.getSpecValueMaxSpeed)
23 g_storeManager:addSpecType("power", "shopListAttributeIconPower", Motorized.loadSpecValuePower, Motorized.getSpecValuePower)
24
25 Vehicle.registerStateChange("MOTOR_TURN_ON")
26 Vehicle.registerStateChange("MOTOR_TURN_OFF")
27end

loadConsumerConfiguration

Description
Definition
loadConsumerConfiguration()
Code
1058function Motorized:loadConsumerConfiguration(xmlFile, consumerIndex)
1059 local key = string.format("vehicle.motorized.consumerConfigurations.consumerConfiguration(%d)", consumerIndex-1)
1060
1061 local spec = self.spec_motorized
1062
1063 local fallbackConfigKey = "vehicle.motorized.consumers"
1064 local fallbackOldKey = nil
1065
1066 spec.consumers = {}
1067 spec.consumersByFillTypeName = {}
1068 spec.consumersByFillType = {}
1069
1070 if not hasXMLProperty(xmlFile, key) then
1071 return
1072 end
1073
1074 local i = 0
1075 while true do
1076 local consumerKey = string.format(".consumer(%d)", i)
1077 if not hasXMLProperty(xmlFile, key..consumerKey) then
1078 break
1079 end
1080 local consumer = {}
1081 consumer.fillUnitIndex = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#fillUnitIndex", getXMLInt, 1, fallbackConfigKey, fallbackOldKey)
1082
1083 local fillTypeName = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#fillType", getXMLString, "consumer", fallbackConfigKey, fallbackOldKey)
1084 consumer.fillType = g_fillTypeManager:getFillTypeIndexByName(fillTypeName)
1085
1086 local fillUnit = self:getFillUnitByIndex(consumer.fillUnitIndex)
1087 if fillUnit ~= nil then
1088 --fill fillUnit on start
1089 fillUnit.startFillLevel = fillUnit.capacity
1090 fillUnit.startFillTypeIndex = consumer.fillType
1091 else
1092 g_logManager:xmlWarning(self.configFileName, "Unknown fillUnit '%d' for consumer '%s'", consumer.fillUnitIndex, key..consumerKey)
1093 break
1094 end
1095
1096 local usage = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#usage", getXMLFloat, 1.0, fallbackConfigKey, fallbackOldKey)
1097 consumer.permanentConsumption = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#permanentConsumption", getXMLBool, true, fallbackConfigKey, fallbackOldKey)
1098 if consumer.permanentConsumption then
1099 consumer.usage = usage / (60*60*1000) -- from l/h to l/ms
1100 else
1101 consumer.usage = usage
1102 end
1103 consumer.refillLitersPerSecond = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#refillLitersPerSecond", getXMLFloat, 0, fallbackConfigKey, fallbackOldKey)
1104 consumer.refillCapacityPercentage = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#refillCapacityPercentage", getXMLFloat, 0, fallbackConfigKey, fallbackOldKey)
1105
1106 table.insert(spec.consumers, consumer)
1107 spec.consumersByFillTypeName[fillTypeName] = consumer
1108 spec.consumersByFillType[consumer.fillType] = consumer
1109 i = i + 1
1110 end
1111end

loadDashboardGroupFromXML

Description
Definition
loadDashboardGroupFromXML()
Code
1501function Motorized:loadDashboardGroupFromXML(superFunc, xmlFile, key, group)
1502 if not superFunc(self, xmlFile, key, group) then
1503 return false
1504 end
1505
1506 group.isMotorStarting = getXMLBool(xmlFile, key .. "#isMotorStarting")
1507 group.isMotorRunning = getXMLBool(xmlFile, key .. "#isMotorRunning")
1508
1509 return true
1510end

loadDifferentials

Description
Load differentials from xml
Definition
loadDifferentials(integer xmlFile, integer configDifferentialIndex)
Arguments
integerxmlFileid of xml object
integerconfigDifferentialIndexindex of differential config
Code
686function Motorized:loadDifferentials(xmlFile, configDifferentialIndex)
687 local key,_ = ConfigurationUtil.getXMLConfigurationKey(xmlFile, configDifferentialIndex, "vehicle.motorized.differentialConfigurations.differentialConfiguration", "vehicle.motorized.differentials", "differentials")
688
689 local spec = self.spec_motorized
690
691 spec.differentials = {}
692 if self.isServer and spec.motorizedNode ~= nil then
693 local i = 0
694 while true do
695 local key = string.format(key..".differentials.differential(%d)", i)
696 if not hasXMLProperty(xmlFile, key) then
697 break
698 end
699 local torqueRatio = Utils.getNoNil(getXMLFloat(xmlFile, key.."#torqueRatio"), 0.5)
700 local maxSpeedRatio = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxSpeedRatio"), 1.3)
701
702 local indices = {-1, -1}
703 local indexIsWheel = {false, false}
704 for j=1,2 do
705 local wheelIndex = getXMLInt(xmlFile, key .. string.format("#wheelIndex%d", j))
706 if wheelIndex ~= nil then
707 if self:getWheelFromWheelIndex(wheelIndex) ~= nil then
708 indices[j] = wheelIndex
709 indexIsWheel[j] = true
710 else
711 g_logManager:xmlWarning(self.configFileName, "Unable to find wheelIndex '%d' for differential '%s' (Indices start at 1)", wheelIndex, key)
712 end
713 else
714 local diffIndex = getXMLInt(xmlFile, key .. string.format("#differentialIndex%d", j))
715 if diffIndex ~= nil then
716 indices[j] = diffIndex - 1
717 indexIsWheel[j] = false
718
719 if diffIndex == 0 then
720 g_logManager:xmlWarning(self.configFileName, "Unable to find differentialIndex '0' for differential '%s' (Indices start at 1)", key)
721 end
722 end
723 end
724 end
725
726 if indices[1] ~= -1 and indices[2] ~= -1 then
727 table.insert(spec.differentials, {
728 torqueRatio = torqueRatio,
729 maxSpeedRatio = maxSpeedRatio,
730 diffIndex1 = indices[1],
731 diffIndex1IsWheel = indexIsWheel[1],
732 diffIndex2 = indices[2],
733 diffIndex2IsWheel = indexIsWheel[2] } )
734 end
735
736 i = i + 1
737 end
738
739 if #spec.differentials == 0 then
740 g_logManager:xmlWarning(self.configFileName, "No differentials defined")
741 end
742 end
743end

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
923function Motorized:loadExhaustEffects(xmlFile)
924 local spec = self.spec_motorized
925
926 spec.exhaustParticleSystems = {}
927 local exhaustParticleSystemCount = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.motorized.exhaustParticleSystems#count"), 0)
928 for i=1, exhaustParticleSystemCount do
929 local namei = string.format("vehicle.motorized.exhaustParticleSystems.exhaustParticleSystem%d", i)
930 local ps = {}
931 ParticleUtil.loadParticleSystem(xmlFile, ps, namei, self.components, false, nil, self.baseDirectory)
932 ps.minScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorized.exhaustParticleSystems#minScale"), 0.5)
933 ps.maxScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorized.exhaustParticleSystems#maxScale"), 1)
934 table.insert(spec.exhaustParticleSystems, ps)
935 end
936 if #spec.exhaustParticleSystems == 0 then
937 spec.exhaustParticleSystems = nil
938 end
939
940 XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, "vehicle.motorized.exhaustFlap#index", "vehicle.motorized.exhaustFlap#node") --FS17 to FS19
941
942 local exhaustFlapIndex = getXMLString(xmlFile, "vehicle.motorized.exhaustFlap#node")
943 if exhaustFlapIndex ~= nil then
944 spec.exhaustFlap = {}
945 spec.exhaustFlap.node = I3DUtil.indexToObject(self.components, exhaustFlapIndex, self.i3dMappings)
946 spec.exhaustFlap.maxRot = MathUtil.degToRad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorized.exhaustFlap#maxRot"),0))
947 end
948
949 spec.exhaustEffects = {}
950 local i = 0
951 while true do
952 local key = string.format("vehicle.motorized.exhaustEffects.exhaustEffect(%d)", i)
953 if not hasXMLProperty(xmlFile, key) then
954 break
955 end
956
957 XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key.."#index", key.."#node") --FS17 to FS19
958
959 local linkNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#node"), self.i3dMappings)
960 local filename = getXMLString(xmlFile, key .. "#filename")
961 if filename ~= nil and linkNode ~= nil then
962 local i3dNode = g_i3DManager:loadSharedI3DFile(filename, self.baseDirectory, false, false, false)
963 if i3dNode ~= 0 then
964 local node = getChildAt(i3dNode, 0)
965 if getHasShaderParameter(node, "param") then
966 local effect = {}
967 effect.effectNode = node
968 effect.node = linkNode
969 effect.filename = filename
970 link(effect.node, effect.effectNode)
971 setVisibility(effect.effectNode, false)
972 delete(i3dNode)
973
974 effect.minRpmColor = StringUtil.getVectorNFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#minRpmColor"), "0 0 0 1"), 4)
975 effect.maxRpmColor = StringUtil.getVectorNFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#maxRpmColor"), "0.0384 0.0359 0.0627 2.0"), 4)
976 effect.minRpmScale = Utils.getNoNil(getXMLFloat(xmlFile, key.."#minRpmScale"), 0.25)
977 effect.maxRpmScale = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxRpmScale"), 0.95)
978 effect.maxForwardSpeed = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxForwardSpeed"), math.ceil(spec.motor:getMaximumForwardSpeed()*3.6))
979 effect.maxBackwardSpeed = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxBackwardSpeed"), math.ceil(spec.motor:getMaximumBackwardSpeed()*3.6))
980
981 effect.xzRotationsOffset = StringUtil.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsOffset"), "0 0"), 2)
982 effect.xzRotationsForward = StringUtil.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsForward"), "0 0"), 2)
983 effect.xzRotationsBackward = StringUtil.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsBackward"), "0 0"), 2)
984 effect.xzRotationsLeft = StringUtil.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsLeft"), "0 0"), 2)
985 effect.xzRotationsRight = StringUtil.getRadiansFromString(Utils.getNoNil(getXMLString(xmlFile, key.."#xzRotationsRight"), "0 0"), 2)
986
987 effect.xRot = 0
988 effect.zRot = 0
989
990 table.insert(spec.exhaustEffects, effect)
991 end
992 end
993 end
994 i = i + 1
995 end
996 spec.exhaustEffectMaxSteeringSpeed = 0.001
997end

loadGears

Description
Definition
loadGears()
Code
892function Motorized:loadGears(xmlFile, gearName, motorKey, motorId, fallbackConfigKey, fallbackOldKey, motorMaxRpm, axleRatio)
893 -- Read gear ratios
894 local gearBase
895 if motorKey ~= nil and hasXMLProperty(xmlFile, string.format("%s.transmission.%s(0)", motorKey, gearName)) then -- using selected motor configuration
896 gearBase = string.format("%s.transmission.%s", motorKey, gearName)
897 elseif motorKey ~= nil and hasXMLProperty(xmlFile, string.format("%s.transmission.%s(0)", fallbackConfigKey, gearName)) then -- using default motor configuration
898 gearBase = string.format("%s.transmission.%s", fallbackConfigKey, gearName)
899 else
900 gearBase = string.format("%s.transmission.%s", fallbackOldKey, gearName) -- fallback to old motor setup
901 end
902
903 local gearRatios = {}
904 local gearI = 0
905 while true do
906 local gearKey = string.format(gearBase.."(%d)", gearI)
907 local gearRatio = getXMLFloat(xmlFile, gearKey.."#gearRatio")
908 if gearRatio == nil then
909 break
910 end
911 table.insert(gearRatios, gearRatio*axleRatio)
912 gearI = gearI +1
913 end
914 if #gearRatios > 0 then
915 return gearRatios
916 end
917end

loadMotor

Description
Load motor from xml file
Definition
loadMotor(integer xmlFile, integer motorId)
Arguments
integerxmlFileid of xml object
integermotorIdindex of motor configuration
Code
749function Motorized:loadMotor(xmlFile, motorId)
750 local key, motorId = ConfigurationUtil.getXMLConfigurationKey(xmlFile, motorId, "vehicle.motorized.motorConfigurations.motorConfiguration", "vehicle.motorized", "motor")
751
752 local spec = self.spec_motorized
753
754 local fallbackConfigKey = "vehicle.motorized.motorConfigurations.motorConfiguration(0)"
755 local fallbackOldKey = "vehicle"
756
757 spec.motorType = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#type", getXMLString, "vehicle", fallbackConfigKey, fallbackOldKey)
758 spec.motorStartAnimation = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#startAnimationName", getXMLString, "vehicle", fallbackConfigKey, fallbackOldKey)
759
760 spec.fuelCapacity = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".fuelCapacity", "", getXMLFloat, 500, fallbackConfigKey, fallbackOldKey)
761 spec.consumerConfigurationIndex = ConfigurationUtil.getConfigurationValue(xmlFile, key, "#consumerConfigurationIndex", "", getXMLInt, 1, fallbackConfigKey, fallbackOldKey)
762
763 local wheelKey, _ = ConfigurationUtil.getXMLConfigurationKey(xmlFile, self.configurations["wheel"], "vehicle.wheels.wheelConfigurations.wheelConfiguration", "vehicle.wheels", "wheels")
764
765 ObjectChangeUtil.updateObjectChanges(xmlFile, "vehicle.motorized.motorConfigurations.motorConfiguration", motorId, self.components, self)
766
767 local motorMinRpm = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#minRpm", getXMLFloat, 1000, fallbackConfigKey, fallbackOldKey)
768 local motorMaxRpm = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#maxRpm", getXMLFloat, 1800, fallbackConfigKey, fallbackOldKey)
769 local minSpeed = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#minSpeed", getXMLFloat, 1, fallbackConfigKey, fallbackOldKey)
770 local maxForwardSpeed = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#maxForwardSpeed", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey)
771 local maxBackwardSpeed = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#maxBackwardSpeed", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey)
772 if maxForwardSpeed ~= nil then
773 maxForwardSpeed = maxForwardSpeed/3.6
774 end
775 if maxBackwardSpeed ~= nil then
776 maxBackwardSpeed = maxBackwardSpeed/3.6
777 end
778
779 local maxWheelSpeed = ConfigurationUtil.getConfigurationValue(xmlFile, wheelKey, ".wheels", "#maxForwardSpeed", getXMLFloat, nil, nil, "vehicle.wheels")
780 if maxWheelSpeed ~= nil then
781 maxForwardSpeed = maxWheelSpeed/3.6
782 end
783 local accelerationLimit = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#accelerationLimit", getXMLFloat, 2.0, fallbackConfigKey, fallbackOldKey) -- m/s^2
784
785 local brakeForce = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#brakeForce", getXMLFloat, 10, fallbackConfigKey, fallbackOldKey)*2
786 local lowBrakeForceScale = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#lowBrakeForceScale", getXMLFloat, 0.5, fallbackConfigKey, fallbackOldKey)
787 local lowBrakeForceSpeedLimit = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#lowBrakeForceSpeedLimit", getXMLFloat, 1, fallbackConfigKey, fallbackOldKey)/3600
788 local torqueScale = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#torqueScale", getXMLFloat, 1, fallbackConfigKey, fallbackOldKey)
789 local ptoMotorRpmRatio = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#ptoMotorRpmRatio", getXMLFloat, 4, fallbackConfigKey, fallbackOldKey)
790
791 local minForwardGearRatio = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".transmission", "#minForwardGearRatio", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey)
792 local maxForwardGearRatio = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".transmission", "#maxForwardGearRatio", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey)
793 local minBackwardGearRatio = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".transmission", "#minBackwardGearRatio", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey)
794 local maxBackwardGearRatio = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".transmission", "#maxBackwardGearRatio", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey)
795 local gearChangeTime = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".transmission", "#gearChangeTime", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey)
796 local autoGearChangeTime = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".transmission", "#autoGearChangeTime", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey)
797 local axleRatio = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".transmission", "#axleRatio", getXMLFloat, 1.0, fallbackConfigKey, fallbackOldKey)
798
799
800 if maxForwardGearRatio == nil or minForwardGearRatio == nil then
801 minForwardGearRatio = nil
802 maxForwardGearRatio = nil
803 else
804 minForwardGearRatio = minForwardGearRatio * axleRatio
805 maxForwardGearRatio = maxForwardGearRatio * axleRatio
806 end
807 if minBackwardGearRatio == nil or maxBackwardGearRatio == nil then
808 minBackwardGearRatio = nil
809 maxBackwardGearRatio = nil
810 else
811 minBackwardGearRatio = minBackwardGearRatio * axleRatio
812 maxBackwardGearRatio = maxBackwardGearRatio * axleRatio
813 end
814
815 -- Read forward gear ratios
816 local forwardGearRatios
817 if minForwardGearRatio == nil then
818 forwardGearRatios = self:loadGears(xmlFile, "forwardGear", key, motorId, fallbackConfigKey, fallbackOldKey, motorMaxRpm, axleRatio)
819 if forwardGearRatios == nil then
820 print("Warning: Missing forward gear ratios for motor in '"..self.configFileName.."'!")
821 forwardGearRatios = {1}
822 end
823 end
824 -- Read backward gear ratios
825 local backwardGearRatios
826 if minBackwardGearRatio == nil then
827 backwardGearRatios = self:loadGears(xmlFile, "backwardGear", key, motorId, fallbackConfigKey, fallbackOldKey, motorMaxRpm, axleRatio)
828 if backwardGearRatios == nil then
829 print("Warning: Missing backward gear ratios for motor in '"..self.configFileName.."'!")
830 backwardGearRatios = {1}
831 end
832 end
833
834 --local maxTorque = 0
835 local torqueCurve = AnimCurve:new(linearInterpolator1)
836 local torqueI = 0
837 local torqueBase = fallbackOldKey..".motor.torque" -- fallback to old motor setup
838 if key ~= nil and hasXMLProperty(xmlFile, fallbackConfigKey..".motor.torque(0)") then -- using default motor configuration
839 torqueBase = fallbackConfigKey..".motor.torque"
840 end
841 if key ~= nil and hasXMLProperty(xmlFile, key..".motor.torque(0)") then -- using selected motor configuration
842 torqueBase = key..".motor.torque"
843 end
844
845 while true do
846 local torqueKey = string.format(torqueBase.."(%d)", torqueI)
847 local normRpm = getXMLFloat(xmlFile, torqueKey.."#normRpm")
848 local rpm
849 if normRpm == nil then
850 rpm = getXMLFloat(xmlFile, torqueKey.."#rpm")
851 else
852 rpm = normRpm * motorMaxRpm
853 end
854 local torque = getXMLFloat(xmlFile, torqueKey.."#torque")
855 if torque == nil or rpm == nil then
856 break
857 end
858 torqueCurve:addKeyframe({torque*torqueScale, time = rpm})
859 torqueI = torqueI +1
860 end
861
862 spec.motor = VehicleMotor:new(self, motorMinRpm, motorMaxRpm, maxForwardSpeed, maxBackwardSpeed, torqueCurve, brakeForce, forwardGearRatios, backwardGearRatios, minForwardGearRatio, maxForwardGearRatio, minBackwardGearRatio, maxBackwardGearRatio, ptoMotorRpmRatio, minSpeed)
863
864 local rotInertia = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#rotInertia", getXMLFloat, spec.motor:getRotInertia(), fallbackConfigKey, fallbackOldKey)
865 local dampingRateFullThrottle = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#dampingRateFullThrottle", getXMLFloat, spec.motor:getDampingRateFullThrottle(), fallbackConfigKey, fallbackOldKey)
866 local dampingRateZeroThrottleClutchEngaged = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#dampingRateZeroThrottleClutchEngaged", getXMLFloat, spec.motor:getDampingRateZeroThrottleClutchEngaged(), fallbackConfigKey, fallbackOldKey)
867 local dampingRateZeroThrottleClutchDisengaged = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#dampingRateZeroThrottleClutchDisengaged", getXMLFloat, spec.motor:getDampingRateZeroThrottleClutchDisengaged(), fallbackConfigKey, fallbackOldKey)
868 spec.motor:setRotInertia(rotInertia)
869 spec.motor:setDampingRateFullThrottle(dampingRateFullThrottle)
870 spec.motor:setDampingRateZeroThrottleClutchEngaged(dampingRateZeroThrottleClutchEngaged)
871 spec.motor:setDampingRateZeroThrottleClutchDisengaged(dampingRateZeroThrottleClutchDisengaged)
872 spec.motor:setLowBrakeForce(lowBrakeForceScale, lowBrakeForceSpeedLimit)
873 spec.motor:setAccelerationLimit(accelerationLimit)
874
875 local motorRotationAccelerationLimit = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#rpmSpeedLimit", getXMLFloat, nil, fallbackConfigKey, fallbackOldKey) -- xml: rpm/s -> converted to rad/s^2
876 if motorRotationAccelerationLimit ~= nil then
877 motorRotationAccelerationLimit = motorRotationAccelerationLimit * math.pi/30
878 spec.motor:setMotorRotationAccelerationLimit(motorRotationAccelerationLimit)
879 end
880
881 if gearChangeTime ~= nil then
882 spec.motor:setGearChangeTime(gearChangeTime*1000)
883 end
884 if autoGearChangeTime ~= nil then
885 spec.motor:setAutoGearChangeTime(autoGearChangeTime*1000)
886 end
887end

loadSounds

Description
Load sounds from xml file
Definition
loadSounds(integer xmlFile)
Arguments
integerxmlFileid of xml object
Code
1003function Motorized:loadSounds(xmlFile, motorId)
1004 if self.isClient then
1005 local spec = self.spec_motorized
1006
1007 local baseString = "vehicle.motorized.sounds"
1008 spec.samples = {}
1009
1010 spec.samples.motorStart = g_soundManager:loadSampleFromXML(xmlFile, baseString, "motorStart", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
1011 spec.samples.motorStop = g_soundManager:loadSampleFromXML(xmlFile, baseString, "motorStop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
1012 spec.samples.gearbox = g_soundManager:loadSampleFromXML(xmlFile, baseString, "gearbox", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
1013 spec.samples.retarder = g_soundManager:loadSampleFromXML(xmlFile, baseString, "retarder", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
1014
1015 spec.motorSamples = {}
1016 local i = 0
1017 while true do
1018 local sample = g_soundManager:loadSampleFromXML(xmlFile, baseString, string.format("motor(%d)", i), self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
1019 if sample == nil then
1020 break
1021 end
1022
1023 table.insert(spec.motorSamples, sample)
1024 i = i + 1
1025 end
1026
1027 spec.samples.airCompressorStart = g_soundManager:loadSampleFromXML(xmlFile, baseString, "airCompressorStart", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
1028 spec.samples.airCompressorStop = g_soundManager:loadSampleFromXML(xmlFile, baseString, "airCompressorStop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
1029 spec.samples.airCompressorRun = g_soundManager:loadSampleFromXML(xmlFile, baseString, "airCompressorRun", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
1030
1031 spec.samples.compressedAir = g_soundManager:loadSampleFromXML(xmlFile, baseString, "compressedAir", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
1032 if spec.samples.compressedAir ~= nil then
1033 spec.samples.compressedAir.brakeTime = 0
1034 spec.samples.compressedAir.lastBrakeTime = 0
1035 end
1036
1037 spec.samples.airRelease = g_soundManager:loadSampleFromXML(xmlFile, baseString, "airRelease", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
1038
1039 spec.samples.reverseDrive = g_soundManager:loadSampleFromXML(xmlFile, baseString, "reverseDrive", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
1040 spec.reverseDriveThreshold = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorized.reverseDriveSound#threshold"), 4)
1041
1042 spec.brakeCompressor = {}
1043 spec.brakeCompressor.capacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorized.brakeCompressor#capacity"), 6)
1044 spec.brakeCompressor.refillFilllevel = math.min(spec.brakeCompressor.capacity, Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorized.brakeCompressor#refillFillLevel"), spec.brakeCompressor.capacity/2))
1045 spec.brakeCompressor.fillSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.motorized.brakeCompressor#fillSpeed"), 0.6) / 1000
1046 spec.brakeCompressor.fillLevel = 0
1047 spec.brakeCompressor.doFill = true
1048
1049 spec.isBrakeSamplePlaying = false
1050 spec.samples.brake = g_soundManager:loadSampleFromXML(xmlFile, baseString, "brake", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
1051
1052 spec.compressionSoundTime = 0
1053 end
1054end

loadSpecValueFuel

Description
Definition
loadSpecValueFuel()
Code
1813function Motorized.loadSpecValueFuel(xmlFile, customEnvironment)
1814 local rootName = getXMLRootName(xmlFile)
1815
1816 local fillUnits = {}
1817
1818 local i = 0
1819 while true do
1820 local configKey = string.format(rootName..".fillUnit.fillUnitConfigurations.fillUnitConfiguration(%d)", i)
1821 if not hasXMLProperty(xmlFile, configKey) then
1822 break
1823 end
1824
1825 local configFillUnits = {}
1826
1827 local j = 0
1828 while true do
1829 local fillUnitKey = string.format(configKey .. ".fillUnits.fillUnit(%d)", j)
1830 if not hasXMLProperty(xmlFile, fillUnitKey) then
1831 break
1832 end
1833
1834 local fillTypes = getXMLString(xmlFile, fillUnitKey .. "#fillTypes")
1835 local capacity = getXMLFloat(xmlFile, fillUnitKey .. "#capacity")
1836
1837 table.insert(configFillUnits, {fillTypes=fillTypes, capacity=capacity})
1838 j = j + 1
1839 end
1840
1841 table.insert(fillUnits, configFillUnits)
1842
1843 i = i + 1
1844 end
1845
1846 local consumers = {}
1847
1848 i = 0
1849 while true do
1850 local key = string.format(rootName..".motorized.consumerConfigurations.consumerConfiguration(%d)", i)
1851 if not hasXMLProperty(xmlFile, key) then
1852 break
1853 end
1854
1855 local consumer = {}
1856
1857 local j = 0
1858 while true do
1859 local consumerKey = string.format(key..".consumer(%d)", j)
1860 if not hasXMLProperty(xmlFile, consumerKey) then
1861 break
1862 end
1863
1864 local fillType = getXMLString(xmlFile, consumerKey .. "#fillType")
1865 local fillUnitIndex = getXMLInt(xmlFile, consumerKey .. "#fillUnitIndex")
1866
1867 table.insert(consumer, {fillType=fillType, fillUnitIndex=fillUnitIndex})
1868
1869 j = j + 1
1870 end
1871
1872 table.insert(consumers, consumer)
1873
1874 i = i + 1
1875 end
1876
1877 return {fillUnits=fillUnits, consumers=consumers}
1878end

loadSpecValueMaxSpeed

Description
Definition
loadSpecValueMaxSpeed()
Code
1938function Motorized.loadSpecValueMaxSpeed(xmlFile, customEnvironment)
1939 local motorKey = nil
1940 if hasXMLProperty(xmlFile, "vehicle.motorized.motorConfigurations.motorConfiguration(0)") then
1941 motorKey = "vehicle.motorized.motorConfigurations.motorConfiguration(0).motor"
1942 elseif hasXMLProperty(xmlFile, "vehicle.motor") then
1943 motorKey = "vehicle.motor"
1944 end
1945 if motorKey ~= nil then
1946 local maxRpm = Utils.getNoNil(getXMLFloat(xmlFile, motorKey.."#maxRpm"), 1800)
1947 local forwardGearRatio = Utils.getNoNil(getXMLFloat(xmlFile, motorKey.."#forwardGearRatio"), 2)
1948 local minForwardGearRatio = Utils.getNoNil(getXMLFloat(xmlFile, motorKey.."#minForwardGearRatio"), nil)
1949 local calculatedMaxSpeed = math.ceil(VehicleMotor.calculatePhysicalMaximumSpeed(minForwardGearRatio, {forwardGearRatio}, maxRpm)*3.6)
1950 local storeDataMaxSpeed = getXMLInt(xmlFile, "vehicle.storeData.specs.maxSpeed")
1951 local maxSpeed = getXMLInt(xmlFile, "vehicle.motorized.motorConfigurations.motorConfiguration(0)#maxSpeed")
1952 local maxForwardSpeed = getXMLInt(xmlFile, motorKey.."#maxForwardSpeed")
1953
1954 if storeDataMaxSpeed ~= nil then
1955 return storeDataMaxSpeed
1956 elseif maxSpeed ~= nil then
1957 return maxSpeed
1958 elseif maxForwardSpeed ~= nil then
1959 return math.min(maxForwardSpeed, calculatedMaxSpeed)
1960 else
1961 return calculatedMaxSpeed
1962 end
1963 end
1964 return nil
1965end

loadSpecValuePower

Description
Definition
loadSpecValuePower()
Code
1986function Motorized.loadSpecValuePower(xmlFile, customEnvironment)
1987 return getXMLInt(xmlFile, "vehicle.storeData.specs.power")
1988end

onAIEnd

Description
Definition
onAIEnd()
Code
1727function Motorized:onAIEnd()
1728 if self.getIsControlled ~= nil then
1729 if not self:getIsControlled() then
1730 self:stopMotor(true)
1731 end
1732 end
1733end

onDelete

Description
Definition
onDelete()
Code
257function Motorized:onDelete()
258 local spec = self.spec_motorized
259
260 if self.isClient then
261 if spec.exhaustEffects ~= nil then
262 for _, effect in pairs(spec.exhaustEffects) do
263 g_i3DManager:releaseSharedI3DFile(effect.filename, self.baseDirectory, true)
264 end
265 end
266 ParticleUtil.deleteParticleSystems(spec.exhaustParticleSystems)
267
268 g_soundManager:deleteSamples(spec.samples)
269 g_soundManager:deleteSamples(spec.motorSamples)
270 g_animationManager:deleteAnimations(spec.animationNodes)
271 end
272end

onDraw

Description
Called on draw
Definition
onDraw(boolean isActiveForInput, boolean isSelected)
Arguments
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
675function Motorized:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
676 local spec = self.spec_motorized
677 if spec.showTurnOnMotorWarning then
678 g_currentMission:showBlinkingWarning(g_i18n:getText("warning_motorNotStarted"), 2000)
679 end
680end

onEnterVehicle

Description
Called on enter vehicle
Definition
onEnterVehicle(boolean isControlling)
Arguments
booleanisControllingis player controlling the vehicle
Code
1682function Motorized:onEnterVehicle(isControlling)
1683 if g_currentMission.missionInfo.automaticMotorStartEnabled then
1684 if self:getCanMotorRun() then
1685 self:startMotor(true)
1686 end
1687 end
1688
1689 --release sound of hand brake
1690 local samples = self.spec_motorized.samples
1691 if samples.compressedAir ~= nil then
1692 g_soundManager:playSample(samples.compressedAir, math.random(500, 2000))
1693 end
1694end

onFillUnitFillLevelChanged

Description
Definition
onFillUnitFillLevelChanged()
Code
1713function Motorized:onFillUnitFillLevelChanged(fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta)
1714 -- refill def if diesel is refilled
1715 if fillLevelDelta > 0 and fillType == FillType.DIESEL then
1716 local factor = self:getFillUnitFillLevel(fillUnitIndex) / self:getFillUnitCapacity(fillUnitIndex)
1717 local defFillUnitIndex = self:getConsumerFillUnitIndex(FillType.DEF)
1718 if defFillUnitIndex ~= nil then
1719 local delta = (self:getFillUnitCapacity(defFillUnitIndex) * factor) - self:getFillUnitFillLevel(defFillUnitIndex)
1720 self:addFillUnitFillLevel(self:getOwnerFarmId(), defFillUnitIndex, delta, FillType.DEF, ToolType.UNDEFINED, nil)
1721 end
1722 end
1723end

onLeaveVehicle

Description
Called on leaving the vehicle
Definition
onLeaveVehicle()
Code
1698function Motorized:onLeaveVehicle()
1699 local spec = self.spec_motorized
1700 if self:getStopMotorOnLeave() and g_currentMission.missionInfo.automaticMotorStartEnabled then
1701 self:stopMotor(true)
1702 end
1703
1704 if self.isServer then
1705 if spec.motorizedNode ~= nil then
1706 controlVehicle(spec.motorizedNode, 0.0, 0.0, 0.0, 0.0, math.huge, 0.0, 0.0, 0.0, 0.0, 0.0)
1707 end
1708 end
1709end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
111function Motorized:onLoad(savegame)
112 local spec = self.spec_motorized
113
114 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.turnedOnRotationNodes.turnedOnRotationNode#type", "vehicle.motor.animationNodes.animationNode", "motor") --FS17 to FS19
115 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.differentialConfigurations", "vehicle.motorized.differentialConfigurations") --FS17 to FS19
116 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.motorConfigurations", "vehicle.motorized.motorConfigurations") --FS17 to FS19
117 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.fuelCapacity", "vehicle.fillUnit") --FS17 to FS19
118 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.maximalAirConsumptionPerFullStop", "vehicle.motorized.consumerConfigurations.consumerConfiguration.consumer(with fill type 'air')#usage (is now in usage per second at full brake power)") --FS17 to FS19
119 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.rpm", "vehicle.motorized.dashboards.dashboard with valueType 'rpm'") --FS17 to FS19
120 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.speed", "vehicle.motorized.dashboards.dashboard with valueType 'speed'") --FS17 to FS19
121 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.fuelUsage", "vehicle.motorized.dashboards.dashboard with valueType 'fuelUsage'") --FS17 to FS19
122 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.fuel", "fillUnit.dashboard with valueType 'fillLevel'") --FS17 to FS19
123
124 spec.motorizedNode = nil
125 for _, component in pairs(self.components) do
126 if component.motorized then
127 spec.motorizedNode = component.node
128 break
129 end
130 end
131
132 self:loadDifferentials(self.xmlFile, self.differentialIndex)
133 self:loadMotor(self.xmlFile, self.configurations["motor"])
134 self:loadSounds(self.xmlFile, self.configurations["motor"])
135
136 self:loadConsumerConfiguration(self.xmlFile, spec.consumerConfigurationIndex)
137
138 if self.isClient then
139 self:loadExhaustEffects(self.xmlFile)
140 end
141
142 spec.stopMotorOnLeave = true
143
144 spec.motorStartDuration = 0
145 if spec.samples ~= nil and spec.samples.motorStart ~= nil then
146 spec.motorStartDuration = spec.samples.motorStart.duration
147 end
148 spec.motorStartDuration = Utils.getNoNil(Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.motorized.motorStartDuration"), spec.motorStartDuration), 0)
149 spec.consumersEmptyWarning = g_i18n:getText(Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.motorized#consumersEmptyWarning"), "warning_motorFuelEmpty"), self.customEnvironment)
150
151 spec.turnOnText = g_i18n:getText(Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.motorized#turnOnText"), "action_startMotor"), self.customEnvironment)
152 spec.turnOffText = g_i18n:getText(Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.motorized#turnOffText"), "action_stopMotor"), self.customEnvironment)
153
154 spec.speedDisplayScale = 1
155 spec.motorStartTime = 0
156 spec.lastRoundPerMinute = 0
157 spec.actualLoadPercentage = 0
158 spec.smoothedLoadPercentage = 0
159 spec.maxDecelerationDuringBrake = 0
160 spec.showTurnOnMotorWarning = 0
161
162 spec.isMotorStarted = false
163 spec.motorStopTimerDuration = g_gameSettings:getValue("motorStopTimerDuration")
164 spec.motorStopTimer = spec.motorStopTimerDuration
165
166 spec.motorTemperature = {}
167 spec.motorTemperature.value = 20
168 spec.motorTemperature.valueSend = 20
169 spec.motorTemperature.valueMax = 120
170 spec.motorTemperature.valueMin = 20
171 spec.motorTemperature.heatingPerMS = 1.5 / 1000 -- delta °C per ms, at full load
172 spec.motorTemperature.coolingByWindPerMS = 1.00 / 1000
173
174 spec.motorFan = {}
175 spec.motorFan.enabled = false
176 spec.motorFan.enableTemperature = 95
177 spec.motorFan.disableTemperature = 85
178 spec.motorFan.coolingPerMS = 3.0 / 1000
179
180 spec.lastFuelUsage = 0
181 spec.lastFuelUsageDisplay = 0
182 spec.lastFuelUsageDisplayTime = 0
183 spec.fuelUsageBuffer = ValueBuffer:new(250)
184 spec.lastDefUsage = 0
185 spec.lastAirUsage = 0
186 spec.lastVehicleDamage = 0
187
188 if self.loadDashboardsFromXML ~= nil then
189 self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "rpm",
190 valueObject = spec.motor,
191 valueFunc = "getEqualizedMotorRpm",
192 minFunc = 0,
193 maxFunc = "getMaxRpm"})
194
195 self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "speed",
196 valueObject = self,
197 valueFunc = "getLastSpeed",
198 minFunc = 0,
199 maxFunc = self:getMotor():getMaximumForwardSpeed()*3.6})
200
201 self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "speedDir",
202 valueObject = self,
203 valueFunc = Motorized.getDashboardSpeedDir,
204 minFunc = -self:getMotor():getMaximumBackwardSpeed()*3.6,
205 maxFunc = self:getMotor():getMaximumForwardSpeed()*3.6,
206 centerFunc = 0})
207
208 self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "fuelUsage",
209 valueObject = spec,
210 valueFunc = "lastFuelUsageDisplay"})
211
212 self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "motorTemperature",
213 valueObject = spec.motorTemperature,
214 valueFunc = "value",
215 minFunc = "valueMin",
216 maxFunc = "valueMax"})
217
218 self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "motorTemperatureWarning",
219 valueObject = spec.motorTemperature,
220 valueFunc = "value",
221 additionalAttributesFunc = Dashboard.warningAttributes,
222 stateFunc = Dashboard.warningState})
223 end
224
225 spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.motorized.animationNodes", self.components, self, self.i3dMappings)
226end

onPostLoad

Description
Definition
onPostLoad()
Code
230function Motorized:onPostLoad(savegame)
231 local spec = self.spec_motorized
232 if self.isServer then
233 -- refill the consumers
234 local moneyChange = 0
235 for _, consumer in pairs(spec.consumersByFillTypeName) do
236 local fillLevel = self:getFillUnitFillLevel(consumer.fillUnitIndex)
237 local minFillLevel = self:getFillUnitCapacity(consumer.fillUnitIndex) * 0.1
238 if fillLevel < minFillLevel then
239 local fillLevelToFill = minFillLevel - fillLevel
240 self:addFillUnitFillLevel(self:getOwnerFarmId(), consumer.fillUnitIndex, fillLevelToFill, consumer.fillType, ToolType.UNDEFINED)
241
242 local costs = fillLevelToFill * g_currentMission.economyManager:getPricePerLiter(consumer.fillType) * 2.0
243 g_currentMission:farmStats(self:getOwnerFarmId()):updateStats("expenses", costs);
244 g_currentMission:addMoney(-costs, self:getOwnerFarmId(), MoneyType.PURCHASE_FUEL);
245 moneyChange = moneyChange + costs
246 end
247 end
248
249 if moneyChange > 0 then
250 g_currentMission:addMoneyChange(-moneyChange, self:getOwnerFarmId(), MoneyType.PURCHASE_FUEL, true)
251 end
252 end
253end

onReadStream

Description
Definition
onReadStream()
Code
276function Motorized:onReadStream(streamId, connection)
277 local isMotorStarted = streamReadBool(streamId)
278 if isMotorStarted then
279 self:startMotor(true)
280 else
281 self:stopMotor(true)
282 end
283end

onReadUpdateStream

Description
Definition
onReadUpdateStream()
Code
293function Motorized:onReadUpdateStream(streamId, timestamp, connection)
294 if connection.isServer then
295 local spec = self.spec_motorized
296
297 if streamReadBool(streamId) then
298 local rpm = streamReadUIntN(streamId, 11) / 2047
299 local rpmRange = spec.motor:getMaxRpm()- spec.motor:getMinRpm()
300 spec.motor:setEqualizedMotorRpm( (rpm * rpmRange) + spec.motor:getMinRpm() )
301
302 local loadPercentage = streamReadUIntN(streamId, 7)
303 spec.actualLoadPercentage = loadPercentage / 127
304 spec.smoothedLoadPercentage = 0.95 * spec.smoothedLoadPercentage + 0.05 * spec.actualLoadPercentage
305
306 spec.brakeCompressor.doFill = streamReadBool(streamId)
307 end
308 end
309end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
1634function Motorized:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
1635 if self.isClient then
1636 local spec = self.spec_motorized
1637 self:clearActionEventsTable(spec.actionEvents)
1638
1639 if isActiveForInputIgnoreSelection then
1640 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_MOTOR_STATE, self, Motorized.actionEventToggleMotorState, false, true, false, true, nil)
1641 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH)
1642 g_inputBinding:setActionEventText(actionEventId, spec.turnOnText)
1643
1644 --[[if spec.motor.minForwardGearRatio == nil or spec.motor.minBackwardGearRatio == nil then
1645 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_UP, self, Motorized.actionEventShiftGear, false, true, false, true, nil)
1646 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH)
1647 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_DOWN, self, Motorized.actionEventShiftGear, false, true, false, true, nil)
1648 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH)
1649 end]]
1650 end
1651 end
1652end

onSetBroken

Description
Definition
onSetBroken()
Code
1737function Motorized:onSetBroken()
1738 self:stopMotor(true)
1739end

onUpdate

Description
Called on update
Definition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
333function Motorized:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
334 local spec = self.spec_motorized
335
336 local accInput = 0
337 if self.getAxisForward ~= nil then
338 accInput = self:getAxisForward()
339 end
340
341 if self:getIsMotorStarted() then
342 spec.motor:update(dt)
343 if self.getCruiseControlState ~= nil then
344 if self:getCruiseControlState() ~= Drivable.CRUISECONTROL_STATE_OFF then
345 accInput = 1
346 end
347 end
348
349 if self.isServer then
350 self:updateConsumers(dt, accInput)
351
352 -- update motor properties on damage change to update the torque reduction
353 local damage = self:getVehicleDamage()
354 if math.abs(damage - spec.lastVehicleDamage) > 0.05 then
355 self:updateMotorProperties()
356 spec.lastVehicleDamage = self:getVehicleDamage()
357 end
358 end
359
360 if self.isClient then
361 -- update sounds
362 local samples = spec.samples
363 if g_soundManager:getIsSamplePlaying(spec.motorSamples[1], 1.5*dt) then
364 -- air compressor fill sound
365 if samples.airCompressorStart ~= nil and samples.airCompressorStop ~= nil and samples.airCompressorRun ~= nil then
366 if spec.consumersByFillTypeName ~= nil and spec.consumersByFillTypeName.air ~= nil then
367 local consumer = spec.consumersByFillTypeName.air
368
369 if not consumer.doRefill then
370 if g_soundManager:getIsSamplePlaying(samples.airCompressorRun) then
371 g_soundManager:stopSample(samples.airCompressorRun)
372 g_soundManager:playSample(samples.airCompressorStop)
373 end
374 else
375 if not g_soundManager:getIsSamplePlaying(samples.airCompressorRun) then
376 if not g_soundManager:getIsSamplePlaying(samples.airCompressorStart, 1.5*dt) and spec.brakeCompressor.playSampleRunTime == nil then
377 g_soundManager:playSample(samples.airCompressorStart)
378 spec.playSampleRunTime = g_currentMission.time + samples.airCompressorStart.duration
379 end
380 if not g_soundManager:getIsSamplePlaying(samples.airCompressorStart) then
381 spec.brakeCompressor.playSampleRunTime = nil
382 g_soundManager:stopSample(samples.airCompressorStart)
383 g_soundManager:playSample(samples.airCompressorRun)
384 end
385 end
386 end
387 end
388 end
389
390 -- random zsch sound
391 if spec.compressionSoundTime <= g_currentMission.time then
392 g_soundManager:playSample(samples.airRelease)
393 spec.compressionSoundTime = g_currentMission.time + math.random(10000, 40000)
394 end
395
396 local isBraking = self:getDecelerationAxis() > 0 and self:getLastSpeed() > 1
397
398 -- brake zsch sound
399 if samples.compressedAir ~= nil then
400 if isBraking then
401 samples.compressedAir.brakeTime = samples.compressedAir.brakeTime + dt
402 else
403 if samples.compressedAir.brakeTime > 0 then
404 samples.compressedAir.lastBrakeTime = samples.compressedAir.brakeTime
405 samples.compressedAir.brakeTime = 0
406
407 g_soundManager:playSample(samples.compressedAir)
408 end
409 end
410 end
411
412 --brake sound
413 if samples.brake ~= nil then
414 if isBraking then
415 if not spec.isBrakeSamplePlaying then
416 g_soundManager:playSample(samples.brake)
417 spec.isBrakeSamplePlaying = true
418 end
419 else
420 if spec.isBrakeSamplePlaying then
421 g_soundManager:stopSample(samples.brake)
422 spec.isBrakeSamplePlaying = false
423 end
424 end
425 end
426
427 -- reverse driving beep
428 if samples.reverseDrive ~= nil then
429 if (self.getIsControlled ~= nil and self:getIsControlled()) or self:getIsAIActive() then
430 local reverserDirection = self.getReverserDirection == nil and 1 or self:getReverserDirection()
431 local isReverseDriving = self:getLastSpeed() > spec.reverseDriveThreshold and self.movingDirection ~= reverserDirection
432 if not g_soundManager:getIsSamplePlaying(samples.reverseDrive) and isReverseDriving then
433 g_soundManager:playSample(samples.reverseDrive)
434 elseif not isReverseDriving then
435 g_soundManager:stopSample(samples.reverseDrive)
436 end
437 else
438 g_soundManager:stopSample(samples.reverseDrive)
439 end
440 end
441 end
442 end
443
444 if self.isServer then
445 if not self:getIsAIActive() and self:getTravedDistanceStatsActive() then
446 if self.lastMovedDistance > 0.001 then
447 g_currentMission:farmStats(self:getOwnerFarmId()):updateStats("traveledDistance", self.lastMovedDistance*0.001)
448 end
449 end
450 end
451
452 spec.showTurnOnMotorWarning = false
453 else
454 if self:getCanMotorRun() then
455 spec.showTurnOnMotorWarning = accInput ~= 0
456 end
457 end
458end

onUpdateTick

Description
Called on update tick
Definition
onUpdateTick(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
465function Motorized:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
466 local spec = self.spec_motorized
467
468 if self.isServer then
469 -- motor load
470 local loadPercentage = spec.motor:getMotorAppliedTorque() / math.max(spec.motor:getMotorAvailableTorque(), 0.0001)
471
472 spec.actualLoadPercentage = loadPercentage
473 if spec.actualLoadPercentage > spec.smoothedLoadPercentage then
474 spec.smoothedLoadPercentage = 0.95*spec.smoothedLoadPercentage + 0.05*loadPercentage
475 else
476 spec.smoothedLoadPercentage = 0.98*spec.smoothedLoadPercentage + 0.02*loadPercentage
477 end
478
479 -- force stop of motor if player is far away from vehicle for a certain amount of time
480 if not g_currentMission.missionInfo.automaticMotorStartEnabled then
481 if spec.isMotorStarted and not self:getIsAIActive() then
482
483 local isEntered = self.getIsEntered ~= nil and self:getIsEntered()
484 local isControlled = self.getIsControlled ~= nil and self:getIsControlled()
485
486 if not isEntered and not isControlled then
487
488 local isPlayerInRange = false
489
490 for _, player in pairs(g_currentMission.players) do
491 if player.isControlled then
492 local distance = calcDistanceFrom(self.rootNode, player.rootNode)
493 if distance < 250 then
494 isPlayerInRange = true
495 break
496 end
497 end
498 end
499 if not isPlayerInRange then
500 for _, enterable in pairs(g_currentMission.enterables) do
501 if enterable.spec_enterable ~= nil and enterable.spec_enterable.isControlled then
502 local distance = calcDistanceFrom(self.rootNode, enterable.rootNode)
503 if distance < 250 then
504 isPlayerInRange = true
505 break
506 end
507 end
508 end
509 end
510
511 if isPlayerInRange then
512 spec.motorStopTimer = spec.motorStopTimerDuration
513 else
514 spec.motorStopTimer = spec.motorStopTimer - dt
515 if spec.motorStopTimer <= 0 then
516 self:stopMotor()
517 end
518 end
519
520 end
521 end
522 end
523
524 if spec.isMotorStarted then
525 self:updateMotorTemperature(dt)
526 else
527 --start motor if fuel was empty and got filled
528 --also starts the motor again when we toggle the automatic motoro start option
529 if g_currentMission.missionInfo.automaticMotorStartEnabled then
530 if self.getIsControlled ~= nil and self:getIsControlled() then
531 if self:getCanMotorRun() then
532 self:startMotor(true)
533 end
534 end
535 end
536 end
537 end
538
539 if self.isClient then
540 if self:getIsMotorStarted() then
541 if spec.exhaustParticleSystems ~= nil then
542 for _, ps in pairs(spec.exhaustParticleSystems) do
543 local scale = MathUtil.lerp(spec.exhaustParticleSystems.minScale, spec.exhaustParticleSystems.maxScale, spec.motor:getEqualizedMotorRpm() / spec.motor:getMaxRpm())
544 ParticleUtil.setEmitCountScale(spec.exhaustParticleSystems, scale)
545 ParticleUtil.setParticleLifespan(ps, ps.originalLifespan * scale)
546 end
547 end
548
549 if spec.exhaustFlap ~= nil then
550 local minRandom = -0.1
551 local maxRandom = 0.1
552 local angle = MathUtil.lerp(minRandom, maxRandom, math.random()) + spec.exhaustFlap.maxRot * (spec.motor:getEqualizedMotorRpm() / spec.motor:getMaxRpm())
553 angle = MathUtil.clamp(angle, 0, spec.exhaustFlap.maxRot)
554 setRotation(spec.exhaustFlap.node, angle, 0, 0)
555 end
556
557 if spec.exhaustEffects ~= nil then
558 local lastSpeed = self:getLastSpeed()
559
560 spec.currentDirection = {localDirectionToWorld(self.rootNode, 0, 0, 1)}
561 if spec.lastDirection == nil then
562 spec.lastDirection = spec.currentDirection
563 end
564
565 local x,_,z = worldDirectionToLocal(self.rootNode, spec.lastDirection[1], spec.lastDirection[2], spec.lastDirection[3])
566 local dot = z
567 dot = dot / MathUtil.vector2Length(x,z)
568 local angle = math.acos(dot)
569 if x < 0 then
570 angle = -angle
571 end
572 local steeringPercent = math.abs((angle / dt) / spec.exhaustEffectMaxSteeringSpeed)
573 spec.lastDirection = spec.currentDirection
574
575 for _, effect in pairs(spec.exhaustEffects) do
576 local rpmScale = spec.motor:getEqualizedMotorRpm() / spec.motor:getMaxRpm()
577 local scale = MathUtil.lerp(effect.minRpmScale, effect.maxRpmScale, rpmScale)
578 local forwardXRot = 0
579 local forwardZRot = 0
580 local steerXRot = 0
581 local steerZRot = 0
582
583 local r = MathUtil.lerp(effect.minRpmColor[1], effect.maxRpmColor[1], rpmScale)
584 local g = MathUtil.lerp(effect.minRpmColor[2], effect.maxRpmColor[2], rpmScale)
585 local b = MathUtil.lerp(effect.minRpmColor[3], effect.maxRpmColor[3], rpmScale)
586 local a = MathUtil.lerp(effect.minRpmColor[4], effect.maxRpmColor[4], rpmScale)
587 setShaderParameter(effect.effectNode, "exhaustColor", r, g, b, a, false)
588
589 -- speed rotation
590 if self.movingDirection == 1 then
591 local percent = MathUtil.clamp(lastSpeed/effect.maxForwardSpeed, 0, 1)
592 forwardXRot = effect.xzRotationsForward[1] * percent
593 forwardZRot = effect.xzRotationsForward[2] * percent
594 elseif self.movingDirection == -1 then
595 local percent = MathUtil.clamp(lastSpeed/effect.maxBackwardSpeed, 0, 1)
596 forwardXRot = effect.xzRotationsBackward[1] * percent
597 forwardZRot = effect.xzRotationsBackward[2] * percent
598 end
599
600 -- steering rotation
601 if angle > 0 then
602 steerXRot = effect.xzRotationsRight[1] * steeringPercent
603 steerZRot = effect.xzRotationsRight[2] * steeringPercent
604 elseif angle < 0 then
605 steerXRot = effect.xzRotationsLeft[1] * steeringPercent
606 steerZRot = effect.xzRotationsLeft[2] * steeringPercent
607 end
608 -- target rotations
609 local targetXRot = effect.xzRotationsOffset[1] + forwardXRot + steerXRot
610 local targetZRot = effect.xzRotationsOffset[2] + forwardZRot + steerZRot
611
612 -- damping
613 if targetXRot > effect.xRot then
614 effect.xRot = math.min(effect.xRot + 0.003*dt, targetXRot)
615 else
616 effect.xRot = math.max(effect.xRot - 0.003*dt, targetXRot)
617 end
618 if targetZRot > effect.xRot then
619 effect.zRot = math.min(effect.zRot + 0.003*dt, targetZRot)
620 else
621 effect.zRot = math.max(effect.zRot - 0.003*dt, targetZRot)
622 end
623 setShaderParameter(effect.effectNode, "param", effect.xRot, effect.zRot, 0, scale, false)
624 end
625 end
626
627 spec.lastFuelUsageDisplayTime = spec.lastFuelUsageDisplayTime + dt
628 if spec.lastFuelUsageDisplayTime > 250 then
629 spec.lastFuelUsageDisplayTime = 0
630 spec.lastFuelUsageDisplay = spec.fuelUsageBuffer:getAverage()
631 end
632
633 spec.fuelUsageBuffer:add(spec.lastFuelUsage)
634 end
635
636 -- display permanent fuel empty warning if automatic motor start is enabled
637 if isActiveForInputIgnoreSelection then
638 if g_currentMission.missionInfo.automaticMotorStartEnabled then
639 if not self:getCanMotorRun() then
640 local warning = self:getMotorNotAllowedWarning()
641 if warning ~= nil then
642 g_currentMission:showBlinkingWarning(warning, 2000)
643 end
644 end
645 end
646
647 -- hide / show start motor input action if setting is changed on the fly
648 local actionEvent = spec.actionEvents[InputAction.TOGGLE_MOTOR_STATE]
649 if actionEvent ~= nil then
650 if not g_currentMission.missionInfo.automaticMotorStartEnabled then
651 local text
652
653 g_inputBinding:setActionEventActive(actionEvent.actionEventId, true)
654 if self:getIsMotorStarted() then
655 g_inputBinding:setActionEventTextPriority(actionEvent.actionEventId, GS_PRIO_VERY_LOW)
656 text = spec.turnOffText
657 else
658 g_inputBinding:setActionEventTextPriority(actionEvent.actionEventId, GS_PRIO_VERY_HIGH)
659 text = spec.turnOnText
660 end
661
662 g_inputBinding:setActionEventText(actionEvent.actionEventId, text)
663 else
664 g_inputBinding:setActionEventActive(actionEvent.actionEventId, false)
665 end
666 end
667 end
668 end
669end

onWriteStream

Description
Definition
onWriteStream()
Code
287function Motorized:onWriteStream(streamId, connection)
288 streamWriteBool(streamId, self.spec_motorized.isMotorStarted)
289end

onWriteUpdateStream

Description
Definition
onWriteUpdateStream()
Code
313function Motorized:onWriteUpdateStream(streamId, connection, dirtyMask)
314 if not connection.isServer then
315 local spec = self.spec_motorized
316 if streamWriteBool(streamId, self.spec_motorized.isMotorStarted) then
317 local rpmRange = spec.motor:getMaxRpm() - spec.motor:getMinRpm()
318 local rpm = MathUtil.clamp((spec.motor:getEqualizedMotorRpm() - spec.motor:getMinRpm()) / rpmRange, 0, 1)
319
320 rpm = math.floor(rpm * 2047)
321 streamWriteUIntN(streamId, rpm, 11)
322 streamWriteUIntN(streamId, 127 * spec.actualLoadPercentage, 7)
323 streamWriteBool(streamId, spec.brakeCompressor.doFill)
324 end
325 end
326end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
31function Motorized.prerequisitesPresent(specializations)
32 return SpecializationUtil.hasSpecialization(FillUnit, specializations)
33end

registerEventListeners

Description
Definition
registerEventListeners()
Code
89function Motorized.registerEventListeners(vehicleType)
90 SpecializationUtil.registerEventListener(vehicleType, "onLoad", Motorized)
91 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Motorized)
92 SpecializationUtil.registerEventListener(vehicleType, "onDelete", Motorized)
93 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Motorized)
94 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Motorized)
95 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Motorized)
96 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Motorized)
97 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Motorized)
98 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Motorized)
99 SpecializationUtil.registerEventListener(vehicleType, "onDraw", Motorized)
100 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Motorized)
101 SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", Motorized)
102 SpecializationUtil.registerEventListener(vehicleType, "onEnterVehicle", Motorized)
103 SpecializationUtil.registerEventListener(vehicleType, "onFillUnitFillLevelChanged", Motorized)
104 SpecializationUtil.registerEventListener(vehicleType, "onAIEnd", Motorized)
105 SpecializationUtil.registerEventListener(vehicleType, "onSetBroken", Motorized)
106end

registerEvents

Description
Definition
registerEvents()
Code
37function Motorized.registerEvents(vehicleType)
38 SpecializationUtil.registerEvent(vehicleType, "onStartMotor")
39 SpecializationUtil.registerEvent(vehicleType, "onStopMotor")
40end

registerFunctions

Description
Definition
registerFunctions()
Code
44function Motorized.registerFunctions(vehicleType)
45 SpecializationUtil.registerFunction(vehicleType, "loadDifferentials", Motorized.loadDifferentials)
46 SpecializationUtil.registerFunction(vehicleType, "loadMotor", Motorized.loadMotor)
47 SpecializationUtil.registerFunction(vehicleType, "loadGears", Motorized.loadGears)
48 SpecializationUtil.registerFunction(vehicleType, "loadExhaustEffects", Motorized.loadExhaustEffects)
49 SpecializationUtil.registerFunction(vehicleType, "loadSounds", Motorized.loadSounds)
50 SpecializationUtil.registerFunction(vehicleType, "loadConsumerConfiguration", Motorized.loadConsumerConfiguration)
51 SpecializationUtil.registerFunction(vehicleType, "getIsMotorStarted", Motorized.getIsMotorStarted)
52 SpecializationUtil.registerFunction(vehicleType, "getCanMotorRun", Motorized.getCanMotorRun)
53 SpecializationUtil.registerFunction(vehicleType, "getStopMotorOnLeave", Motorized.getStopMotorOnLeave)
54 SpecializationUtil.registerFunction(vehicleType, "getMotorNotAllowedWarning", Motorized.getMotorNotAllowedWarning)
55 SpecializationUtil.registerFunction(vehicleType, "startMotor", Motorized.startMotor)
56 SpecializationUtil.registerFunction(vehicleType, "stopMotor", Motorized.stopMotor)
57 SpecializationUtil.registerFunction(vehicleType, "updateMotorProperties", Motorized.updateMotorProperties)
58 SpecializationUtil.registerFunction(vehicleType, "updateConsumers", Motorized.updateConsumers)
59 SpecializationUtil.registerFunction(vehicleType, "updateMotorTemperature", Motorized.updateMotorTemperature)
60 SpecializationUtil.registerFunction(vehicleType, "getMotor", Motorized.getMotor)
61 SpecializationUtil.registerFunction(vehicleType, "getMotorStartTime", Motorized.getMotorStartTime)
62 SpecializationUtil.registerFunction(vehicleType, "getMotorType", Motorized.getMotorType)
63 SpecializationUtil.registerFunction(vehicleType, "getMotorRpmPercentage", Motorized.getMotorRpmPercentage)
64 SpecializationUtil.registerFunction(vehicleType, "getMotorLoadPercentage", Motorized.getMotorLoadPercentage)
65 SpecializationUtil.registerFunction(vehicleType, "getConsumerFillUnitIndex", Motorized.getConsumerFillUnitIndex)
66 SpecializationUtil.registerFunction(vehicleType, "getAirConsumerUsage", Motorized.getAirConsumerUsage)
67 SpecializationUtil.registerFunction(vehicleType, "getTravedDistanceStatsActive", Motorized.getTravedDistanceStatsActive)
68end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
72function Motorized.registerOverwrittenFunctions(vehicleType)
73 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getBrakeForce", Motorized.getBrakeForce)
74 SpecializationUtil.registerOverwrittenFunction(vehicleType, "addToPhysics", Motorized.addToPhysics)
75 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsOperating", Motorized.getIsOperating)
76 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDeactivateOnLeave", Motorized.getDeactivateOnLeave)
77 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDeactivateLightsOnLeave", Motorized.getDeactivateLightsOnLeave)
78 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanStartAIVehicle", Motorized.getCanStartAIVehicle)
79 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadDashboardGroupFromXML", Motorized.loadDashboardGroupFromXML)
80 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsDashboardGroupActive", Motorized.getIsDashboardGroupActive)
81 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsActiveForInteriorLights", Motorized.getIsActiveForInteriorLights)
82 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsActiveForWipers", Motorized.getIsActiveForWipers)
83 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getName", Motorized.getName)
84 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", Motorized.getCanBeSelected)
85end

startMotor

Description
Start motor
Definition
startMotor(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
1166function Motorized:startMotor(noEventSend)
1167 if noEventSend == nil or noEventSend == false then
1168 if g_server ~= nil then
1169 g_server:broadcastEvent(SetMotorTurnedOnEvent:new(self, true), nil, nil, self)
1170 else
1171 g_client:getServerConnection():sendEvent(SetMotorTurnedOnEvent:new(self, true))
1172 end
1173 end
1174 local spec = self.spec_motorized
1175 if not spec.isMotorStarted then
1176 spec.isMotorStarted = true
1177
1178 if self.isClient then
1179 if spec.exhaustParticleSystems ~= nil then
1180 for _, ps in pairs(spec.exhaustParticleSystems) do
1181 ParticleUtil.setEmittingState(ps, true)
1182 end
1183 end
1184 if spec.exhaustEffects ~= nil then
1185 for _, effect in pairs(spec.exhaustEffects) do
1186 setVisibility(effect.effectNode, true)
1187 effect.xRot = effect.xzRotationsOffset[1]
1188 effect.zRot = effect.xzRotationsOffset[2]
1189 setShaderParameter(effect.effectNode, "param", effect.xRot, effect.zRot, 0, 0, false)
1190
1191 local color = effect.minRpmColor
1192 setShaderParameter(effect.effectNode, "exhaustColor", color[1], color[2], color[3], color[4], false)
1193 end
1194 end
1195
1196 g_soundManager:stopSample(spec.samples.motorStop)
1197
1198 g_soundManager:playSample(spec.samples.motorStart)
1199 g_soundManager:playSamples(spec.motorSamples, 0, spec.samples.motorStart)
1200 g_soundManager:playSample(spec.samples.gearbox, 0, spec.samples.motorStart)
1201 g_soundManager:playSample(spec.samples.retarder, 0, spec.samples.motorStart)
1202
1203 g_animationManager:startAnimations(spec.animationNodes)
1204
1205 if spec.motorStartAnimation ~= nil then
1206 self:playAnimation(spec.motorStartAnimation, 1, nil, true)
1207 end
1208 end
1209
1210 spec.motorStartTime = g_currentMission.time + spec.motorStartDuration
1211 spec.compressionSoundTime = g_currentMission.time + math.random(5000, 20000)
1212 spec.lastRoundPerMinute = 0
1213
1214 SpecializationUtil.raiseEvent(self, "onStartMotor")
1215 self:getRootVehicle():raiseStateChange(Vehicle.STATE_CHANGE_MOTOR_TURN_ON)
1216 end
1217
1218 if self.setDashboardsDirty ~= nil then
1219 self:setDashboardsDirty()
1220 end
1221
1222end

stopMotor

Description
Stop motor
Definition
stopMotor(boolean noEventSend)
Arguments
booleannoEventSendno event send
Code
1227function Motorized:stopMotor(noEventSend)
1228 if noEventSend == nil or noEventSend == false then
1229 if g_server ~= nil then
1230 g_server:broadcastEvent(SetMotorTurnedOnEvent:new(self, false), nil, nil, self)
1231 else
1232 g_client:getServerConnection():sendEvent(SetMotorTurnedOnEvent:new(self, false))
1233 end
1234 end
1235
1236 local spec = self.spec_motorized
1237 if spec.isMotorStarted then
1238 spec.isMotorStarted = false
1239
1240 if self.isClient then
1241 if spec.exhaustParticleSystems ~= nil then
1242 for _, ps in pairs(spec.exhaustParticleSystems) do
1243 ParticleUtil.setEmittingState(ps, false)
1244 end
1245 end
1246
1247 if spec.exhaustEffects ~= nil then
1248 for _, effect in pairs(spec.exhaustEffects) do
1249 setVisibility(effect.effectNode, false)
1250 end
1251 end
1252 if spec.exhaustFlap ~= nil then
1253 setRotation(spec.exhaustFlap.node, 0, 0, 0)
1254 end
1255
1256 g_soundManager:stopSample(spec.samples.motorStart)
1257 g_soundManager:playSample(spec.samples.motorStop)
1258 g_soundManager:stopSamples(spec.motorSamples)
1259 g_soundManager:stopSample(spec.samples.gearbox)
1260 g_soundManager:stopSample(spec.samples.retarder)
1261
1262 g_soundManager:stopSample(spec.samples.airCompressorStart)
1263 g_soundManager:stopSample(spec.samples.airCompressorStop)
1264 g_soundManager:stopSample(spec.samples.airCompressorRun)
1265
1266 g_soundManager:stopSample(spec.samples.compressedAir)
1267 g_soundManager:stopSample(spec.samples.airRelease)
1268
1269 g_soundManager:stopSample(spec.samples.reverseDrive)
1270 g_soundManager:stopSample(spec.samples.brake)
1271 spec.isBrakeSamplePlaying = false
1272
1273 g_animationManager:stopAnimations(spec.animationNodes)
1274
1275 if spec.motorStartAnimation ~= nil then
1276 self:playAnimation(spec.motorStartAnimation, -1, nil, true)
1277 end
1278 end
1279
1280 SpecializationUtil.raiseEvent(self, "onStopMotor")
1281 self:getRootVehicle():raiseStateChange(Vehicle.STATE_CHANGE_MOTOR_TURN_OFF)
1282 end
1283
1284 if self.setDashboardsDirty ~= nil then
1285 self:setDashboardsDirty()
1286 end
1287end

updateConsumers

Description
Definition
updateConsumers()
Code
1291function Motorized:updateConsumers(dt, accInput)
1292 local spec = self.spec_motorized
1293
1294 local idleFactor = 0.5
1295 local rpmPercentage = (spec.motor:getLastMotorRpm() - spec.motor:getMinRpm()) / (spec.motor:getMaxRpm() - spec.motor:getMinRpm())
1296 local rpmFactor = idleFactor + rpmPercentage * (1-idleFactor)
1297 local loadFactor = spec.smoothedLoadPercentage * rpmPercentage
1298 local motorFactor = 0.5 * ( (0.2*rpmFactor) + (1.8*loadFactor) )
1299
1300 local usageFactor = 1.0
1301 if g_currentMission.missionInfo.fuelUsageLow then
1302 usageFactor = 0.7
1303 end
1304
1305 local damage = self:getVehicleDamage()
1306 if damage > 0 then
1307 usageFactor = usageFactor * (1 + damage * Motorized.DAMAGED_USAGE_INCREASE)
1308 end
1309
1310 -- update permanent consumers
1311 for _,consumer in pairs(spec.consumers) do
1312 if consumer.permanentConsumption and consumer.usage > 0 then
1313 local used = usageFactor * motorFactor * consumer.usage * dt
1314 if used ~= 0 then
1315 local fillType = self:getFillUnitLastValidFillType(consumer.fillUnitIndex)
1316
1317 local stats = g_currentMission:farmStats(self:getOwnerFarmId())
1318 stats:updateStats("fuelUsage", used)
1319
1320 if self:getIsAIActive() then
1321 if fillType == FillType.DIESEL or fillType == FillType.DEF then
1322 if g_currentMission.missionInfo.helperBuyFuel then
1323 if fillType == FillType.DIESEL then
1324 local price = used * g_currentMission.economyManager:getPricePerLiter(fillType) * 1.5
1325 stats:updateStats("expenses", price)
1326
1327 g_currentMission:addMoney(-price, self:getOwnerFarmId(), MoneyType.PURCHASE_FUEL, true)
1328 end
1329
1330 used = 0
1331 end
1332 end
1333 end
1334
1335 if fillType == consumer.fillType then
1336 self:addFillUnitFillLevel(self:getOwnerFarmId(), consumer.fillUnitIndex, -used, fillType, ToolType.UNDEFINED)
1337 end
1338
1339 if fillType == FillType.DIESEL then
1340 spec.lastFuelUsage = used / dt * 1000 * 60 * 60 -- per hour
1341 elseif fillType == FillType.DEF then
1342 spec.lastDefUsage = used / dt * 1000 * 60 * 60 -- per hour
1343 end
1344 end
1345 end
1346 end
1347
1348 -- update air consuming
1349 if spec.consumersByFillTypeName.air ~= nil then
1350 local consumer = spec.consumersByFillTypeName.air
1351 local fillType = self:getFillUnitLastValidFillType(consumer.fillUnitIndex)
1352 if fillType == consumer.fillType then
1353 local usage = 0
1354
1355 -- consume air on brake
1356 local forwardBrake = self.movingDirection > 0 and accInput < 0
1357 local backwardBrake = self.movingDirection < 0 and accInput > 0
1358 local brakeIsPressed = self:getLastSpeed() > 1.0 and (forwardBrake or backwardBrake)
1359 if brakeIsPressed then
1360 local delta = math.abs(accInput) * dt * self:getAirConsumerUsage() / 1000
1361 self:addFillUnitFillLevel(self:getOwnerFarmId(), consumer.fillUnitIndex, -delta, consumer.fillType, ToolType.UNDEFINED)
1362
1363 usage = delta / dt * 1000 -- per sec
1364 end
1365
1366 --refill air fill unit if it is below given level
1367 local fillLevelPercentage = self:getFillUnitFillLevelPercentage(consumer.fillUnitIndex)
1368 if fillLevelPercentage < consumer.refillCapacityPercentage then
1369 consumer.doRefill = true
1370 elseif fillLevelPercentage == 1 then
1371 consumer.doRefill = false
1372 end
1373
1374 if consumer.doRefill then
1375 local delta = consumer.refillLitersPerSecond / 1000 * dt
1376 self:addFillUnitFillLevel(self:getOwnerFarmId(), consumer.fillUnitIndex, delta, consumer.fillType, ToolType.UNDEFINED)
1377
1378 usage = -delta / dt * 1000 -- per sec
1379 end
1380
1381 spec.lastAirUsage = usage
1382 end
1383 end
1384end

updateMotorProperties

Description
Update the motor properties based on script motor state
Definition
updateMotorProperties()
Code
1603function Motorized:updateMotorProperties()
1604 local spec = self.spec_motorized
1605 local motor = spec.motor
1606 local torques, rotationSpeeds = motor:getTorqueAndSpeedValues()
1607
1608 setMotorProperties(spec.motorizedNode, motor:getMinRpm()*math.pi/30, motor:getMaxRpm()*math.pi/30, motor:getRotInertia(), motor:getDampingRateFullThrottle(), motor:getDampingRateZeroThrottleClutchEngaged(), motor:getDampingRateZeroThrottleClutchDisengaged(), rotationSpeeds, torques)
1609end

updateMotorTemperature

Description
Definition
updateMotorTemperature()
Code
1388function Motorized:updateMotorTemperature(dt)
1389 local spec = self.spec_motorized
1390
1391 local delta = spec.motorTemperature.heatingPerMS * dt
1392 local factor = (1 + 4*spec.actualLoadPercentage) / 5
1393 delta = delta * (factor + self:getMotorRpmPercentage())
1394 spec.motorTemperature.value = math.min(spec.motorTemperature.valueMax, spec.motorTemperature.value + delta)
1395
1396 -- cooling due to wind
1397 delta = spec.motorTemperature.coolingByWindPerMS * dt
1398 local speedFactor = math.pow( math.min(1.0, self:getLastSpeed() / 30), 2 )
1399 spec.motorTemperature.value = math.max(spec.motorTemperature.valueMin, spec.motorTemperature.value - (speedFactor * delta))
1400
1401 -- cooling per fan
1402 if spec.motorTemperature.value > spec.motorFan.enableTemperature then
1403 spec.motorFan.enabled = true
1404 end
1405 if spec.motorFan.enabled then
1406 if spec.motorTemperature.value < spec.motorFan.disableTemperature then
1407 spec.motorFan.enabled = false
1408 end
1409 end
1410 if spec.motorFan.enabled then
1411 local delta = spec.motorFan.coolingPerMS * dt
1412 spec.motorTemperature.value = math.max(spec.motorTemperature.valueMin, spec.motorTemperature.value - delta)
1413 end
1414end