2669 | function Motorized:generateShiftAnimation(gearLever, state, time, isResetPosition) |
2670 | local gearLeverInterpolator = {} |
2671 | gearLeverInterpolator.interpolations = {} |
2672 | |
2673 | state.curRotation[1], state.curRotation[2], state.curRotation[3] = getRotation(gearLever.node) |
2674 | |
2675 | -- check if the current rotation is already the target rotation |
2676 | local requiresChange = false |
2677 | for axis=1, 3 do |
2678 | if math.abs(state.curRotation[axis]-state.rotation[axis]) > 0.00001 then |
2679 | requiresChange = true |
2680 | break |
2681 | end |
2682 | end |
2683 | |
2684 | -- check if the current target direction is already the target direction |
2685 | local alreadyMovingToTarget = true |
2686 | for axis=1, 3 do |
2687 | if math.abs(gearLever.curTarget[axis]-state.rotation[axis]) > 0.00001 then |
2688 | alreadyMovingToTarget = false |
2689 | break |
2690 | end |
2691 | end |
2692 | |
2693 | if not requiresChange or alreadyMovingToTarget then |
2694 | return false |
2695 | end |
2696 | |
2697 | gearLever.curTarget[1], gearLever.curTarget[2], gearLever.curTarget[3] = state.curRotation[1], state.curRotation[2], state.curRotation[3] |
2698 | |
2699 | local requiresMoveToCenter = false |
2700 | if gearLever.centerAxis ~= nil then |
2701 | local curCenter = state.curRotation[gearLever.centerAxis] |
2702 | local tarCenter = state.rotation[gearLever.centerAxis] |
2703 | requiresMoveToCenter = math.abs(curCenter-tarCenter) > 0.00001 |
2704 | end |
2705 | |
2706 | -- move to center on non center axis |
2707 | if requiresMoveToCenter then |
2708 | for axis=1, 3 do |
2709 | if axis ~= gearLever.centerAxis then |
2710 | local cur = state.curRotation[axis] |
2711 | local tar = state.rotation[axis] |
2712 | if gearLever.centerAxis ~= nil then |
2713 | tar = 0 |
2714 | end |
2715 | |
2716 | local allowed = math.abs(cur-tar) > 0.00001 |
2717 | local goToCenter = false |
2718 | if gearLever.centerAxis ~= nil and not allowed then |
2719 | allowed = state.useRotation[axis] and math.abs(state.curRotation[gearLever.centerAxis]-state.rotation[gearLever.centerAxis]) > 0.00001 |
2720 | goToCenter = allowed |
2721 | end |
2722 | |
2723 | if allowed then |
2724 | table.insert(gearLeverInterpolator.interpolations, {axis=axis, cur=cur, tar=(goToCenter and 0 or tar)}) |
2725 | gearLever.curTarget[axis] = tar |
2726 | end |
2727 | end |
2728 | end |
2729 | end |
2730 | |
2731 | if gearLever.centerAxis ~= nil then |
2732 | -- align center axis to new state |
2733 | if requiresMoveToCenter then |
2734 | local curCenter = state.curRotation[gearLever.centerAxis] |
2735 | local tarCenter = state.rotation[gearLever.centerAxis] |
2736 | table.insert(gearLeverInterpolator.interpolations, {axis=gearLever.centerAxis, cur=curCenter, tar=tarCenter}) |
2737 | gearLever.curTarget[gearLever.centerAxis] = tarCenter |
2738 | end |
2739 | |
2740 | -- move non center axis to final position |
2741 | for axis=1, 3 do |
2742 | if axis ~= gearLever.centerAxis then |
2743 | local cur = state.curRotation[axis] |
2744 | local tar = state.rotation[axis] |
2745 | local allowed = math.abs(cur-tar) > 0.00001 |
2746 | if gearLever.centerAxis ~= nil and not allowed then |
2747 | allowed = state.useRotation[axis] and math.abs(state.curRotation[gearLever.centerAxis]-state.rotation[gearLever.centerAxis]) > 0.00001 |
2748 | end |
2749 | |
2750 | if allowed then |
2751 | table.insert(gearLeverInterpolator.interpolations, {axis=axis, cur=requiresMoveToCenter and 0 or cur, tar=tar}) |
2752 | gearLever.curTarget[axis] = tar |
2753 | end |
2754 | end |
2755 | end |
2756 | end |
2757 | |
2758 | for intState, _ in pairs(self.spec_motorized.activeGearLeverInterpolators) do |
2759 | if intState.gearLever == state.gearLever then |
2760 | self.spec_motorized.activeGearLeverInterpolators[intState] = nil |
2761 | end |
2762 | end |
2763 | |
2764 | if self.spec_motorized.activeGearLeverInterpolators[state] == nil then |
2765 | local numInterpolations = #gearLeverInterpolator.interpolations |
2766 | if numInterpolations > 0 then |
2767 | local timePerInterpolation = math.max(gearLever.changeTime, 0.001) / numInterpolations |
2768 | |
2769 | for ii=1, numInterpolations do |
2770 | local interpolation = gearLeverInterpolator.interpolations[ii] |
2771 | interpolation.speed = (interpolation.tar - interpolation.cur) / timePerInterpolation |
2772 | end |
2773 | |
2774 | gearLeverInterpolator.currentInterpolation = 1 |
2775 | gearLeverInterpolator.isResetPosition = (isResetPosition == nil or isResetPosition == true) |
2776 | gearLeverInterpolator.handsOnDelay = gearLever.handsOnDelay |
2777 | gearLeverInterpolator.isGear = state.gear ~= nil |
2778 | self.spec_motorized.activeGearLeverInterpolators[state] = gearLeverInterpolator |
2779 | end |
2780 | end |
2781 | end |
3076 | function Motorized.getSpecValueFuel(storeItem, realItem, configurations, fillTypeFilter) |
3077 | local consumerIndex = 1 |
3078 | if realItem ~= nil and storeItem.configurations ~= nil and realItem.configurations["motor"] ~= nil and storeItem.configurations["motor"] ~= nil then |
3079 | local motorConfigId = realItem.configurations["motor"] |
3080 | consumerIndex = Utils.getNoNil(storeItem.configurations["motor"][motorConfigId].consumerConfigurationIndex, consumerIndex) |
3081 | elseif configurations ~= nil then |
3082 | local motorConfigId = configurations["motor"] |
3083 | if motorConfigId ~= nil then |
3084 | consumerIndex = Utils.getNoNil(storeItem.configurations["motor"][motorConfigId].consumerConfigurationIndex, consumerIndex) |
3085 | end |
3086 | end |
3087 | |
3088 | local fuel, def, electricCharge, methane |
3089 | |
3090 | local fuelFillUnitIndex, defFillUnitIndex, electricFillUnitIndex, methaneFillUnitIndex = 0, 0, 0, 0 |
3091 | |
3092 | --#debug if storeItem.specs.fuel == nil then printCallstack() end |
3093 | |
3094 | local consumerConfiguration = storeItem.specs.fuel and storeItem.specs.fuel.consumers[consumerIndex] |
3095 | if consumerConfiguration ~= nil then |
3096 | for _, unitConsumers in ipairs(consumerConfiguration) do |
3097 | local fillType = g_fillTypeManager:getFillTypeIndexByName(unitConsumers.fillType) |
3098 | |
3099 | if fillTypeFilter == nil or fillType == fillTypeFilter then |
3100 | if fillType == FillType.DIESEL then |
3101 | fuelFillUnitIndex = unitConsumers.fillUnitIndex |
3102 | fuel = unitConsumers.capacity |
3103 | |
3104 | if fillType == FillType.DEF then |
3105 | defFillUnitIndex = unitConsumers.fillUnitIndex |
3106 | def = unitConsumers.capacity |
3107 | end |
3108 | elseif fillType == FillType.ELECTRICCHARGE then |
3109 | electricFillUnitIndex = unitConsumers.fillUnitIndex |
3110 | electricCharge = unitConsumers.capacity |
3111 | elseif fillType == FillType.METHANE then |
3112 | methaneFillUnitIndex = unitConsumers.fillUnitIndex |
3113 | methane = unitConsumers.capacity |
3114 | end |
3115 | end |
3116 | end |
3117 | end |
3118 | |
3119 | local fuelConfigIndex = 1 |
3120 | if realItem ~= nil and storeItem.configurations ~= nil and realItem.configurations["fillUnit"] ~= nil and storeItem.configurations["fillUnit"] ~= nil then |
3121 | fuelConfigIndex = realItem.configurations["fillUnit"] |
3122 | end |
3123 | |
3124 | if storeItem.specs.fuel and storeItem.specs.fuel.fillUnits[fuelConfigIndex] ~= nil then |
3125 | local fuelFillUnit = storeItem.specs.fuel.fillUnits[fuelConfigIndex][fuelFillUnitIndex] |
3126 | if fuelFillUnit ~= nil and fuel == nil then |
3127 | fuel = math.max(fuelFillUnit.capacity, fuel or 0) |
3128 | end |
3129 | |
3130 | local defFillUnit = storeItem.specs.fuel.fillUnits[fuelConfigIndex][defFillUnitIndex] |
3131 | if defFillUnit ~= nil and def == nil then |
3132 | def = math.max(defFillUnit.capacity, def or 0) |
3133 | end |
3134 | |
3135 | local electricFillUnit = storeItem.specs.fuel.fillUnits[fuelConfigIndex][electricFillUnitIndex] |
3136 | if electricFillUnit ~= nil and electricCharge == nil then |
3137 | electricCharge = math.max(electricFillUnit.capacity, electricCharge or 0) |
3138 | end |
3139 | |
3140 | local methaneFillUnit = storeItem.specs.fuel.fillUnits[fuelConfigIndex][methaneFillUnitIndex] |
3141 | if methaneFillUnit ~= nil and methane == nil then |
3142 | methane = math.max(methaneFillUnit.capacity, methane or 0) |
3143 | end |
3144 | |
3145 | end |
3146 | |
3147 | if fuel ~= nil then |
3148 | if def ~= nil and def > 0 then |
3149 | 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")) |
3150 | else |
3151 | return string.format(g_i18n:getText("shop_fuelValue"), fuel, g_i18n:getText("unit_literShort")) |
3152 | end |
3153 | elseif electricCharge ~= nil then |
3154 | return string.format(g_i18n:getText("shop_fuelValue"), electricCharge, g_i18n:getText("unit_kw")) |
3155 | elseif methane ~= nil then |
3156 | return string.format(g_i18n:getText("shop_fuelValue"), methane, g_i18n:getText("unit_kg")) |
3157 | end |
3158 | |
3159 | return nil |
3160 | end |
19 | function Motorized.initSpecialization() |
20 | g_configurationManager:addConfigurationType("motor", g_i18n:getText("configuration_motorSetup"), "motorized", nil, Motorized.getStoreAdditionalConfigData, nil, ConfigurationUtil.SELECTOR_MULTIOPTION) |
21 | |
22 | g_storeManager:addSpecType("fuel", "shopListAttributeIconFuel", Motorized.loadSpecValueFuel, Motorized.getSpecValueFuelDiesel, "vehicle") |
23 | g_storeManager:addSpecType("electricCharge", "shopListAttributeIconElectricCharge", Motorized.loadSpecValueFuel, Motorized.getSpecValueFuelElectricCharge, "vehicle") |
24 | g_storeManager:addSpecType("methane", "shopListAttributeIconMethane", Motorized.loadSpecValueFuel, Motorized.getSpecValueFuelMethane, "vehicle") |
25 | g_storeManager:addSpecType("maxSpeed", "shopListAttributeIconMaxSpeed", Motorized.loadSpecValueMaxSpeed, Motorized.getSpecValueMaxSpeed, "vehicle") |
26 | g_storeManager:addSpecType("power", "shopListAttributeIconPower", Motorized.loadSpecValuePower, Motorized.getSpecValuePower, "vehicle") |
27 | g_storeManager:addSpecType("powerConfig", "shopListAttributeIconPower", Motorized.loadSpecValuePowerConfig, Motorized.getSpecValuePowerConfig, "vehicle") -- used for export only |
28 | g_storeManager:addSpecType("transmission", "shopListAttributeIconTransmission", Motorized.loadSpecValueTransmission, Motorized.getSpecValueTransmission, "vehicle") |
29 | |
30 | Vehicle.registerStateChange("MOTOR_TURN_ON") |
31 | Vehicle.registerStateChange("MOTOR_TURN_OFF") |
32 | |
33 | local schema = Vehicle.xmlSchema |
34 | schema:setXMLSpecializationType("Motorized") |
35 | |
36 | Motorized.registerDifferentialXMLPaths(schema, "vehicle.motorized.differentialConfigurations.differentialConfiguration(?)") |
37 | Motorized.registerDifferentialXMLPaths(schema, "vehicle.motorized.differentials") |
38 | |
39 | Motorized.registerMotorXMLPaths(schema, "vehicle.motorized.motorConfigurations.motorConfiguration(?)") |
40 | |
41 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.motorized.motorConfigurations.motorConfiguration(?)") |
42 | |
43 | Motorized.registerConsumerXMLPaths(schema, "vehicle.motorized.consumerConfigurations.consumerConfiguration(?)") |
44 | Motorized.registerConsumerXMLPaths(schema, "vehicle.motorized.consumers") |
45 | |
46 | schema:register(XMLValueType.FLOAT, "vehicle.wheels.wheelConfigurations.wheelConfiguration(?).wheels#maxForwardSpeed", "Max. forward speed") |
47 | schema:register(XMLValueType.FLOAT, "vehicle.wheels#maxForwardSpeed", "Max. forward speed") |
48 | |
49 | Motorized.registerSoundXMLPaths(schema, "vehicle.motorized.sounds") |
50 | Motorized.registerSoundXMLPaths(schema, "vehicle.motorized.motorConfigurations.motorConfiguration(?).sounds") |
51 | |
52 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.reverseDriveSound#threshold", "Reverse drive sound turn on speed threshold", 4) |
53 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.brakeCompressor#capacity", "Brake compressor capacity", 6) |
54 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.brakeCompressor#refillFillLevel", "Brake compressor refill threshold", "half of capacity") |
55 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.brakeCompressor#fillSpeed", "Brake compressor fill speed", 0.6) |
56 | |
57 | ParticleUtil.registerParticleXMLPaths(schema, "vehicle.motorized.exhaustParticleSystems", "exhaustParticleSystem(?)") |
58 | |
59 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.exhaustParticleSystems#minScale", "Min. scale", 0.5) |
60 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.exhaustParticleSystems#maxScale", "Max. scale", 1) |
61 | |
62 | schema:register(XMLValueType.NODE_INDEX, "vehicle.motorized.exhaustFlap#node", "Exhaust Flap Node") |
63 | schema:register(XMLValueType.ANGLE, "vehicle.motorized.exhaustFlap#maxRot", "Max. rotation", 0) |
64 | schema:register(XMLValueType.INT, "vehicle.motorized.exhaustFlap#rotationAxis", "Rotation Axis", 1) |
65 | |
66 | schema:register(XMLValueType.NODE_INDEX, "vehicle.motorized.exhaustEffects.exhaustEffect(?)#node", "Effect link node") |
67 | schema:register(XMLValueType.STRING, "vehicle.motorized.exhaustEffects.exhaustEffect(?)#filename", "Effect i3d filename") |
68 | |
69 | schema:register(XMLValueType.VECTOR_4, "vehicle.motorized.exhaustEffects.exhaustEffect(?)#minRpmColor", "Min. rpm color", "0 0 0 1") |
70 | schema:register(XMLValueType.VECTOR_4, "vehicle.motorized.exhaustEffects.exhaustEffect(?)#maxRpmColor", "Max. rpm color", "0.0384 0.0359 0.0627 2.0") |
71 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.exhaustEffects.exhaustEffect(?)#minRpmScale", "Min. rpm scale", 0.25) |
72 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.exhaustEffects.exhaustEffect(?)#maxRpmScale", "Max. rpm scale", 0.95) |
73 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.exhaustEffects.exhaustEffect(?)#upFactor", "Defines how far the effect goes up in the air in meter", 0.75) |
74 | |
75 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.motorStartDuration", "Motor start duration", "Duration motor takes to start. After this time player can start to drive") |
76 | |
77 | schema:register(XMLValueType.L10N_STRING, "vehicle.motorized#clutchNoEngagedWarning", "Warning to be displayed if try to start the engine but clutch not engaged", "warning_motorClutchNoEngaged") |
78 | schema:register(XMLValueType.L10N_STRING, "vehicle.motorized#clutchCrackingGearWarning", "Warning to be display if user trys to select a gear without pressing clutch pedal", "action_clutchCrackingGear") |
79 | schema:register(XMLValueType.L10N_STRING, "vehicle.motorized#clutchCrackingGroupWarning", "Warning to be display if user trys to select a gear without pressing clutch pedal", "action_clutchCrackingGroup") |
80 | |
81 | schema:register(XMLValueType.L10N_STRING, "vehicle.motorized#turnOnText", "Motor start text", "action_startMotor") |
82 | schema:register(XMLValueType.L10N_STRING, "vehicle.motorized#turnOffText", "Motor stop text", "action_stopMotor") |
83 | |
84 | schema:register(XMLValueType.NODE_INDEX, "vehicle.motorized.gearLevers.gearLever(?)#node", "Gear lever node") |
85 | schema:register(XMLValueType.INT, "vehicle.motorized.gearLevers.gearLever(?)#centerAxis", "Axis of center bay") |
86 | schema:register(XMLValueType.TIME, "vehicle.motorized.gearLevers.gearLever(?)#changeTime", "Time to move lever from one state to another", 0.5) |
87 | schema:register(XMLValueType.TIME, "vehicle.motorized.gearLevers.gearLever(?)#handsOnDelay", "The animation is delayed by this time to have time to put the hand on the lever", 0) |
88 | schema:register(XMLValueType.INT, "vehicle.motorized.gearLevers.gearLever(?).state(?)#gear", "Gear index") |
89 | schema:register(XMLValueType.INT, "vehicle.motorized.gearLevers.gearLever(?).state(?)#group", "Group index") |
90 | schema:register(XMLValueType.ANGLE, "vehicle.motorized.gearLevers.gearLever(?).state(?)#xRot", "X rotation") |
91 | schema:register(XMLValueType.ANGLE, "vehicle.motorized.gearLevers.gearLever(?).state(?)#yRot", "Y rotation") |
92 | schema:register(XMLValueType.ANGLE, "vehicle.motorized.gearLevers.gearLever(?).state(?)#zRot", "Z rotation") |
93 | |
94 | schema:register(XMLValueType.FLOAT, "vehicle.storeData.specs.power", "Power") |
95 | schema:register(XMLValueType.FLOAT, "vehicle.storeData.specs.maxSpeed", "Max speed") |
96 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.motorConfigurations.motorConfiguration(?)#maxSpeed", "Max speed for shop") |
97 | schema:register(XMLValueType.FLOAT, "vehicle.motorized.motorConfigurations.motorConfiguration(?)#hp", "HP for shop") |
98 | |
99 | schema:register(XMLValueType.STRING, "vehicle.motorized#statsType", "Statistic type", "tractor") |
100 | |
101 | schema:register(XMLValueType.BOOL, "vehicle.motorized#forceSpeedHudDisplay", "Force usage of vehicle speed display in hud independent of setting", false) |
102 | schema:register(XMLValueType.BOOL, "vehicle.motorized#forceRpmHudDisplay", "Force usage of motor speed display in hud independent of setting", false) |
103 | |
104 | Dashboard.registerDashboardXMLPaths(schema, "vehicle.motorized.dashboards", "rpm | load | speed | speedDir | fuelUsage | motorTemperature | motorTemperatureWarning | clutchPedal | gear | gearGroup | movingDirection | directionForward | directionForwardExclusive | directionBackward | movingDirectionLetter | ignitionState") |
105 | Dashboard.registerDashboardWarningXMLPaths(schema, "vehicle.motorized.dashboards") |
106 | |
107 | AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.motorized.animationNodes") |
108 | |
109 | schema:register(XMLValueType.BOOL, Dashboard.GROUP_XML_KEY .. "#isMotorStarting", "Is motor starting") |
110 | schema:register(XMLValueType.BOOL, Dashboard.GROUP_XML_KEY .. "#isMotorRunning", "Is motor running") |
111 | |
112 | schema:setXMLSpecializationType() |
113 | end |
1628 | function Motorized:loadConsumerConfiguration(xmlFile, consumerIndex) |
1629 | local key = string.format("vehicle.motorized.consumerConfigurations.consumerConfiguration(%d)", consumerIndex-1) |
1630 | |
1631 | local spec = self.spec_motorized |
1632 | |
1633 | local fallbackConfigKey = "vehicle.motorized.consumers" |
1634 | |
1635 | spec.consumersEmptyWarning = self.xmlFile:getValue(key .. "#consumersEmptyWarning", "warning_motorFuelEmpty", self.customEnvironment) |
1636 | |
1637 | spec.consumers = {} |
1638 | spec.consumersByFillTypeName = {} |
1639 | spec.consumersByFillType = {} |
1640 | |
1641 | if not xmlFile:hasProperty(key) then |
1642 | return |
1643 | end |
1644 | |
1645 | local i = 0 |
1646 | while true do |
1647 | local consumerKey = string.format(".consumer(%d)", i) |
1648 | if not xmlFile:hasProperty(key..consumerKey) then |
1649 | break |
1650 | end |
1651 | local consumer = {} |
1652 | consumer.fillUnitIndex = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#fillUnitIndex", 1, fallbackConfigKey) |
1653 | |
1654 | local fillTypeName = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#fillType", "consumer", fallbackConfigKey) |
1655 | consumer.fillType = g_fillTypeManager:getFillTypeIndexByName(fillTypeName) |
1656 | |
1657 | consumer.capacity = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#capacity", nil, fallbackConfigKey) |
1658 | |
1659 | local fillUnit = self:getFillUnitByIndex(consumer.fillUnitIndex) |
1660 | if fillUnit ~= nil then |
1661 | if fillUnit.supportedFillTypes[consumer.fillType] ~= nil then |
1662 | fillUnit.capacity = consumer.capacity or fillUnit.capacity |
1663 | |
1664 | --fill fillUnit on start |
1665 | fillUnit.startFillLevel = fillUnit.capacity |
1666 | fillUnit.startFillTypeIndex = consumer.fillType |
1667 | |
1668 | local usage = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#usage", 1.0, fallbackConfigKey) |
1669 | consumer.permanentConsumption = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#permanentConsumption", true, fallbackConfigKey) |
1670 | if consumer.permanentConsumption then |
1671 | consumer.usage = usage / (60*60*1000) -- from l/h to l/ms |
1672 | else |
1673 | consumer.usage = usage |
1674 | end |
1675 | consumer.refillLitersPerSecond = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#refillLitersPerSecond", 0, fallbackConfigKey) |
1676 | consumer.refillCapacityPercentage = ConfigurationUtil.getConfigurationValue(xmlFile, key, consumerKey, "#refillCapacityPercentage", 0, fallbackConfigKey) |
1677 | |
1678 | consumer.fillLevelToChange = 0 |
1679 | |
1680 | table.insert(spec.consumers, consumer) |
1681 | spec.consumersByFillTypeName[fillTypeName:upper()] = consumer |
1682 | spec.consumersByFillType[consumer.fillType] = consumer |
1683 | else |
1684 | Logging.xmlWarning(self.xmlFile, "FillUnit '%d' does not support fillType '%s' for consumer '%s'", consumer.fillUnitIndex, fillTypeName, key..consumerKey) |
1685 | end |
1686 | else |
1687 | Logging.xmlWarning(self.xmlFile, "Unknown fillUnit '%d' for consumer '%s'", consumer.fillUnitIndex, key..consumerKey) |
1688 | end |
1689 | i = i + 1 |
1690 | end |
1691 | end |
1231 | function Motorized:loadMotor(xmlFile, motorId) |
1232 | local key |
1233 | -- Sets motorId to default 1 if motor cannot be found. |
1234 | key, motorId = ConfigurationUtil.getXMLConfigurationKey(xmlFile, motorId, "vehicle.motorized.motorConfigurations.motorConfiguration", "vehicle.motorized", "motor") |
1235 | |
1236 | local spec = self.spec_motorized |
1237 | |
1238 | local fallbackConfigKey = "vehicle.motorized.motorConfigurations.motorConfiguration(0)" |
1239 | |
1240 | spec.motorType = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#type", "vehicle", fallbackConfigKey) |
1241 | spec.motorStartAnimation = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#startAnimationName", "vehicle", fallbackConfigKey) |
1242 | |
1243 | spec.consumerConfigurationIndex = ConfigurationUtil.getConfigurationValue(xmlFile, key, "#consumerConfigurationIndex", "", 1, fallbackConfigKey) |
1244 | |
1245 | local wheelKey, _ = ConfigurationUtil.getXMLConfigurationKey(xmlFile, self.configurations["wheel"], "vehicle.wheels.wheelConfigurations.wheelConfiguration", "vehicle.wheels", "wheels") |
1246 | |
1247 | ObjectChangeUtil.updateObjectChanges(xmlFile, "vehicle.motorized.motorConfigurations.motorConfiguration", motorId, self.components, self) |
1248 | |
1249 | local motorMinRpm = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#minRpm", 1000, fallbackConfigKey) |
1250 | local motorMaxRpm = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#maxRpm", 1800, fallbackConfigKey) |
1251 | local minSpeed = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#minSpeed", 1, fallbackConfigKey) |
1252 | local maxForwardSpeed = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#maxForwardSpeed", nil, fallbackConfigKey) |
1253 | local maxBackwardSpeed = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#maxBackwardSpeed", nil, fallbackConfigKey) |
1254 | if maxForwardSpeed ~= nil then |
1255 | maxForwardSpeed = maxForwardSpeed/3.6 |
1256 | end |
1257 | if maxBackwardSpeed ~= nil then |
1258 | maxBackwardSpeed = maxBackwardSpeed/3.6 |
1259 | end |
1260 | |
1261 | local maxWheelSpeed = ConfigurationUtil.getConfigurationValue(xmlFile, wheelKey, ".wheels", "#maxForwardSpeed", nil, nil) |
1262 | if maxWheelSpeed ~= nil then |
1263 | maxForwardSpeed = maxWheelSpeed/3.6 |
1264 | end |
1265 | local accelerationLimit = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#accelerationLimit", 2.0, fallbackConfigKey) -- m/s^2 |
1266 | |
1267 | local brakeForce = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#brakeForce", 10, fallbackConfigKey) * 2 |
1268 | local lowBrakeForceScale = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#lowBrakeForceScale", 0.5, fallbackConfigKey) |
1269 | local lowBrakeForceSpeedLimit = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#lowBrakeForceSpeedLimit", 1, fallbackConfigKey) / 3600 |
1270 | local torqueScale = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#torqueScale", 1, fallbackConfigKey) |
1271 | local ptoMotorRpmRatio = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#ptoMotorRpmRatio", 4, fallbackConfigKey) |
1272 | |
1273 | -- transmission settings can only be fully overwritten, not only single attributes |
1274 | local transmissionKey = key .. ".transmission" |
1275 | if not xmlFile:hasProperty(transmissionKey) then |
1276 | transmissionKey = fallbackConfigKey .. ".transmission" |
1277 | end |
1278 | |
1279 | local minForwardGearRatio = xmlFile:getValue(transmissionKey .. "#minForwardGearRatio") |
1280 | local maxForwardGearRatio = xmlFile:getValue(transmissionKey .. "#maxForwardGearRatio") |
1281 | local minBackwardGearRatio = xmlFile:getValue(transmissionKey .. "#minBackwardGearRatio") |
1282 | local maxBackwardGearRatio = xmlFile:getValue(transmissionKey .. "#maxBackwardGearRatio") |
1283 | local gearChangeTime = xmlFile:getValue(transmissionKey .. "#gearChangeTime") |
1284 | local autoGearChangeTime = xmlFile:getValue(transmissionKey .. "#autoGearChangeTime") |
1285 | local axleRatio = xmlFile:getValue(transmissionKey .. "#axleRatio", 1.0) |
1286 | local startGearThreshold = xmlFile:getValue(transmissionKey .. "#startGearThreshold", VehicleMotor.GEAR_START_THRESHOLD) |
1287 | |
1288 | |
1289 | if maxForwardGearRatio == nil or minForwardGearRatio == nil then |
1290 | minForwardGearRatio = nil |
1291 | maxForwardGearRatio = nil |
1292 | else |
1293 | minForwardGearRatio = minForwardGearRatio * axleRatio |
1294 | maxForwardGearRatio = maxForwardGearRatio * axleRatio |
1295 | end |
1296 | if minBackwardGearRatio == nil or maxBackwardGearRatio == nil then |
1297 | minBackwardGearRatio = nil |
1298 | maxBackwardGearRatio = nil |
1299 | else |
1300 | minBackwardGearRatio = minBackwardGearRatio * axleRatio |
1301 | maxBackwardGearRatio = maxBackwardGearRatio * axleRatio |
1302 | end |
1303 | |
1304 | -- Read forward gear ratios |
1305 | local forwardGears |
1306 | if minForwardGearRatio == nil then |
1307 | forwardGears = self:loadGears(xmlFile, "forwardGear", transmissionKey, motorMaxRpm, axleRatio, 1) |
1308 | if forwardGears == nil then |
1309 | print("Warning: Missing forward gear ratios for motor in '"..self.configFileName.."'!") |
1310 | forwardGears = {{ratio=1, default=false}} |
1311 | end |
1312 | end |
1313 | -- Read backward gear ratios |
1314 | local backwardGears |
1315 | if minBackwardGearRatio == nil then |
1316 | backwardGears = self:loadGears(xmlFile, "backwardGear", transmissionKey, motorMaxRpm, axleRatio, -1) |
1317 | end |
1318 | |
1319 | local gearGroups = self:loadGearGroups(xmlFile, transmissionKey .. ".groups", motorMaxRpm, axleRatio) |
1320 | local groupsType = xmlFile:getValue(transmissionKey .. ".groups#type", "default") |
1321 | local groupChangeTime = xmlFile:getValue(transmissionKey .. ".groups#changeTime", 0.5) |
1322 | |
1323 | local directionChangeUseGear = xmlFile:getValue(transmissionKey .. ".directionChange#useGear", false) |
1324 | local directionChangeGearIndex = xmlFile:getValue(transmissionKey .. ".directionChange#reverseGearIndex", 1) |
1325 | local directionChangeUseGroup = xmlFile:getValue(transmissionKey .. ".directionChange#useGroup", false) |
1326 | local directionChangeGroupIndex = xmlFile:getValue(transmissionKey .. ".directionChange#reverseGroupIndex", 1) |
1327 | local directionChangeTime = xmlFile:getValue(transmissionKey .. ".directionChange#changeTime", 0.5) |
1328 | |
1329 | local manualShiftGears = xmlFile:getValue(transmissionKey .. ".manualShift#gears", true) |
1330 | local manualShiftGroups = xmlFile:getValue(transmissionKey .. ".manualShift#groups", true) |
1331 | |
1332 | --local maxTorque = 0 |
1333 | local torqueCurve = AnimCurve.new(linearInterpolator1) |
1334 | local torqueI = 0 |
1335 | local torqueBase = fallbackConfigKey..".motor.torque" |
1336 | if key ~= nil and xmlFile:hasProperty(key..".motor.torque(0)") then -- using selected motor configuration |
1337 | torqueBase = key..".motor.torque" |
1338 | end |
1339 | |
1340 | while true do |
1341 | local torqueKey = string.format(torqueBase.."(%d)", torqueI) |
1342 | local normRpm = xmlFile:getValue(torqueKey.."#normRpm") |
1343 | local rpm |
1344 | if normRpm == nil then |
1345 | rpm = xmlFile:getValue(torqueKey.."#rpm") |
1346 | else |
1347 | rpm = normRpm * motorMaxRpm |
1348 | end |
1349 | local torque = xmlFile:getValue(torqueKey.."#torque") |
1350 | if torque == nil or rpm == nil then |
1351 | break |
1352 | end |
1353 | torqueCurve:addKeyframe({torque*torqueScale, time = rpm}) |
1354 | torqueI = torqueI +1 |
1355 | end |
1356 | |
1357 | spec.motor = VehicleMotor.new(self, motorMinRpm, motorMaxRpm, maxForwardSpeed, maxBackwardSpeed, torqueCurve, brakeForce, forwardGears, backwardGears, minForwardGearRatio, maxForwardGearRatio, minBackwardGearRatio, maxBackwardGearRatio, ptoMotorRpmRatio, minSpeed) |
1358 | spec.motor:setGearGroups(gearGroups, groupsType, groupChangeTime) |
1359 | spec.motor:setDirectionChange(directionChangeUseGear, directionChangeGearIndex, directionChangeUseGroup, directionChangeGroupIndex, directionChangeTime) |
1360 | spec.motor:setManualShift(manualShiftGears, manualShiftGroups) |
1361 | spec.motor:setStartGearThreshold(startGearThreshold) |
1362 | |
1363 | local rotInertia = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#rotInertia", spec.motor:getRotInertia(), fallbackConfigKey) |
1364 | local dampingRateScale = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#dampingRateScale", 1, fallbackConfigKey) |
1365 | spec.motor:setRotInertia(rotInertia) |
1366 | spec.motor:setDampingRateScale(dampingRateScale) |
1367 | spec.motor:setLowBrakeForce(lowBrakeForceScale, lowBrakeForceSpeedLimit) |
1368 | spec.motor:setAccelerationLimit(accelerationLimit) |
1369 | |
1370 | local motorRotationAccelerationLimit = ConfigurationUtil.getConfigurationValue(xmlFile, key, ".motor", "#rpmSpeedLimit", nil, fallbackConfigKey) -- xml: rpm/s -> converted to rad/s^2 |
1371 | if motorRotationAccelerationLimit ~= nil then |
1372 | motorRotationAccelerationLimit = motorRotationAccelerationLimit * math.pi/30 |
1373 | spec.motor:setMotorRotationAccelerationLimit(motorRotationAccelerationLimit) |
1374 | end |
1375 | |
1376 | if gearChangeTime ~= nil then |
1377 | spec.motor:setGearChangeTime(gearChangeTime) |
1378 | end |
1379 | if autoGearChangeTime ~= nil then |
1380 | spec.motor:setAutoGearChangeTime(autoGearChangeTime) |
1381 | end |
1382 | end |
1575 | function Motorized:loadSounds(xmlFile, baseString) |
1576 | if self.isClient then |
1577 | local spec = self.spec_motorized |
1578 | |
1579 | spec.samples = spec.samples or {} |
1580 | |
1581 | spec.samples.motorStart = g_soundManager:loadSampleFromXML(xmlFile, baseString, "motorStart", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.motorStart |
1582 | spec.samples.motorStop = g_soundManager:loadSampleFromXML(xmlFile, baseString, "motorStop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.motorStop |
1583 | spec.samples.clutchCracking = g_soundManager:loadSampleFromXML(xmlFile, baseString, "clutchCracking", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.clutchCracking |
1584 | spec.samples.gearEngaged = g_soundManager:loadSampleFromXML(xmlFile, baseString, "gearEngaged", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.gearEngaged |
1585 | spec.samples.gearDisengaged = g_soundManager:loadSampleFromXML(xmlFile, baseString, "gearDisengaged", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.gearDisengaged |
1586 | spec.samples.gearGroupChange = g_soundManager:loadSampleFromXML(xmlFile, baseString, "gearGroupChange", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.gearGroupChange |
1587 | spec.samples.gearLeverStart = g_soundManager:loadSampleFromXML(xmlFile, baseString, "gearLeverStart", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.gearLeverStart |
1588 | spec.samples.gearLeverEnd = g_soundManager:loadSampleFromXML(xmlFile, baseString, "gearLeverEnd", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.gearLeverEnd |
1589 | spec.samples.gearGroupLeverStart = g_soundManager:loadSampleFromXML(xmlFile, baseString, "gearGroupLeverStart", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.gearGroupLeverStart |
1590 | spec.samples.gearGroupLeverEnd = g_soundManager:loadSampleFromXML(xmlFile, baseString, "gearGroupLeverEnd", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.gearGroupLeverEnd |
1591 | spec.samples.blowOffValve = g_soundManager:loadSampleFromXML(xmlFile, baseString, "blowOffValve", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.blowOffValve |
1592 | spec.samples.retarder = g_soundManager:loadSampleFromXML(xmlFile, baseString, "retarder", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.retarder |
1593 | |
1594 | spec.gearboxSamples = g_soundManager:loadSamplesFromXML(xmlFile, baseString, "gearbox", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self, spec.gearboxSamples) |
1595 | spec.motorSamples = g_soundManager:loadSamplesFromXML(xmlFile, baseString, "motor", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self, spec.motorSamples) |
1596 | |
1597 | spec.samples.airCompressorStart = g_soundManager:loadSampleFromXML(xmlFile, baseString, "airCompressorStart", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.airCompressorStart |
1598 | spec.samples.airCompressorStop = g_soundManager:loadSampleFromXML(xmlFile, baseString, "airCompressorStop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.airCompressorStop |
1599 | spec.samples.airCompressorRun = g_soundManager:loadSampleFromXML(xmlFile, baseString, "airCompressorRun", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.airCompressorRun |
1600 | |
1601 | spec.samples.compressedAir = g_soundManager:loadSampleFromXML(xmlFile, baseString, "compressedAir", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.compressedAir |
1602 | if spec.samples.compressedAir ~= nil then |
1603 | spec.samples.compressedAir.brakeTime = 0 |
1604 | spec.samples.compressedAir.lastBrakeTime = 0 |
1605 | end |
1606 | |
1607 | spec.samples.airRelease = g_soundManager:loadSampleFromXML(xmlFile, baseString, "airRelease", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.airRelease |
1608 | |
1609 | spec.samples.reverseDrive = g_soundManager:loadSampleFromXML(xmlFile, baseString, "reverseDrive", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.reverseDrive |
1610 | spec.reverseDriveThreshold = xmlFile:getValue("vehicle.motorized.reverseDriveSound#threshold", 4) |
1611 | |
1612 | spec.brakeCompressor = {} |
1613 | spec.brakeCompressor.capacity = xmlFile:getValue("vehicle.motorized.brakeCompressor#capacity", 6) |
1614 | spec.brakeCompressor.refillFilllevel = math.min(spec.brakeCompressor.capacity, xmlFile:getValue("vehicle.motorized.brakeCompressor#refillFillLevel", spec.brakeCompressor.capacity / 2)) |
1615 | spec.brakeCompressor.fillSpeed = xmlFile:getValue("vehicle.motorized.brakeCompressor#fillSpeed", 0.6) / 1000 |
1616 | spec.brakeCompressor.fillLevel = 0 |
1617 | spec.brakeCompressor.doFill = true |
1618 | |
1619 | spec.isBrakeSamplePlaying = false |
1620 | spec.samples.brake = g_soundManager:loadSampleFromXML(xmlFile, baseString, "brake", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) or spec.samples.brake |
1621 | |
1622 | spec.compressionSoundTime = 0 |
1623 | end |
1624 | end |
347 | function Motorized:onLoad(savegame) |
348 | local spec = self.spec_motorized |
349 | |
350 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.turnedOnRotationNodes.turnedOnRotationNode#type", "vehicle.motor.animationNodes.animationNode", "motor") --FS17 to FS19 |
351 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.differentialConfigurations", "vehicle.motorized.differentialConfigurations") --FS17 to FS19 |
352 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.motorConfigurations", "vehicle.motorized.motorConfigurations") --FS17 to FS19 |
353 | 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 |
354 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.rpm", "vehicle.motorized.dashboards.dashboard with valueType 'rpm'") --FS17 to FS19 |
355 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.speed", "vehicle.motorized.dashboards.dashboard with valueType 'speed'") --FS17 to FS19 |
356 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.fuelUsage", "vehicle.motorized.dashboards.dashboard with valueType 'fuelUsage'") --FS17 to FS19 |
357 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.indoorHud.fuel", "fillUnit.dashboard with valueType 'fillLevel'") --FS17 to FS19 |
358 | |
359 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.motor", "vehicle.motorized.motorConfigurations.motorConfiguration(?).motor") --FS19 to FS22 |
360 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.transmission", "vehicle.motorized.motorConfigurations.motorConfiguration(?).transmission") --FS19 to FS22 |
361 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.fuelCapacity", "vehicle.motorized.consumerConfigurations.consumerConfiguration.consumer#capacity") --FS19 to FS22 |
362 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.motorized.motorConfigurations.motorConfiguration(?).fuelCapacity", "vehicle.motorized.consumerConfigurations.consumerConfiguration.consumer#capacity") --FS19 to FS22 |
363 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle#consumerConfigurationIndex", "vehicle.motorized.motorConfigurations.motorConfiguration(?)#consumerConfigurationIndex'") --FS19 to FS22 |
364 | |
365 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.motorized.exhaustParticleSystems#count") --FS19 to FS22 |
366 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.motorized.exhaustParticleSystems.exhaustParticleSystem1", "vehicle.motorized.exhaustParticleSystems.exhaustParticleSystem") --FS19 to FS22 |
367 | |
368 | spec.motorizedNode = nil |
369 | for _, component in pairs(self.components) do |
370 | if component.motorized then |
371 | spec.motorizedNode = component.node |
372 | break |
373 | end |
374 | end |
375 | |
376 | spec.directionChangeMode = VehicleMotor.DIRECTION_CHANGE_MODE_AUTOMATIC |
377 | spec.gearShiftMode = VehicleMotor.SHIFT_MODE_AUTOMATIC |
378 | |
379 | local configKey = string.format("vehicle.motorized.motorConfigurations.motorConfiguration(%d)", self.configurations["motor"] - 1) |
380 | |
381 | self:loadDifferentials(self.xmlFile, self.differentialIndex) |
382 | self:loadMotor(self.xmlFile, self.configurations["motor"]) |
383 | |
384 | self:loadSounds(self.xmlFile, "vehicle.motorized.sounds") |
385 | if self.xmlFile:hasProperty(configKey) then |
386 | self:loadSounds(self.xmlFile, configKey .. ".sounds") |
387 | end |
388 | |
389 | self:loadConsumerConfiguration(self.xmlFile, spec.consumerConfigurationIndex) |
390 | |
391 | if self.isClient then |
392 | self:loadExhaustEffects(self.xmlFile) |
393 | end |
394 | |
395 | spec.gearLevers = {} |
396 | spec.activeGearLeverInterpolators = {} |
397 | self.xmlFile:iterate("vehicle.motorized.gearLevers.gearLever", function(index, key) |
398 | local entry = {} |
399 | entry.node = self.xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings) |
400 | if entry.node ~= nil then |
401 | entry.centerAxis = self.xmlFile:getValue(key .. "#centerAxis") |
402 | |
403 | entry.changeTime = self.xmlFile:getValue(key .. "#changeTime", 500) |
404 | entry.handsOnDelay = self.xmlFile:getValue(key .. "#handsOnDelay", 0) |
405 | |
406 | entry.curTarget = {getRotation(entry.node)} |
407 | |
408 | entry.states = {} |
409 | self.xmlFile:iterate(key .. ".state", function(stateIndex, stateKey) |
410 | local state = {} |
411 | |
412 | state.gear = self.xmlFile:getValue(stateKey .. "#gear") |
413 | state.group = self.xmlFile:getValue(stateKey .. "#group") |
414 | |
415 | if state.gear ~= nil or state.group ~= nil then |
416 | state.node = entry.node |
417 | state.gearLever = entry |
418 | |
419 | local x, y, z = getRotation(entry.node) |
420 | local xRot = self.xmlFile:getValue(stateKey .. "#xRot", x) |
421 | local yRot = self.xmlFile:getValue(stateKey .. "#yRot", y) |
422 | local zRot = self.xmlFile:getValue(stateKey .. "#zRot", z) |
423 | |
424 | state.rotation = {xRot, yRot, zRot} |
425 | state.useRotation = {self.xmlFile:getValue(stateKey .. "#xRot") ~= nil, |
426 | self.xmlFile:getValue(stateKey .. "#yRot") ~= nil, |
427 | self.xmlFile:getValue(stateKey .. "#zRot") ~= nil} |
428 | state.curRotation = {xRot, yRot, zRot} |
429 | |
430 | table.insert(entry.states, state) |
431 | else |
432 | Logging.xmlWarning(self.xmlFile, "Unable to load gear lever state. Missing gear or group! '%s'", stateKey) |
433 | end |
434 | end) |
435 | |
436 | table.insert(spec.gearLevers, entry) |
437 | else |
438 | Logging.xmlWarning(self.xmlFile, "Unable to load gear lever. Missing node! '%s'", key) |
439 | end |
440 | end) |
441 | |
442 | spec.stopMotorOnLeave = true |
443 | |
444 | spec.motorStartDuration = 0 |
445 | if spec.samples ~= nil and spec.samples.motorStart ~= nil then |
446 | spec.motorStartDuration = spec.samples.motorStart.duration |
447 | end |
448 | spec.motorStartDuration = self.xmlFile:getValue("vehicle.motorized.motorStartDuration", spec.motorStartDuration) or 0 |
449 | if self.xmlFile:hasProperty(configKey) then |
450 | spec.motorStartDuration = self.xmlFile:getValue(configKey .. ".motorStartDuration", spec.motorStartDuration) |
451 | end |
452 | |
453 | spec.clutchNoEngagedWarning = self.xmlFile:getValue("vehicle.motorized#clutchNoEngagedWarning", "warning_motorClutchNoEngaged", self.customEnvironment) |
454 | spec.clutchCrackingGearWarning = self.xmlFile:getValue("vehicle.motorized#clutchCrackingGearWarning", "action_clutchCrackingGear", self.customEnvironment) |
455 | spec.clutchCrackingGroupWarning = self.xmlFile:getValue("vehicle.motorized#clutchCrackingGroupWarning", "action_clutchCrackingGroup", self.customEnvironment) |
456 | |
457 | spec.turnOnText = self.xmlFile:getValue("vehicle.motorized#turnOnText", "action_startMotor", self.customEnvironment) |
458 | spec.turnOffText = self.xmlFile:getValue("vehicle.motorized#turnOffText", "action_stopMotor", self.customEnvironment) |
459 | |
460 | spec.speedDisplayScale = 1 |
461 | spec.motorStartTime = 0 |
462 | spec.actualLoadPercentage = 0 |
463 | spec.smoothedLoadPercentage = 0 |
464 | spec.maxDecelerationDuringBrake = 0 |
465 | |
466 | spec.lastControlParameters = { |
467 | acceleratorPedal = nil, |
468 | maxSpeed = nil, |
469 | maxAcceleration = nil, |
470 | minMotorRotSpeed = nil, |
471 | maxMotorRotSpeed = nil, |
472 | maxMotorRotAcceleration = nil, |
473 | minGearRatio = nil, |
474 | maxGearRatio = nil, |
475 | maxClutchTorque = nil, |
476 | neededPtoTorque = nil, |
477 | } |
478 | |
479 | spec.clutchCrackingTimeOut = math.huge |
480 | spec.clutchState = 0 |
481 | spec.clutchStateSent = 0 |
482 | |
483 | spec.isMotorStarted = false |
484 | spec.motorStopTimerDuration = g_gameSettings:getValue("motorStopTimerDuration") |
485 | spec.motorStopTimer = spec.motorStopTimerDuration |
486 | spec.ignitionState = 0 |
487 | |
488 | spec.motorTemperature = {} |
489 | spec.motorTemperature.value = 20 |
490 | spec.motorTemperature.valueSend = 20 |
491 | spec.motorTemperature.valueMax = 120 |
492 | spec.motorTemperature.valueMin = 20 |
493 | spec.motorTemperature.heatingPerMS = 1.5 / 1000 -- delta °C per ms, at full load |
494 | spec.motorTemperature.coolingByWindPerMS = 1.00 / 1000 |
495 | |
496 | spec.motorFan = {} |
497 | spec.motorFan.enabled = false |
498 | spec.motorFan.enableTemperature = 95 |
499 | spec.motorFan.disableTemperature = 85 |
500 | spec.motorFan.coolingPerMS = 3.0 / 1000 |
501 | |
502 | spec.lastFuelUsage = 0 |
503 | spec.lastFuelUsageDisplay = 0 |
504 | spec.lastFuelUsageDisplayTime = 0 |
505 | spec.fuelUsageBuffer = ValueBuffer.new(250) |
506 | spec.lastDefUsage = 0 |
507 | spec.lastAirUsage = 0 |
508 | spec.lastVehicleDamage = 0 |
509 | |
510 | spec.forceSpeedHudDisplay = self.xmlFile:getValue("vehicle.motorized#forceSpeedHudDisplay", false) |
511 | spec.forceRpmHudDisplay = self.xmlFile:getValue("vehicle.motorized#forceRpmHudDisplay", false) |
512 | |
513 | spec.statsType = string.lower(self.xmlFile:getValue("vehicle.motorized#statsType", "tractor")) |
514 | if spec.statsType ~= "tractor" and spec.statsType ~= "car" and spec.statsType ~= "truck" then |
515 | spec.statsType = "tractor" |
516 | end |
517 | |
518 | spec.statsTypeDistance = spec.statsType .. "Distance" |
519 | |
520 | if self.loadDashboardsFromXML ~= nil then |
521 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "rpm", |
522 | valueObject = spec.motor, |
523 | valueFunc = "getLastModulatedMotorRpm", |
524 | minFunc = 0, |
525 | maxFunc = "getMaxRpm"}) |
526 | |
527 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "load", |
528 | valueObject = spec.motor, |
529 | valueFunc = "getSmoothLoadPercentage", |
530 | minFunc = 0, |
531 | maxFunc = 100, |
532 | valueFactor = 100}) |
533 | |
534 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "speed", |
535 | valueObject = self, |
536 | valueFunc = "getLastSpeed", |
537 | minFunc = 0, |
538 | maxFunc = self:getMotor():getMaximumForwardSpeed()*3.6}) |
539 | |
540 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "speedDir", |
541 | valueObject = self, |
542 | valueFunc = Motorized.getDashboardSpeedDir, |
543 | minFunc = -self:getMotor():getMaximumBackwardSpeed()*3.6, |
544 | maxFunc = self:getMotor():getMaximumForwardSpeed()*3.6, |
545 | centerFunc = 0}) |
546 | |
547 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "fuelUsage", |
548 | valueObject = spec, |
549 | valueFunc = "lastFuelUsageDisplay"}) |
550 | |
551 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "motorTemperature", |
552 | valueObject = spec.motorTemperature, |
553 | valueFunc = "value", |
554 | minFunc = "valueMin", |
555 | maxFunc = "valueMax"}) |
556 | |
557 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "motorTemperatureWarning", |
558 | valueObject = spec.motorTemperature, |
559 | valueFunc = "value", |
560 | additionalAttributesFunc = Dashboard.warningAttributes, |
561 | stateFunc = Dashboard.warningState}) |
562 | |
563 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "clutchPedal", |
564 | valueObject = spec.motor, |
565 | valueFunc = "getSmoothedClutchPedal", |
566 | minFunc = 0, |
567 | maxFunc = 1}) |
568 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "gear", |
569 | valueObject = spec.motor, |
570 | valueFunc = "getGearToDisplay", |
571 | minFunc = 0, |
572 | maxFunc = math.huge}) |
573 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "gearGroup", |
574 | valueObject = spec.motor, |
575 | valueFunc = "getGearGroupToDisplay", |
576 | minFunc = 0, |
577 | maxFunc = math.huge}) |
578 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "movingDirection", |
579 | valueObject = spec.motor, |
580 | valueFunc = "getDrivingDirection", |
581 | minFunc = -1, |
582 | maxFunc = 1}) |
583 | |
584 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "directionForward", |
585 | valueObject = spec.motor, |
586 | valueFunc = function(motor) |
587 | return motor:getDrivingDirection() >= 0 |
588 | end}) |
589 | |
590 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "directionForwardExclusive", |
591 | valueObject = spec.motor, |
592 | valueFunc = function(motor) |
593 | return motor:getDrivingDirection() > 0 |
594 | end}) |
595 | |
596 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "directionBackward", |
597 | valueObject = spec.motor, |
598 | valueFunc = function(motor) |
599 | return motor:getDrivingDirection() < 0 |
600 | end}) |
601 | |
602 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "movingDirectionLetter", |
603 | valueObject = spec.motor, |
604 | valueFunc = function(motor) |
605 | return motor:getDrivingDirection() == 1 and "F" or (motor:getDrivingDirection() == -1 and "R" or "N") |
606 | end}) |
607 | |
608 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "ignitionState", |
609 | valueObject = self, |
610 | valueFunc = Motorized.getMotorIgnitionState, |
611 | minFunc = 0, |
612 | maxFunc = 2}) |
613 | |
614 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.motorized.dashboards", {valueTypeToLoad = "battery", |
615 | valueObject = self, |
616 | valueFunc = 12 + (math.random() * 0.5 - 0.15), |
617 | minFunc = 0, |
618 | maxFunc = 15}) |
619 | end |
620 | |
621 | spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.motorized.animationNodes", self.components, self, self.i3dMappings) |
622 | |
623 | spec.traveledDistanceBuffer = 0 |
624 | |
625 | spec.dirtyFlag = self:getNextDirtyFlag() |
626 | spec.inputDirtyFlag = self:getNextDirtyFlag() |
627 | |
628 | self:registerVehicleSetting(GameSettings.SETTING.DIRECTION_CHANGE_MODE, false) |
629 | self:registerVehicleSetting(GameSettings.SETTING.GEAR_SHIFT_MODE, false) |
630 | end |
2463 | function Motorized:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
2464 | if self.isClient then |
2465 | local spec = self.spec_motorized |
2466 | self:clearActionEventsTable(spec.actionEvents) |
2467 | |
2468 | if isActiveForInputIgnoreSelection then |
2469 | local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_MOTOR_STATE, self, Motorized.actionEventToggleMotorState, false, true, false, true, nil) |
2470 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_HIGH) |
2471 | g_inputBinding:setActionEventText(actionEventId, spec.turnOnText) |
2472 | |
2473 | if spec.motor.minForwardGearRatio == nil or spec.motor.minBackwardGearRatio == nil then |
2474 | if self:getGearShiftMode() ~= VehicleMotor.SHIFT_MODE_AUTOMATIC or not GS_IS_CONSOLE_VERSION then |
2475 | if spec.motor.manualShiftGears then |
2476 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_UP, self, Motorized.actionEventShiftGear, false, true, false, true, nil) |
2477 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2478 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_DOWN, self, Motorized.actionEventShiftGear, false, true, false, true, nil) |
2479 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2480 | |
2481 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_SELECT_1, self, Motorized.actionEventSelectGear, true, true, false, true, 1) |
2482 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2483 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_SELECT_2, self, Motorized.actionEventSelectGear, true, true, false, true, 2) |
2484 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2485 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_SELECT_3, self, Motorized.actionEventSelectGear, true, true, false, true, 3) |
2486 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2487 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_SELECT_4, self, Motorized.actionEventSelectGear, true, true, false, true, 4) |
2488 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2489 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_SELECT_5, self, Motorized.actionEventSelectGear, true, true, false, true, 5) |
2490 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2491 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_SELECT_6, self, Motorized.actionEventSelectGear, true, true, false, true, 6) |
2492 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2493 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_SELECT_7, self, Motorized.actionEventSelectGear, true, true, false, true, 7) |
2494 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2495 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GEAR_SELECT_8, self, Motorized.actionEventSelectGear, true, true, false, true, 8) |
2496 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2497 | end |
2498 | |
2499 | if spec.motor.manualShiftGroups then |
2500 | if spec.motor.gearGroups ~= nil then |
2501 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GROUP_UP, self, Motorized.actionEventShiftGroup, false, true, false, true, nil) |
2502 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2503 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GROUP_DOWN, self, Motorized.actionEventShiftGroup, false, true, false, true, nil) |
2504 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2505 | |
2506 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GROUP_SELECT_1, self, Motorized.actionEventSelectGroup, true, true, false, true, 1) |
2507 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2508 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GROUP_SELECT_2, self, Motorized.actionEventSelectGroup, true, true, false, true, 2) |
2509 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2510 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GROUP_SELECT_3, self, Motorized.actionEventSelectGroup, true, true, false, true, 3) |
2511 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2512 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.SHIFT_GROUP_SELECT_4, self, Motorized.actionEventSelectGroup, true, true, false, true, 4) |
2513 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2514 | end |
2515 | end |
2516 | |
2517 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.AXIS_CLUTCH_VEHICLE, self, Motorized.actionEventClutch, false, false, true, true, nil) |
2518 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2519 | end |
2520 | end |
2521 | |
2522 | if self:getDirectionChangeMode() == VehicleMotor.DIRECTION_CHANGE_MODE_MANUAL or self:getGearShiftMode() ~= VehicleMotor.SHIFT_MODE_AUTOMATIC then |
2523 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.DIRECTION_CHANGE, self, Motorized.actionEventDirectionChange, false, true, false, true, nil, nil, true) |
2524 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2525 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.DIRECTION_CHANGE_POS, self, Motorized.actionEventDirectionChange, false, true, false, true, nil, nil, true) |
2526 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2527 | _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.DIRECTION_CHANGE_NEG, self, Motorized.actionEventDirectionChange, false, true, false, true, nil, nil, true) |
2528 | g_inputBinding:setActionEventTextVisibility(actionEventId, false) |
2529 | end |
2530 | |
2531 | Motorized.updateActionEvents(self) |
2532 | end |
2533 | end |
2534 | end |
784 | function Motorized:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
785 | local spec = self.spec_motorized |
786 | |
787 | local accInput = 0 |
788 | if self.getAxisForward ~= nil then |
789 | accInput = self:getAxisForward() |
790 | end |
791 | |
792 | if self:getIsMotorStarted() then |
793 | spec.motor:update(dt) |
794 | |
795 | -- client receives this information from server |
796 | if self.isServer then |
797 | spec.actualLoadPercentage = spec.motor.rawLoadPercentage |
798 | end |
799 | |
800 | spec.smoothedLoadPercentage = spec.motor:getSmoothLoadPercentage() |
801 | |
802 | if self.getCruiseControlState ~= nil then |
803 | if self:getCruiseControlState() ~= Drivable.CRUISECONTROL_STATE_OFF then |
804 | accInput = 1 |
805 | end |
806 | end |
807 | |
808 | if self.isServer then |
809 | self:updateConsumers(dt, accInput) |
810 | |
811 | -- update motor properties on damage change to update the torque reduction |
812 | local damage = self:getVehicleDamage() |
813 | if math.abs(damage - spec.lastVehicleDamage) > 0.05 then |
814 | self:updateMotorProperties() |
815 | spec.lastVehicleDamage = self:getVehicleDamage() |
816 | end |
817 | end |
818 | |
819 | if self.isClient then |
820 | -- update sounds |
821 | local samples = spec.samples |
822 | local rpm, minRpm, maxRpm = spec.motor:getLastModulatedMotorRpm(), spec.motor.minRpm, spec.motor.maxRpm |
823 | local rpmPercentage = math.max(math.min((rpm - minRpm) / (maxRpm - minRpm), 1), 0) |
824 | local loadPercentage = math.max(math.min(spec.smoothedLoadPercentage, 1), -1) |
825 | g_soundManager:setSamplesLoopSynthesisParameters(spec.motorSamples, rpmPercentage, loadPercentage) |
826 | |
827 | if g_soundManager:getIsSamplePlaying(spec.motorSamples[1], 1.5*dt) then |
828 | -- air compressor fill sound |
829 | if samples.airCompressorRun ~= nil then |
830 | if spec.consumersByFillTypeName ~= nil and spec.consumersByFillTypeName["AIR"] ~= nil then |
831 | local consumer = spec.consumersByFillTypeName["AIR"] |
832 | |
833 | if not consumer.doRefill then |
834 | if g_soundManager:getIsSamplePlaying(samples.airCompressorRun) then |
835 | g_soundManager:stopSample(samples.airCompressorRun) |
836 | g_soundManager:playSample(samples.airCompressorStop) |
837 | end |
838 | else |
839 | if not g_soundManager:getIsSamplePlaying(samples.airCompressorRun) then |
840 | if samples.airCompressorStart ~= nil then |
841 | if not g_soundManager:getIsSamplePlaying(samples.airCompressorStart, 1.5*dt) and spec.brakeCompressor.playSampleRunTime == nil then |
842 | g_soundManager:playSample(samples.airCompressorStart) |
843 | spec.brakeCompressor.playSampleRunTime = g_currentMission.time + samples.airCompressorStart.duration |
844 | end |
845 | if not g_soundManager:getIsSamplePlaying(samples.airCompressorStart) then |
846 | spec.brakeCompressor.playSampleRunTime = nil |
847 | g_soundManager:stopSample(samples.airCompressorStart) |
848 | g_soundManager:playSample(samples.airCompressorRun) |
849 | end |
850 | else |
851 | g_soundManager:playSample(samples.airCompressorRun) |
852 | end |
853 | end |
854 | end |
855 | end |
856 | end |
857 | |
858 | -- random zsch sound |
859 | if spec.compressionSoundTime <= g_currentMission.time then |
860 | g_soundManager:playSample(samples.airRelease) |
861 | spec.compressionSoundTime = g_currentMission.time + math.random(10000, 40000) |
862 | end |
863 | |
864 | local isBraking = self:getDecelerationAxis() > 0 and self:getLastSpeed() > 1 |
865 | |
866 | -- brake zsch sound |
867 | if samples.compressedAir ~= nil then |
868 | if isBraking then |
869 | samples.compressedAir.brakeTime = samples.compressedAir.brakeTime + dt |
870 | else |
871 | if samples.compressedAir.brakeTime > 0 then |
872 | samples.compressedAir.lastBrakeTime = samples.compressedAir.brakeTime |
873 | samples.compressedAir.brakeTime = 0 |
874 | |
875 | g_soundManager:playSample(samples.compressedAir) |
876 | end |
877 | end |
878 | end |
879 | |
880 | -- blow off valve sound |
881 | if spec.motor.blowOffValveState > 0 then |
882 | if not g_soundManager:getIsSamplePlaying(samples.blowOffValve) then |
883 | g_soundManager:playSample(samples.blowOffValve) |
884 | end |
885 | else |
886 | if g_soundManager:getIsSamplePlaying(samples.blowOffValve) then |
887 | g_soundManager:stopSample(samples.blowOffValve) |
888 | end |
889 | end |
890 | |
891 | --brake sound |
892 | if samples.brake ~= nil then |
893 | if isBraking then |
894 | if not spec.isBrakeSamplePlaying then |
895 | g_soundManager:playSample(samples.brake) |
896 | spec.isBrakeSamplePlaying = true |
897 | end |
898 | else |
899 | if spec.isBrakeSamplePlaying then |
900 | g_soundManager:stopSample(samples.brake) |
901 | spec.isBrakeSamplePlaying = false |
902 | end |
903 | end |
904 | end |
905 | |
906 | -- reverse driving beep |
907 | if samples.reverseDrive ~= nil then |
908 | local reverserDirection = self.getReverserDirection == nil and 1 or self:getReverserDirection() |
909 | local isReverseDriving = self:getLastSpeed() > spec.reverseDriveThreshold and self.movingDirection ~= reverserDirection |
910 | if not g_soundManager:getIsSamplePlaying(samples.reverseDrive) and isReverseDriving then |
911 | g_soundManager:playSample(samples.reverseDrive) |
912 | elseif not isReverseDriving then |
913 | g_soundManager:stopSample(samples.reverseDrive) |
914 | end |
915 | end |
916 | end |
917 | |
918 | for state, gearLeverInterpolator in pairs(spec.activeGearLeverInterpolators) do |
919 | local currentInterpolation = gearLeverInterpolator.interpolations[gearLeverInterpolator.currentInterpolation] |
920 | if currentInterpolation ~= nil then |
921 | if gearLeverInterpolator.handsOnDelay > 0 then |
922 | gearLeverInterpolator.handsOnDelay = gearLeverInterpolator.handsOnDelay - dt |
923 | |
924 | if gearLeverInterpolator.handsOnDelay <= 0 then |
925 | local sample = gearLeverInterpolator.isGear and spec.samples.gearLeverStart or spec.samples.gearGroupLeverStart |
926 | if not g_soundManager:getIsSamplePlaying(sample) then |
927 | g_soundManager:playSample(sample) |
928 | end |
929 | end |
930 | |
931 | if self.setCharacterTargetNodeStateDirty ~= nil then |
932 | self:setCharacterTargetNodeStateDirty(state.node, true) |
933 | end |
934 | else |
935 | state.curRotation[1], state.curRotation[2], state.curRotation[3] = getRotation(state.node) |
936 | local limit = math.min |
937 | if currentInterpolation.speed < 0 then |
938 | limit = math.max |
939 | end |
940 | |
941 | state.curRotation[currentInterpolation.axis] = limit(state.curRotation[currentInterpolation.axis] + currentInterpolation.speed * dt, currentInterpolation.tar) |
942 | setRotation(state.node, state.curRotation[1], state.curRotation[2], state.curRotation[3]) |
943 | |
944 | if state.curRotation[currentInterpolation.axis] == currentInterpolation.tar then |
945 | gearLeverInterpolator.currentInterpolation = gearLeverInterpolator.currentInterpolation + 1 |
946 | if gearLeverInterpolator.currentInterpolation > #gearLeverInterpolator.interpolations then |
947 | spec.activeGearLeverInterpolators[state] = nil |
948 | |
949 | if gearLeverInterpolator.isResetPosition then |
950 | if self.resetCharacterTargetNodeStateDefaults ~= nil then |
951 | self:resetCharacterTargetNodeStateDefaults(state.node) |
952 | end |
953 | end |
954 | |
955 | local sample = gearLeverInterpolator.isGear and spec.samples.gearLeverEnd or spec.samples.gearGroupLeverEnd |
956 | if not g_soundManager:getIsSamplePlaying(sample) then |
957 | g_soundManager:playSample(sample) |
958 | end |
959 | end |
960 | end |
961 | |
962 | if self.setCharacterTargetNodeStateDirty ~= nil then |
963 | self:setCharacterTargetNodeStateDirty(state.node) |
964 | end |
965 | end |
966 | else |
967 | spec.activeGearLeverInterpolators[state] = nil |
968 | end |
969 | end |
970 | end |
971 | |
972 | if self.isServer then |
973 | if not self:getIsAIActive() and self:getTraveledDistanceStatsActive() then |
974 | if self.lastMovedDistance > 0.001 then |
975 | spec.traveledDistanceBuffer = spec.traveledDistanceBuffer + self.lastMovedDistance |
976 | if spec.traveledDistanceBuffer > 10 then |
977 | local stats = g_currentMission:farmStats(self:getOwnerFarmId()) |
978 | local distance = spec.traveledDistanceBuffer * 0.001 |
979 | stats:updateStats("traveledDistance", distance) |
980 | stats:updateStats(spec.statsTypeDistance, distance) |
981 | spec.traveledDistanceBuffer = 0 |
982 | end |
983 | end |
984 | end |
985 | end |
986 | end |
987 | end |
994 | function Motorized:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
995 | local spec = self.spec_motorized |
996 | |
997 | if self.isServer then |
998 | -- force stop of motor if player is far away from vehicle for a certain amount of time |
999 | if not g_currentMission.missionInfo.automaticMotorStartEnabled then |
1000 | if spec.isMotorStarted and not self:getIsAIActive() then |
1001 | |
1002 | local isEntered = self.getIsEntered ~= nil and self:getIsEntered() |
1003 | local isControlled = self.getIsControlled ~= nil and self:getIsControlled() |
1004 | |
1005 | if not isEntered and not isControlled then |
1006 | |
1007 | local isPlayerInRange = false |
1008 | |
1009 | for _, player in pairs(g_currentMission.players) do |
1010 | if player.isControlled then |
1011 | local distance = calcDistanceFrom(self.rootNode, player.rootNode) |
1012 | if distance < 250 then |
1013 | isPlayerInRange = true |
1014 | break |
1015 | end |
1016 | end |
1017 | end |
1018 | if not isPlayerInRange then |
1019 | for _, enterable in pairs(g_currentMission.enterables) do |
1020 | if enterable.spec_enterable ~= nil and enterable.spec_enterable.isControlled then |
1021 | local distance = calcDistanceFrom(self.rootNode, enterable.rootNode) |
1022 | if distance < 250 then |
1023 | isPlayerInRange = true |
1024 | break |
1025 | end |
1026 | end |
1027 | end |
1028 | end |
1029 | |
1030 | if isPlayerInRange then |
1031 | spec.motorStopTimer = spec.motorStopTimerDuration |
1032 | else |
1033 | spec.motorStopTimer = spec.motorStopTimer - dt |
1034 | if spec.motorStopTimer <= 0 then |
1035 | self:stopMotor() |
1036 | end |
1037 | end |
1038 | |
1039 | end |
1040 | end |
1041 | end |
1042 | |
1043 | if spec.isMotorStarted then |
1044 | self:updateMotorTemperature(dt) |
1045 | else |
1046 | --start motor if fuel was empty and got filled |
1047 | --also starts the motor again when we toggle the automatic motoro start option |
1048 | if g_currentMission.missionInfo.automaticMotorStartEnabled then |
1049 | if self.getIsControlled ~= nil and self:getIsControlled() then |
1050 | if self:getCanMotorRun() then |
1051 | self:startMotor(true) |
1052 | end |
1053 | end |
1054 | end |
1055 | end |
1056 | end |
1057 | |
1058 | if self.isClient then |
1059 | if self:getIsMotorStarted() then |
1060 | if spec.exhaustParticleSystems ~= nil then |
1061 | for _, ps in pairs(spec.exhaustParticleSystems) do |
1062 | local scale = MathUtil.lerp(spec.exhaustParticleSystems.minScale, spec.exhaustParticleSystems.maxScale, spec.motor:getEqualizedMotorRpm() / spec.motor:getMaxRpm()) |
1063 | ParticleUtil.setEmitCountScale(spec.exhaustParticleSystems, scale) |
1064 | ParticleUtil.setParticleLifespan(ps, ps.originalLifespan * scale) |
1065 | end |
1066 | end |
1067 | |
1068 | if spec.exhaustFlap ~= nil then |
1069 | local minRandom = -0.1 |
1070 | local maxRandom = 0.1 |
1071 | local angle = MathUtil.lerp(minRandom, maxRandom, math.random()) + spec.exhaustFlap.maxRot * (spec.motor:getEqualizedMotorRpm() / spec.motor:getMaxRpm()) |
1072 | angle = MathUtil.clamp(angle, 0, spec.exhaustFlap.maxRot) |
1073 | |
1074 | if spec.exhaustFlap.rotationAxis == 1 then |
1075 | setRotation(spec.exhaustFlap.node, angle, 0, 0) |
1076 | elseif spec.exhaustFlap.rotationAxis == 2 then |
1077 | setRotation(spec.exhaustFlap.node, 0, angle, 0) |
1078 | else |
1079 | setRotation(spec.exhaustFlap.node, 0, 0, angle) |
1080 | end |
1081 | end |
1082 | |
1083 | if spec.exhaustEffects ~= nil then |
1084 | for _, effect in pairs(spec.exhaustEffects) do |
1085 | local posX, posY, posZ = localToWorld(effect.effectNode, 0, 0.5, 0) |
1086 | if effect.lastPosition == nil then |
1087 | effect.lastPosition = {posX, posY, posZ} |
1088 | end |
1089 | |
1090 | local vx = (posX - effect.lastPosition[1]) * 10 |
1091 | local vy = (posY - effect.lastPosition[2]) * 10 |
1092 | local vz = (posZ - effect.lastPosition[3]) * 10 |
1093 | |
1094 | local ex, ey, ez = localToWorld(effect.effectNode, 0, 1, 0) |
1095 | vx, vy, vz = ex - vx, ey - vy + effect.upFactor, ez - vz |
1096 | |
1097 | local lx, ly, lz = worldToLocal(effect.effectNode, vx, vy, vz) |
1098 | |
1099 | local distance = MathUtil.vector2Length(lx, lz) |
1100 | lx, lz = MathUtil.vector2Normalize(lx, lz) |
1101 | |
1102 | ly = math.abs(math.max(ly, 0.01)) |
1103 | |
1104 | local xFactor = math.atan(distance / ly) * (1.2 + 2 * ly) |
1105 | local yFactor = math.atan(distance / ly) * (1.2 + 2 * ly) |
1106 | |
1107 | local xRot = math.atan(lz / ly) * xFactor |
1108 | local zRot = -math.atan(lx / ly) * yFactor |
1109 | |
1110 | effect.xRot = effect.xRot * 0.95 + xRot * 0.05 |
1111 | effect.zRot = effect.zRot * 0.95 + zRot * 0.05 |
1112 | |
1113 | local rpmScale = spec.motor:getEqualizedMotorRpm() / spec.motor:getMaxRpm() |
1114 | local scale = MathUtil.lerp(effect.minRpmScale, effect.maxRpmScale, rpmScale) |
1115 | |
1116 | setShaderParameter(effect.effectNode, "param", effect.xRot, effect.zRot, 0, scale, false) |
1117 | |
1118 | local r = MathUtil.lerp(effect.minRpmColor[1], effect.maxRpmColor[1], rpmScale) |
1119 | local g = MathUtil.lerp(effect.minRpmColor[2], effect.maxRpmColor[2], rpmScale) |
1120 | local b = MathUtil.lerp(effect.minRpmColor[3], effect.maxRpmColor[3], rpmScale) |
1121 | local a = MathUtil.lerp(effect.minRpmColor[4], effect.maxRpmColor[4], rpmScale) |
1122 | setShaderParameter(effect.effectNode, "exhaustColor", r, g, b, a, false) |
1123 | |
1124 | effect.lastPosition[1] = posX |
1125 | effect.lastPosition[2] = posY |
1126 | effect.lastPosition[3] = posZ |
1127 | end |
1128 | end |
1129 | |
1130 | spec.lastFuelUsageDisplayTime = spec.lastFuelUsageDisplayTime + dt |
1131 | if spec.lastFuelUsageDisplayTime > 250 then |
1132 | spec.lastFuelUsageDisplayTime = 0 |
1133 | spec.lastFuelUsageDisplay = spec.fuelUsageBuffer:getAverage() |
1134 | end |
1135 | |
1136 | spec.fuelUsageBuffer:add(spec.lastFuelUsage) |
1137 | end |
1138 | |
1139 | if spec.clutchCrackingTimeOut < g_time then |
1140 | if g_soundManager:getIsSamplePlaying(spec.samples.clutchCracking) then |
1141 | g_soundManager:stopSample(spec.samples.clutchCracking) |
1142 | end |
1143 | |
1144 | if spec.clutchCrackingGearIndex ~= nil then |
1145 | self:setGearLeversState(0, nil, 500) |
1146 | end |
1147 | |
1148 | if spec.clutchCrackingGroupIndex ~= nil then |
1149 | self:setGearLeversState(nil, 0, 500) |
1150 | end |
1151 | |
1152 | spec.clutchCrackingTimeOut = math.huge |
1153 | end |
1154 | |
1155 | -- display permanent fuel empty warning if automatic motor start is enabled |
1156 | if isActiveForInputIgnoreSelection then |
1157 | if g_currentMission.missionInfo.automaticMotorStartEnabled then |
1158 | if not self:getCanMotorRun() then |
1159 | local warning = self:getMotorNotAllowedWarning() |
1160 | if warning ~= nil then |
1161 | g_currentMission:showBlinkingWarning(warning, 2000) |
1162 | end |
1163 | end |
1164 | end |
1165 | |
1166 | Motorized.updateActionEvents(self) |
1167 | end |
1168 | end |
1169 | end |
258 | function Motorized.registerFunctions(vehicleType) |
259 | SpecializationUtil.registerFunction(vehicleType, "loadDifferentials", Motorized.loadDifferentials) |
260 | SpecializationUtil.registerFunction(vehicleType, "loadMotor", Motorized.loadMotor) |
261 | SpecializationUtil.registerFunction(vehicleType, "loadGears", Motorized.loadGears) |
262 | SpecializationUtil.registerFunction(vehicleType, "loadGearGroups", Motorized.loadGearGroups) |
263 | SpecializationUtil.registerFunction(vehicleType, "loadExhaustEffects", Motorized.loadExhaustEffects) |
264 | SpecializationUtil.registerFunction(vehicleType, "onExhaustEffectI3DLoaded", Motorized.onExhaustEffectI3DLoaded) |
265 | SpecializationUtil.registerFunction(vehicleType, "loadSounds", Motorized.loadSounds) |
266 | SpecializationUtil.registerFunction(vehicleType, "loadConsumerConfiguration", Motorized.loadConsumerConfiguration) |
267 | SpecializationUtil.registerFunction(vehicleType, "getIsMotorStarted", Motorized.getIsMotorStarted) |
268 | SpecializationUtil.registerFunction(vehicleType, "getIsMotorInNeutral", Motorized.getIsMotorInNeutral) |
269 | SpecializationUtil.registerFunction(vehicleType, "getCanMotorRun", Motorized.getCanMotorRun) |
270 | SpecializationUtil.registerFunction(vehicleType, "getStopMotorOnLeave", Motorized.getStopMotorOnLeave) |
271 | SpecializationUtil.registerFunction(vehicleType, "getMotorNotAllowedWarning", Motorized.getMotorNotAllowedWarning) |
272 | SpecializationUtil.registerFunction(vehicleType, "startMotor", Motorized.startMotor) |
273 | SpecializationUtil.registerFunction(vehicleType, "stopMotor", Motorized.stopMotor) |
274 | SpecializationUtil.registerFunction(vehicleType, "updateMotorProperties", Motorized.updateMotorProperties) |
275 | SpecializationUtil.registerFunction(vehicleType, "controlVehicle", Motorized.controlVehicle) |
276 | SpecializationUtil.registerFunction(vehicleType, "updateConsumers", Motorized.updateConsumers) |
277 | SpecializationUtil.registerFunction(vehicleType, "updateMotorTemperature", Motorized.updateMotorTemperature) |
278 | SpecializationUtil.registerFunction(vehicleType, "getMotor", Motorized.getMotor) |
279 | SpecializationUtil.registerFunction(vehicleType, "getMotorStartTime", Motorized.getMotorStartTime) |
280 | SpecializationUtil.registerFunction(vehicleType, "getMotorType", Motorized.getMotorType) |
281 | SpecializationUtil.registerFunction(vehicleType, "getMotorRpmPercentage", Motorized.getMotorRpmPercentage) |
282 | SpecializationUtil.registerFunction(vehicleType, "getMotorRpmReal", Motorized.getMotorRpmReal) |
283 | SpecializationUtil.registerFunction(vehicleType, "getMotorLoadPercentage", Motorized.getMotorLoadPercentage) |
284 | SpecializationUtil.registerFunction(vehicleType, "getMotorBlowOffValveState", Motorized.getMotorBlowOffValveState) |
285 | SpecializationUtil.registerFunction(vehicleType, "getMotorDifferentialSpeed", Motorized.getMotorDifferentialSpeed) |
286 | SpecializationUtil.registerFunction(vehicleType, "getConsumerFillUnitIndex", Motorized.getConsumerFillUnitIndex) |
287 | SpecializationUtil.registerFunction(vehicleType, "getAirConsumerUsage", Motorized.getAirConsumerUsage) |
288 | SpecializationUtil.registerFunction(vehicleType, "getTraveledDistanceStatsActive", Motorized.getTraveledDistanceStatsActive) |
289 | SpecializationUtil.registerFunction(vehicleType, "setGearLeversState", Motorized.setGearLeversState) |
290 | SpecializationUtil.registerFunction(vehicleType, "generateShiftAnimation", Motorized.generateShiftAnimation) |
291 | SpecializationUtil.registerFunction(vehicleType, "getGearInfoToDisplay", Motorized.getGearInfoToDisplay) |
292 | SpecializationUtil.registerFunction(vehicleType, "setTransmissionDirection", Motorized.setTransmissionDirection) |
293 | SpecializationUtil.registerFunction(vehicleType, "getDirectionChangeMode", Motorized.getDirectionChangeMode) |
294 | SpecializationUtil.registerFunction(vehicleType, "getIsManualDirectionChangeAllowed", Motorized.getIsManualDirectionChangeAllowed) |
295 | SpecializationUtil.registerFunction(vehicleType, "getGearShiftMode", Motorized.getGearShiftMode) |
296 | SpecializationUtil.registerFunction(vehicleType, "stopVehicle", Motorized.stopVehicle) |
297 | end |
117 | function Motorized.registerMotorXMLPaths(schema, baseKey) |
118 | schema:register(XMLValueType.STRING, baseKey .. ".motor#type", "Motor type", "vehicle") |
119 | schema:register(XMLValueType.STRING, baseKey .. ".motor#startAnimationName", "Motor start animation", "vehicle") |
120 | schema:register(XMLValueType.INT, baseKey .. "#consumerConfigurationIndex", "Consumer configuration index", 1) |
121 | |
122 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#minRpm", "Min. RPM", 1000) |
123 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#maxRpm", "Max. RPM", 1800) |
124 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#minSpeed", "Min. driving speed", 1) |
125 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#maxForwardSpeed", "Max. forward speed") |
126 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#maxBackwardSpeed", "Max. backward speed") |
127 | |
128 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#accelerationLimit", "Acceleration limit", 2.0) |
129 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#brakeForce", "Brake force", 10) |
130 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#lowBrakeForceScale", "Low brake force scale", 0.5) |
131 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#lowBrakeForceSpeedLimit", "Low brake force speed limit (below this speed the lowBrakeForceScale is activated)", 1) |
132 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#torqueScale", "Scale factor for torque curve", 1) |
133 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#ptoMotorRpmRatio", "PTO to motor rpm ratio", 4) |
134 | |
135 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission#minForwardGearRatio", "Min. forward gear ratio") |
136 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission#maxForwardGearRatio", "Max. forward gear ratio") |
137 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission#minBackwardGearRatio", "Min. backward gear ratio") |
138 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission#maxBackwardGearRatio", "Max. backward gear ratio") |
139 | schema:register(XMLValueType.TIME, baseKey .. ".transmission#gearChangeTime", "Gear change time") |
140 | schema:register(XMLValueType.TIME, baseKey .. ".transmission#autoGearChangeTime", "Auto gear change time") |
141 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission#axleRatio", "Axle ratio", 1) |
142 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission#startGearThreshold", "Adjusts which gear is used as start gear", VehicleMotor.GEAR_START_THRESHOLD) |
143 | |
144 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor.torque(?)#normRpm", "Norm RPM (0-1)") |
145 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor.torque(?)#rpm", "RPM") |
146 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor.torque(?)#torque", "Torque") |
147 | |
148 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#rotInertia", "Rotation inertia", "Peak. motor torque / 600") |
149 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#dampingRateScale", "Scales motor damping rate", 1) |
150 | |
151 | schema:register(XMLValueType.FLOAT, baseKey .. ".motor#rpmSpeedLimit", "Motor rotation acceleration limit") |
152 | |
153 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission.forwardGear(?)#gearRatio", "Gear ratio") |
154 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission.forwardGear(?)#maxSpeed", "Gear ratio") |
155 | schema:register(XMLValueType.BOOL, baseKey .. ".transmission.forwardGear(?)#defaultGear", "Gear ratio") |
156 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.forwardGear(?)#name", "Gear name to display") |
157 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.forwardGear(?)#reverseName", "Gear name to display (if reverse direction is active)") |
158 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.forwardGear(?)#actionName", "Input Action to select this gear", "SHIFT_GEAR_SELECT_X") |
159 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission.backwardGear(?)#gearRatio", "Gear ratio") |
160 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission.backwardGear(?)#maxSpeed", "Gear ratio") |
161 | schema:register(XMLValueType.BOOL, baseKey .. ".transmission.backwardGear(?)#defaultGear", "Gear ratio") |
162 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.backwardGear(?)#name", "Gear name to display") |
163 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.backwardGear(?)#reverseName", "Gear name to display (if reverse direction is active)") |
164 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.backwardGear(?)#actionName", "Input Action to select this gear", "SHIFT_GEAR_SELECT_X") |
165 | |
166 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.groups#type", "Type of groups (powershift/default)", "default") |
167 | schema:register(XMLValueType.TIME, baseKey .. ".transmission.groups#changeTime", "Change time if default type", 0.5) |
168 | schema:register(XMLValueType.FLOAT, baseKey .. ".transmission.groups.group(?)#ratio", "Ratio while stage active") |
169 | schema:register(XMLValueType.BOOL, baseKey .. ".transmission.groups.group(?)#isDefault", "Is default stage", false) |
170 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.groups.group(?)#name", "Gear name to display") |
171 | schema:register(XMLValueType.STRING, baseKey .. ".transmission.groups.group(?)#actionName", "Input Action to select this group", "SHIFT_GROUP_SELECT_X") |
172 | |
173 | schema:register(XMLValueType.BOOL, baseKey .. ".transmission.directionChange#useGroup", "Use group as reverse change", false) |
174 | schema:register(XMLValueType.INT, baseKey .. ".transmission.directionChange#reverseGroupIndex", "Group will be activated while direction is changed", 1) |
175 | schema:register(XMLValueType.BOOL, baseKey .. ".transmission.directionChange#useGear", "Use gear as reverse change", false) |
176 | schema:register(XMLValueType.INT, baseKey .. ".transmission.directionChange#reverseGearIndex", "Gear will be activated while direction is changed", 1) |
177 | schema:register(XMLValueType.TIME, baseKey .. ".transmission.directionChange#changeTime", "Direction change time", 0.5) |
178 | |
179 | schema:register(XMLValueType.BOOL, baseKey .. ".transmission.manualShift#gears", "Defines if gears can be shifted manually", true) |
180 | schema:register(XMLValueType.BOOL, baseKey .. ".transmission.manualShift#groups", "Defines if groups can be shifted manually", true) |
181 | |
182 | schema:register(XMLValueType.L10N_STRING, baseKey .. ".transmission#name", "Name of transmission to display in the shop") |
183 | schema:register(XMLValueType.STRING, baseKey .. ".transmission#param", "Parameter to insert in transmission name") |
184 | |
185 | schema:register(XMLValueType.FLOAT, baseKey .. ".motorStartDuration", "Motor start duration", "Duration motor takes to start. After this time player can start to drive") |
186 | end |
1894 | function Motorized:updateConsumers(dt, accInput) |
1895 | local spec = self.spec_motorized |
1896 | |
1897 | local idleFactor = 0.5 |
1898 | local rpmPercentage = (spec.motor.lastMotorRpm - spec.motor.minRpm) / (spec.motor.maxRpm - spec.motor.minRpm) |
1899 | local rpmFactor = idleFactor + rpmPercentage * (1-idleFactor) |
1900 | local loadFactor = math.max(spec.smoothedLoadPercentage * rpmPercentage, 0) |
1901 | local motorFactor = 0.5 * ( (0.2*rpmFactor) + (1.8*loadFactor) ) |
1902 | |
1903 | local usageFactor = 1.5 -- medium |
1904 | if g_currentMission.missionInfo.fuelUsage == 1 then |
1905 | usageFactor = 1.0 -- low |
1906 | elseif g_currentMission.missionInfo.fuelUsage == 3 then |
1907 | usageFactor = 2.5 -- high |
1908 | end |
1909 | |
1910 | local damage = self:getVehicleDamage() |
1911 | if damage > 0 then |
1912 | usageFactor = usageFactor * (1 + damage * Motorized.DAMAGED_USAGE_INCREASE) |
1913 | end |
1914 | |
1915 | -- update permanent consumers |
1916 | for _,consumer in pairs(spec.consumers) do |
1917 | if consumer.permanentConsumption and consumer.usage > 0 then |
1918 | local used = usageFactor * motorFactor * consumer.usage * dt |
1919 | if used ~= 0 then |
1920 | consumer.fillLevelToChange = consumer.fillLevelToChange + used |
1921 | if math.abs(consumer.fillLevelToChange) > 1 then |
1922 | used = consumer.fillLevelToChange |
1923 | consumer.fillLevelToChange = 0 |
1924 | |
1925 | local fillType = self:getFillUnitLastValidFillType(consumer.fillUnitIndex) |
1926 | |
1927 | local stats = g_currentMission:farmStats(self:getOwnerFarmId()) |
1928 | stats:updateStats("fuelUsage", used) |
1929 | |
1930 | if self:getIsAIActive() then |
1931 | if fillType == FillType.DIESEL or fillType == FillType.DEF then |
1932 | if g_currentMission.missionInfo.helperBuyFuel then |
1933 | if fillType == FillType.DIESEL then |
1934 | local price = used * g_currentMission.economyManager:getCostPerLiter(fillType) * 1.5 |
1935 | stats:updateStats("expenses", price) |
1936 | |
1937 | g_currentMission:addMoney(-price, self:getOwnerFarmId(), MoneyType.PURCHASE_FUEL, true) |
1938 | end |
1939 | |
1940 | used = 0 |
1941 | end |
1942 | end |
1943 | end |
1944 | |
1945 | if fillType == consumer.fillType then |
1946 | self:addFillUnitFillLevel(self:getOwnerFarmId(), consumer.fillUnitIndex, -used, fillType, ToolType.UNDEFINED) |
1947 | end |
1948 | end |
1949 | |
1950 | if consumer.fillType == FillType.DIESEL or consumer.fillType == FillType.ELECTRICCHARGE or consumer.fillType == FillType.METHANE then |
1951 | spec.lastFuelUsage = used / dt * 1000 * 60 * 60 -- per hour |
1952 | elseif consumer.fillType == FillType.DEF then |
1953 | spec.lastDefUsage = used / dt * 1000 * 60 * 60 -- per hour |
1954 | end |
1955 | end |
1956 | end |
1957 | end |
1958 | |
1959 | -- update air consuming |
1960 | if spec.consumersByFillTypeName["AIR"] ~= nil then |
1961 | local consumer = spec.consumersByFillTypeName["AIR"] |
1962 | local fillType = self:getFillUnitLastValidFillType(consumer.fillUnitIndex) |
1963 | if fillType == consumer.fillType then |
1964 | local usage = 0 |
1965 | |
1966 | -- consume air on brake |
1967 | local direction = self.movingDirection * self:getReverserDirection() |
1968 | local forwardBrake = direction > 0 and accInput < 0 |
1969 | local backwardBrake = direction < 0 and accInput > 0 |
1970 | local brakeIsPressed = self:getLastSpeed() > 1.0 and (forwardBrake or backwardBrake) |
1971 | if brakeIsPressed then |
1972 | local delta = math.abs(accInput) * dt * self:getAirConsumerUsage() / 1000 |
1973 | self:addFillUnitFillLevel(self:getOwnerFarmId(), consumer.fillUnitIndex, -delta, consumer.fillType, ToolType.UNDEFINED) |
1974 | |
1975 | usage = delta / dt * 1000 -- per sec |
1976 | end |
1977 | |
1978 | --refill air fill unit if it is below given level |
1979 | local fillLevelPercentage = self:getFillUnitFillLevelPercentage(consumer.fillUnitIndex) |
1980 | if fillLevelPercentage < consumer.refillCapacityPercentage then |
1981 | consumer.doRefill = true |
1982 | elseif fillLevelPercentage == 1 then |
1983 | consumer.doRefill = false |
1984 | end |
1985 | |
1986 | if consumer.doRefill then |
1987 | local delta = consumer.refillLitersPerSecond / 1000 * dt |
1988 | self:addFillUnitFillLevel(self:getOwnerFarmId(), consumer.fillUnitIndex, delta, consumer.fillType, ToolType.UNDEFINED) |
1989 | |
1990 | usage = -delta / dt * 1000 -- per sec |
1991 | end |
1992 | |
1993 | spec.lastAirUsage = usage |
1994 | end |
1995 | end |
1996 | end |