Advertisement
Guest User

Untitled

a guest
Aug 23rd, 2015
261
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 34.74 KB | None | 0 0
  1. -- This Source Code Form is subject to the terms of the bCDDL, v. 1.1.
  2. -- If a copy of the bCDDL was not distributed with this
  3. -- file, You can obtain one at http://beamng.com/bCDDL-1.1.txt
  4.  
  5. local M = {}
  6.  
  7. M._serialize = {
  8.     differentialMode = true,
  9.     manualShift = true,
  10.     autoClutch = true,
  11.     shifterMode = true,
  12.     activeModeIndex = true
  13. }
  14.  
  15. M.torque = 0
  16. M.gear = 0
  17. M.rpm = 0
  18. M.torqueTransmission = 0
  19. M.brake = 0
  20. M.throttle = 0
  21. M.wheels = {}
  22. M.wheelInfo = {}
  23. M.engineDisabled = false
  24. M.engineIgnition = true
  25. M.absPulse = 0
  26. M.fuelLeakRate = 0 -- L/sec
  27. M.fuel = 100
  28. M.fuelCapacity = 100
  29.  
  30. -- shifterMode = 0 : full manual
  31. -- shifterMode = 1 : manual with automatic clutch
  32. -- shifterMode = 2 : simple automatic
  33. -- shifterMode = 3 : real automatic
  34. M.shifterMode = 2 -- initial value needs to fit to the two modes below
  35. M.differentialMode = 0
  36. M.autoClutch = true
  37. M.manualShift = false
  38. M.shifterPosition = 0
  39. M.wheelCount = 0
  40. M.avgAV = 0
  41. M.axleAngle = 0
  42. M.driveshaftAngle = 0
  43. M.clutch = 1
  44. M.activeModeIndex = 1
  45.  
  46. local diffs = {}
  47. local diffCount = 1
  48. local diffTypeMap = {open = 0, lsd = 1}
  49. local diffStateMap = {open = 0, closed = 1, locked = 2}
  50. local avgDiffAV = 0
  51. local invDiffCount = 1
  52. local invWheelCount = 0
  53. local propWheelsCount = 0
  54. local engInertia = 0.1
  55. local invEngInertia = 10
  56. local halfInvEngInertia = invEngInertia * 0.5
  57. local engAV = 0
  58. local axleAV = 0
  59. local engFriction = 20
  60. local brakingCoef = 0
  61. local axleFriction = 50
  62. local clutchTimer = 0
  63. local clutchDuration = 0.5
  64. local clutchRatio = 1
  65. local clutchTorque = 0
  66. local invClutchDuration = 2
  67. local viscousCoupling
  68. local viscousCouplingOrig
  69. local engIdleAV = 0
  70. local engStallAV = 0
  71. local engineWorkPerUpdate = 0
  72. local torqueReactionNodes = nil
  73. local invBurnEfficiencyFuelDensity = 0
  74. local torsionCoef = 0
  75. local twist = 0
  76. local diffRatio = 2
  77. local invDiffRatio = 0.5
  78. local diffLimit = 0.75
  79. local avgPropAV = 0
  80. local minPropAV = 0
  81. local maxPropAV = 0
  82. local maxGearRatio = 0
  83. local gearChangedTimer = 0
  84. local gearChangeDelay = 0.5
  85. local idleTorque = 0
  86. local maxTorque = 0
  87. local checkEngineTimer = 0
  88. local engineDifferential = 1
  89. local allModes = {0,1,2,3}
  90. local autoModes = {2,3}
  91. local manualModes = {2,1,0}
  92. local activeModes = allModes
  93. local avgAVsmoother = newExponentialSmoothing(15)
  94. local smoothedAvgAV = 0
  95. local freeze = 0
  96. local ABSavgAV = 0
  97. local torqueRatio = 0
  98.  
  99. --Turbo stuff
  100. M.hasturbo = 1
  101. M.turborpm = 0
  102. M.maxturborpm = 0
  103. local curTurboRPM = 0
  104. local maxTurboRPM = 200000
  105. local turboInertia = 0
  106. local turboInertiaFactor = 4
  107. local turboPower = 0
  108. local turboPSI = 0
  109. local turboEngineRpmOperation = 3000
  110.  
  111. local function nop()
  112. end
  113.  
  114. esc = {update = nop, graphicsStep = nop, toggleESCMode = nop}
  115.  
  116. local function updateEngineState(dt)
  117.     local max = math.max
  118.  
  119.     local engine = v.data.engine
  120.     local torquediff
  121.     local torque = nil
  122.     local n, wd
  123.  
  124.     --Calc wheel sided engine AV
  125.     local wheelBasedEngAV = avgDiffAV * engine.gears[M.gear]
  126.  
  127.     local internal_clutchRatio = clutchRatio
  128.     -- manual vs automatic clutch
  129.     if M.autoClutch then
  130.         -- auto clutch
  131.         if clutchTimer > 0 then
  132.             clutchTimer = max(0, clutchTimer - dt)
  133.             internal_clutchRatio = math.min((clutchDuration - clutchTimer) * invClutchDuration, clutchRatio)
  134.         end
  135.     end
  136.  
  137.     --Calc torque from engine rpm
  138.     torque = engine.torqueCurve[math.floor(engAV * 9.5493)] or 0
  139.     torque = torque * M.throttle
  140.  
  141.     --Idle torque
  142.     if engAV < engIdleAV and M.fuel ~= 0 then
  143.         torque = max(torque, idleTorque)
  144.     end
  145.  
  146.     -- rpm limiter
  147.     if engAV > engine.maxAV then torque = 0 end
  148.  
  149.     -- Calculate engine's work
  150.     local dtT = dt * torque
  151.     engineWorkPerUpdate = engineWorkPerUpdate + dtT * (dtT * halfInvEngInertia + engAV)
  152.  
  153.     torquediff = (engAV - wheelBasedEngAV) * viscousCoupling
  154.     if math.abs(torquediff) > clutchTorque then
  155.         torquediff = fsign(torquediff) * clutchTorque
  156.     end
  157.     torquediff = torquediff * internal_clutchRatio
  158.  
  159.     -- Turbo code
  160.     if M.hasturbo then
  161.       turbotorque = 0
  162.       torqueRatio = 0
  163.       turboInertia = 0.000003 * turboInertiaFactor
  164.       turboPower = 0
  165.       turboPSI = 0
  166.  
  167.       turbotorque = turbotorque - curTurboRPM / maxTurboRPM
  168.  
  169.       if M.rpm >= turboEngineRpmOperation then
  170.         if curTurboRPM <= maxTurboRPM and input.throttle > 0.1 then
  171.           turbotorque = turbotorque + 1.5 * input.throttle * ((M.rpm - turboEngineRpmOperation) / (v.data.engine.maxRPM - turboEngineRpmOperation))
  172.         else
  173.           turbotorque = turbotorque + 0.1 * ((M.rpm - turboEngineRpmOperation) / (v.data.engine.maxRPM - turboEngineRpmOperation))
  174.         end
  175.       end
  176.  
  177.       curTurboRPM = curTurboRPM + dt * turbotorque / turboInertia
  178.  
  179.       M.turborpm = curTurboRPM
  180.       M.maxturborpm = maxTurboRPM
  181.  
  182.       -- 1 psi = 6% more power
  183.       turboPSI = curTurboRPM / 10000
  184.       torque = torque + (((turboPSI * 6) * torque) / 100)
  185.  
  186.       print(turboPSI)
  187.     end
  188.  
  189.     -- decouple when in neutral
  190.     if M.gear == 0 then
  191.         torquediff = 0
  192.         M.torque = 0
  193.         M.torqueTransmission = 0
  194.         engAV = max(engAV + dt * (torque - engFriction - brakingCoef * engAV) * invEngInertia, 0)
  195.         axleAV = avgDiffAV
  196.     else
  197.         M.torque = torquediff
  198.         -- Interesting place to add turbo code
  199.         M.torqueTransmission = torquediff * engine.gears[M.gear]
  200.         engAV = max(engAV + dt * (torque - torquediff - engFriction - brakingCoef * engAV) * invEngInertia, 0)
  201.         axleAV = engAV / engine.gears[M.gear]
  202.     end
  203. end
  204.  
  205. local function updateWheels(dt)
  206.     local abs = math.abs
  207.     local max = math.max
  208.     local min = math.min
  209.  
  210.     local n, wd
  211.  
  212.     local absABSavgAV = abs(ABSavgAV)
  213.     local ABSwheelCount = 0
  214.  
  215.     M.avgAV = 0
  216.     ABSavgAV = 0
  217.  
  218.     for n,wd in pairs(M.wheels) do
  219.         local w = wd.obj
  220.         wd.angularVelocity = w.angularVelocity
  221.         local wBrakingTorque = 0
  222.         local wheelAV = wd.angularVelocity * wd.wheelDir
  223.  
  224.         M.avgAV = M.avgAV + wheelAV
  225.  
  226.         -- braking
  227.         if M.brake > 0 then
  228.             wBrakingTorque = wd.brakeTorque *
  229.                         (min(M.brake, wd.brakeInputSplit) + max(M.brake - wd.brakeInputSplit, 0) * wd.brakeSplitCoef)
  230.             --anti-lock braking system (ABS)
  231.             if wd.enableABS then
  232.                 if abs(wd.angularVelocity) < absABSavgAV - wd.ABSthreshold then
  233.                     if wd.ABStorque == -1 then wd.ABStorque = wBrakingTorque end
  234.                     wd.ABStorque = math.max(wd.ABStorque - wd.ABSchangeRate, 0)
  235.                     wBrakingTorque = wd.ABStorque
  236.                     M.absPulse = bit.bxor(M.absPulse, 1)
  237.                 else
  238.                     ABSavgAV = ABSavgAV + wheelAV
  239.                     ABSwheelCount = ABSwheelCount + 1
  240.                     if wd.ABStorque ~= -1 then
  241.                         wd.ABStorque = math.min(wd.ABStorque + wd.ABSchangeRate, wBrakingTorque)
  242.                         wBrakingTorque = wd.ABStorque
  243.                     end
  244.                 end
  245.             else
  246.                 ABSavgAV = ABSavgAV + wheelAV
  247.                 ABSwheelCount = ABSwheelCount + 1
  248.             end
  249.             wd.lastTorqueMode = 1
  250.         else
  251.             ABSavgAV = ABSavgAV + wheelAV
  252.             ABSwheelCount = ABSwheelCount + 1
  253.             wd.ABStorque = -1
  254.             wd.lastTorqueMode = 0
  255.         end
  256.  
  257.         -- and the parking brake
  258.         if input.parkingbrake ~= 0 then
  259.             wd.lastTorqueMode = 2
  260.             wBrakingTorque = max(wBrakingTorque, wd.parkingTorque * input.parkingbrake)
  261.         end
  262.  
  263.         w.brakingTorque = wd.brakePressureDelay:get(wBrakingTorque)
  264.         wd.torque = 0 -- prepare torque for propulsion
  265.     end
  266.  
  267.     --update the ESC, right now it might override certain brake actions (handbrake for example), if a car has no esc, this is a nop call
  268.     esc.update()
  269.  
  270.     M.avgAV = M.avgAV * invWheelCount
  271.     ABSavgAV = ABSavgAV / ABSwheelCount
  272.  
  273.     -- propulsion
  274.     local torque
  275.     local diff
  276.     local absTorqueTransmission = abs(M.torqueTransmission)
  277.     local absAxleAV = abs(axleAV)
  278.  
  279.     avgDiffAV = 0
  280.     for n,diff in pairs(diffs) do
  281.         local w1 = diff.w1
  282.         local w2 = diff.w2
  283.         local w1U = w1
  284.         local w2U = w2
  285.         local w1AV = w1.angularVelocity * w1.wheelDir
  286.         local w2AV = w2.angularVelocity * w2.wheelDir
  287.         local w1AVU = w1AV
  288.         local w2AVU = w2AV
  289.  
  290.         local absW1AV = abs(w1AV)
  291.         local absW2AV = abs(w2AV)
  292.         local w1torque = 0
  293.         local w2torque = 0
  294.         local w1torqueU = 0
  295.         local w2torqueU = 0
  296.  
  297.         if absW2AV < absW1AV then
  298.             w1AV, w2AV = w2AV, w1AV
  299.             absW1AV, absW2AV = absW2AV, absW1AV
  300.             w1, w2 = w2, w1
  301.         end
  302.  
  303.         avgDiffAV = avgDiffAV + w2AV -- Use max wheel speed as the axle's speed
  304.  
  305.         -- closed diff
  306.         if diff.state == 2 then
  307.             if absW2AV > absAxleAV then
  308.                 torque = min((absW2AV - absAxleAV), 1) * M.torqueTransmission * diff.engineTorqueCoef
  309.             else
  310.                 torque = M.torqueTransmission * diff.engineTorqueCoef
  311.             end
  312.  
  313.             local ltorque
  314.             diff.angle = diff.angle + (w1AVU - w2AVU) * dt
  315.             if abs(diff.angle) < 1 then
  316.                 local absangle = abs(diff.angle)
  317.                 ltorque = fsign(diff.angle) * absangle * absangle * diff.closedTorque
  318.             else
  319.                 local signangle = fsign(diff.angle)
  320.                 ltorque = signangle * diff.closedTorque
  321.                 diff.angle = signangle
  322.             end
  323.  
  324.             local absltorque = math.abs(ltorque)
  325.             local absTorque = math.abs(torque)
  326.             if absltorque < absTorque then
  327.                 if fsign(ltorque) ~= fsign(torque) then
  328.                     w1torqueU = torque
  329.                     w2torqueU = torque + fsign(ltorque) * absltorque * 2
  330.                 else
  331.                     w1torqueU = torque - fsign(ltorque) * absltorque * 2
  332.                     w2torqueU = torque
  333.                 end
  334.             else
  335.                 w1torqueU = -ltorque
  336.                 w2torqueU = ltorque
  337.             end
  338.         else
  339.             -- Open diffs
  340.             if absW2AV > absAxleAV then
  341.                 if absW2AV > absAxleAV + 1 then
  342.                     local coef = min((absW2AV - (absAxleAV + 1)), 1)
  343.                     torque = coef * absTorqueTransmission * diff.engineTorqueCoef
  344.                     w1torque = fsign(M.torqueTransmission) * torque
  345.                     w2torque = fsign(axleAV - w2AV) * torque
  346.                 else
  347.                     torque = (1 - (absW2AV - absAxleAV)) * M.torqueTransmission * diff.engineTorqueCoef
  348.                     w1torque = torque
  349.                     w2torque = torque
  350.                 end
  351.             else
  352.                 torque = M.torqueTransmission * diff.engineTorqueCoef
  353.                 w1torque = torque
  354.                 w2torque = torque
  355.             end
  356.             w1.torque = w1.torque + w1torque * w1.wheelDir
  357.             w2.torque = w2.torque + w2torque * w2.wheelDir
  358.  
  359.             -- LSD diffs
  360.             if diff.state ~= 0 then
  361.                 local ltorque
  362.                 diff.angle = diff.angle + (w1AVU - w2AVU) * dt
  363.                 if abs(diff.angle) < 1 then
  364.                     local absangle = abs(diff.angle)
  365.                     ltorque = fsign(diff.angle) * absangle * absangle * diff.closedTorque
  366.                 else
  367.                     local signangle = fsign(diff.angle)
  368.                     ltorque = signangle * diff.closedTorque
  369.                     diff.angle = 0
  370.                 end
  371.                 w1torqueU = -ltorque
  372.                 w2torqueU = ltorque
  373.             else
  374.                 diff.angle = 0
  375.             end
  376.         end
  377.         w1U.torque = w1U.torque + w1torqueU * w1U.wheelDir
  378.                     - fsign(w1U.angularVelocity) * min(abs(w1U.angularVelocity), 1) * axleFriction
  379.         w2U.torque = w2U.torque + w2torqueU * w2U.wheelDir
  380.                     - fsign(w2U.angularVelocity) * min(abs(w2U.angularVelocity), 1) * axleFriction
  381.  
  382.         w1U.obj.torque = w1U.torque
  383.         w2U.obj.torque = w2U.torque
  384.     end
  385.  
  386.     avgDiffAV = avgDiffAV * invDiffCount
  387.  
  388.     M.axleAngle = M.axleAngle + avgDiffAV * dt
  389.     M.driveshaftAngle = M.driveshaftAngle + avgDiffAV * dt * engineDifferential
  390.  
  391.     if v.data.engine then
  392.         updateEngineState(dt)
  393.     end
  394. end
  395.  
  396. local function disableEngine()
  397.     M.engineDisabled = true
  398.     engIdleAV = 0
  399. end
  400.  
  401. local function checkEngine()
  402.     if M.engineDisabled then return end
  403.  
  404.     -- engine dies when one of waterDamage nodes in water
  405.     local n
  406.     for _, n in ipairs(v.data.engine.waterDamage.nodes) do
  407.         if obj:inWater(n) then
  408.             disableEngine()
  409.             break
  410.         end
  411.     end
  412. end
  413.  
  414. local function simpleAutoGearbox(dt)
  415.     local engine = v.data.engine
  416.     local tmpCurGear = M.gear
  417.     gearChangedTimer = math.max( gearChangedTimer - dt, 0 )
  418.     -- automatic
  419.     --interpolate based on throttle between high/low ranges
  420.     local throttleCubed = M.throttle * M.throttle * M.throttle
  421.     local shiftDown = engine.lowShiftDownAV + (engine.highShiftDownAV - engine.lowShiftDownAV) * throttleCubed
  422.     local shiftUp   = engine.lowShiftUpAV + (engine.highShiftUpAV - engine.lowShiftUpAV) * throttleCubed
  423.  
  424.     --log('D', "drivetrain.simpleAutoGearbox", shiftDown, engIdleAV)
  425.  
  426.     if gearChangedTimer == 0 then
  427.         if engAV < shiftDown then
  428.             M.gear = M.gear - sign(M.gear)
  429.         end
  430.         if engAV > shiftUp then
  431.             M.gear = M.gear + sign(M.gear)
  432.         end
  433.     end
  434.  
  435.     -- neutral gear handling
  436.     if M.gear == 0 then
  437.         if input.throttle > 0 and smoothedAvgAV > -1 and tmpCurGear >=0 then
  438.             M.gear = 1
  439.         end
  440.  
  441.         if input.brake > 0 and smoothedAvgAV <= 0.15 and tmpCurGear <=0 then
  442.             M.gear = -1
  443.         end
  444.  
  445.         -- Control clutch to buildup engine RPM
  446.         if clutchRatio == 1 then
  447.             clutchRatio = math.min(math.max((engAV - engIdleAV)/(shiftDown - engIdleAV),0),1)
  448.         end
  449.     end
  450.  
  451.     M.gear = math.min(math.max(M.gear, -engine.revGearCount), engine.fwdGearCount)
  452.  
  453.     if M.gear ~= tmpCurGear then
  454.         gearChangedTimer = gearChangeDelay
  455.     end
  456. end
  457.  
  458. local function realAutoGearbox(dt)
  459.     clutchRatio = 1
  460.     gearChangedTimer = math.max( gearChangedTimer - dt, 0 )
  461.  
  462.     local engine = v.data.engine
  463.     local tmpCurGear = M.gear
  464.  
  465.     M.shifterPosition = math.max( -2, math.min(3, M.shifterPosition))
  466.  
  467.     if M.shifterPosition == 0 then
  468.         M.gear = 0
  469.         return
  470.     end
  471.  
  472.     if math.abs(M.shifterPosition) == 1 then
  473.         --interpolate based on throttle between high/low ranges
  474.         if gearChangedTimer == 0 then
  475.             local throttleCubed = M.throttle * M.throttle * M.throttle
  476.             local shiftDown = engine.lowShiftDownAV + (engine.highShiftDownAV - engine.lowShiftDownAV) * throttleCubed
  477.             local shiftUp   = engine.lowShiftUpAV + (engine.highShiftUpAV - engine.lowShiftUpAV) * throttleCubed
  478.  
  479.             if engAV < shiftDown then
  480.                 M.gear = M.gear - sign(M.gear)
  481.             end
  482.  
  483.             if engAV > shiftUp then
  484.                 M.gear = M.gear + sign(M.gear)
  485.             end
  486.  
  487.             if M.shifterPosition == 1 then M.gear = math.max(1, M.gear) end
  488.             if M.shifterPosition == -1 then M.gear = math.min(-1, M.gear) end
  489.             -- Control clutch to buildup engine RPM
  490.             if math.abs(M.gear) == 1 and clutchRatio == 1 then
  491.                 clutchRatio = math.min(math.max(engAV/shiftDown,0),1)
  492.             end
  493.         end
  494.     elseif M.shifterPosition == 3 then
  495.         M.gear = 1
  496.     elseif M.shifterPosition == 2 then
  497.         M.gear = 2
  498.     elseif M.shifterPosition == -2 then
  499.         M.gear = 0
  500.         M.brake = 1
  501.     end
  502.  
  503.     M.gear = math.min(math.max(M.gear, -engine.revGearCount), engine.fwdGearCount)
  504.  
  505.     if M.gear ~= tmpCurGear then
  506.         gearChangedTimer = gearChangeDelay
  507.     end
  508. end
  509.  
  510. local function updateEngine(dt)
  511.     local engine = v.data.engine
  512.  
  513.     --Update GUI engine RPM
  514.     M.rpm = engAV * 9.5493
  515.  
  516.     M.axleAngle = M.axleAngle % math.pi
  517.     M.driveshaftAngle = M.driveshaftAngle % math.pi
  518.  
  519.     M.throttle = input.throttle
  520.     M.brake = input.brake
  521.     clutchRatio = 1 - input.clutch
  522.  
  523.     -- Fuel consumption
  524.     M.fuel = M.fuel - engineWorkPerUpdate * invBurnEfficiencyFuelDensity - M.fuelLeakRate * dt
  525.     engineWorkPerUpdate = 0
  526.  
  527.     smoothedAvgAV = avgAVsmoother:get(M.avgAV)
  528.  
  529.     if M.fuel <= 0 then
  530.         M.fuel = 0
  531.         M.throttle = 0
  532.     end
  533.  
  534.     if M.manualShift then
  535.         if M.autoClutch then
  536.             if M.brake ~= 0 and engAV < engIdleAV  * 2 then
  537.                 clutchRatio = 0
  538.             end
  539.  
  540.             if engAV < engStallAV then
  541.                 clutchRatio = 0
  542.             end
  543.         end
  544.     else
  545.         -- driving backwards? - only with automatic shift - for obvious reasons ;)
  546.         if M.shifterMode == 2 and M.gear <= 0 and smoothedAvgAV <= 0 and freeze == 0 then
  547.             M.throttle = input.brake
  548.             M.brake = input.throttle
  549.         end
  550.     end
  551.  
  552.     -- check for engine disabling (every 0.3 sec)
  553.     checkEngineTimer = checkEngineTimer + dt
  554.     if checkEngineTimer > 2 then
  555.         checkEngineTimer = 0
  556.         checkEngine()
  557.     end
  558.  
  559.     if M.engineDisabled then
  560.         M.throttle = 0
  561.         M.rpm = 0
  562.     end
  563.  
  564.     local prevGear = M.gear
  565.     --transmission logic
  566.     if M.manualShift then
  567.         -- manual
  568.         M.shifterPosition = math.min( math.max(M.shifterPosition, -engine.revGearCount), engine.fwdGearCount )
  569.         M.gear = M.shifterPosition
  570.         if prevGear ~= M.gear and M.autoClutch then
  571.             clutchTimer = clutchDuration
  572.         end
  573.     else
  574.         if M.shifterMode == 2 then simpleAutoGearbox(dt)
  575.         elseif M.shifterMode == 3 then realAutoGearbox(dt)
  576.         end
  577.     end
  578.  
  579.     if freeze == 1 then
  580.         M.brake = 1
  581.         clutchRatio = 0
  582.         clutchTimer = 0
  583.         if not M.manualShift then
  584.             M.gear = 0
  585.         end
  586.     end
  587.  
  588.     M.clutch = 1 - clutchRatio
  589. end
  590.  
  591. local function disableDriveshaft()
  592.     axleFriction = 0
  593.     viscousCoupling = 0
  594. end
  595.  
  596. local function isDriveshaftDisabled()
  597.     return axleFriction == 0 and viscousCoupling == 0
  598. end
  599.  
  600. local function updateCounts()
  601.     local n,wd
  602.  
  603.     propWheelsCount = 0
  604.     M.wheelCount = 0
  605.     for n,wd in pairs(M.wheels) do
  606.         if wd.propulsed ~= 0 then
  607.             propWheelsCount = propWheelsCount + 1
  608.         end
  609.         M.wheelCount = M.wheelCount + 1
  610.     end
  611.  
  612.     if M.wheelCount ~= 0 then
  613.         invWheelCount = 1 / M.wheelCount
  614.     else
  615.         invWheelCount = 0
  616.     end
  617. end
  618.  
  619. local function updateDifferentials()
  620.     local wheelNames = {}
  621.  
  622.     -- Clear old diffs config state
  623.     for _,diff in pairs(diffs) do
  624.         diff.w1.obj.torque = 0
  625.         diff.w2.obj.torque = 0
  626.     end
  627.  
  628.     for _,wd in pairs(M.wheelInfo) do
  629.         wheelNames[wd.name] = M.wheels[wd.wheelID]
  630.     end
  631.  
  632.  
  633.     local totalEngCoef = 0
  634.  
  635.     -- Sum engine torque coefs
  636.     v.data.differentials = v.data.differentials or {}
  637.  
  638.     for _, diff in pairs(v.data.differentials) do
  639.         if wheelNames[diff.wheelName1] and wheelNames[diff.wheelName2] then
  640.             diff.engineTorqueCoef = diff.engineTorqueCoef or 1
  641.             totalEngCoef = totalEngCoef + diff.engineTorqueCoef
  642.         end
  643.     end
  644.  
  645.     -- Update diffs
  646.     local i = 0
  647.     diffs = {}
  648.     for _,diff in pairs(v.data.differentials) do
  649.         if wheelNames[diff.wheelName1] and wheelNames[diff.wheelName2] then
  650.             diffs[i] = {    w1 = wheelNames[diff.wheelName1] ,
  651.                             w2 = wheelNames[diff.wheelName2] ,
  652.                             dtype = diffTypeMap[string.lower(diff.type or "open")] ,
  653.                             closedTorque = diff.closedTorque ,
  654.                             state = diffStateMap[string.lower(diff.state or "open")] ,
  655.                             engineTorqueCoef = 0.5 * diff.engineTorqueCoef / totalEngCoef, --per diff wheel (0.5)
  656.                             angle = 0
  657.                         }
  658.             i = i + 1
  659.         end
  660.     end
  661.  
  662.     diffCount = i
  663.     if diffCount ~= 0 then
  664.         invDiffCount = 1 / diffCount
  665.     else
  666.         invDiffCount = 0
  667.     end
  668. end
  669.  
  670. local function beamBroke(id)
  671.     if not v.data.beams[id].name then return end
  672.     local k,ab,n,wd
  673.     local doUpdate = false
  674.     local brokenBeamName = v.data.beams[id].name
  675.  
  676.     for n,wd in pairs(M.wheels) do
  677.         if wd.axleBeams then
  678.             for k,ab in pairs(wd.axleBeams) do
  679.                 if ab == brokenBeamName then
  680.                     doUpdate = true
  681.                     local w = wd.obj
  682.                     w.torque = 0
  683.                     w.brakingTorque = 0
  684.                     M.wheels[n] = nil
  685.                     break
  686.                 end
  687.             end
  688.         end
  689.     end
  690.  
  691.     if v.data.engine then
  692.         if v.data.engine.onBeamBreakDisableEngine then
  693.             for k,ab in pairs(v.data.engine.onBeamBreakDisableEngine) do
  694.                 if ab == brokenBeamName then
  695.                     M.engineDisabled = true
  696.                     engIdleAV = 0
  697.                     break
  698.                 end
  699.             end
  700.         end
  701.  
  702.         if v.data.engine.onBeamBreakDisableDriveshaft then
  703.             for k,ab in pairs(v.data.engine.onBeamBreakDisableDriveshaft) do
  704.                 if ab == brokenBeamName then
  705.                     disableDriveshaft()
  706.                     break
  707.                 end
  708.             end
  709.         end
  710.  
  711.         if v.data.engine.fuelTankBeams then
  712.             for k,ab in pairs(v.data.engine.fuelTankBeams) do
  713.                 if ab == brokenBeamName then
  714.                     M.fuelLeakRate = M.fuelLeakRate + 1 / #v.data.engine.fuelTankBeams
  715.                     break
  716.                 end
  717.             end
  718.         end
  719.     end
  720.  
  721.     if doUpdate then
  722.         updateCounts()
  723.         updateDifferentials()
  724.     end
  725. end
  726.  
  727. local function updateWheelSlip(p)
  728.     if not p then return end
  729.     if not v.data.nodes[p.id1] then return end
  730.     local wheelID = v.data.nodes[p.id1].wheelID
  731.     if wheelID then
  732.         local wInfo = M.wheelInfo[wheelID]
  733.         wInfo.lastSlip = math.max(p.slipVel, wInfo.lastSlip)
  734.         -- Smoothed instant energy (E/dt)
  735.         wInfo.slipEnergy = 0.5 * (p.slipForce * p.slipVel + wInfo.slipEnergy)
  736.         wInfo.contactMaterialID1 = p.materialID1
  737.         wInfo.contactMaterialID2 = p.materialID2
  738.         wInfo.contactDepth = math.max (p.depth, wInfo.contactDepth)
  739.         wInfo.downForceRaw = wInfo.downForceRaw - p.normalForce
  740.     end
  741. end
  742.  
  743. local function graphicsStepLocal()
  744.     esc.graphicsStep()
  745.  
  746.     for n,wd in pairs(M.wheelInfo) do
  747.         wd.contactMaterialID1 = -1
  748.         wd.contactMaterialID2 = -1
  749.         wd.lastSlip = 0
  750.         wd.slipEnergy = 0
  751.         wd.contactDepth = 0
  752.         wd.downForce = wd.downForceSmoother:get(wd.downForceRaw)
  753.         wd.downForceRaw = 0
  754.     end
  755.     M.absPulse = 0
  756.     --print((obj:getGroupPressure(0) - 101325) / 6894.757)
  757. end
  758.  
  759. local function shiftUp()
  760.     if M.shifterMode == 2 then
  761.         -- TODO: add automatic logic
  762.     end
  763.     M.shifterPosition = M.shifterPosition + 1
  764. end
  765.  
  766. local function shiftDown()
  767.     if M.shifterMode == 2 then
  768.         -- TODO: add automatic logic
  769.     end
  770.     M.shifterPosition = M.shifterPosition - 1
  771. end
  772.  
  773. local function setShifterMode(v)
  774.     v = v or 0
  775.  
  776.     wasDriveshaftDisabled = isDriveshaftDisabled()
  777.  
  778.     M.shifterPosition = M.gear
  779.  
  780.     M.activeModeIndex = v
  781.  
  782.     -- limits
  783.     if M.activeModeIndex > #activeModes then
  784.         M.activeModeIndex = 1
  785.     end
  786.     if M.activeModeIndex < 1 then
  787.         M.activeModeIndex = 1
  788.     end
  789.  
  790.     M.shifterMode = activeModes[M.activeModeIndex]
  791.  
  792.     -- now do the important things
  793.     if M.shifterMode == 0 then
  794.         -- full manual
  795.         gui.message("Manual", 5, "shiftermode")
  796.         M.autoClutch = false
  797.         M.manualShift = true
  798.     elseif M.shifterMode == 1 then
  799.         -- manual with automatic clutch
  800.         gui.message("Manual automatic clutch", 5, "shiftermode")
  801.         M.autoClutch = true
  802.         M.manualShift = true
  803.     elseif M.shifterMode == 2 then
  804.         -- simple automatic
  805.         gui.message("Arcade automatic", 5, "shiftermode")
  806.         M.autoClutch = true
  807.         M.manualShift = false
  808.         viscousCoupling = viscousCouplingOrig
  809.     elseif M.shifterMode == 3 then
  810.         -- real automatic
  811.         gui.message("Real automatic", 5, "shiftermode")
  812.         M.autoClutch = true
  813.         M.manualShift = false
  814.         viscousCoupling = viscousCouplingOrig
  815.         M.shifterPosition = 0
  816.     end
  817.  
  818.     -- if not automatic
  819.     if M.shifterMode < 2 then
  820.         viscousCoupling = clutchTorque / maxGearRatio
  821.     end
  822.  
  823.     if wasDriveshaftDisabled then
  824.         disableDriveshaft()
  825.     end
  826. end
  827.  
  828. local function toggleShifterMode()
  829.     setShifterMode(M.activeModeIndex + 1)
  830. end
  831.  
  832. local function shiftToGear(val)
  833.     -- when in full automatic, shifting only to -1, 1, 2 and N is allowed
  834.     -- TODO: lock -1 when moving forwards
  835.     if M.shifterMode == 2 or (M.shifterMode == 3 and val > 3) then
  836.         local manualModeIndex = nil
  837.         for modeIndex,mode in ipairs(activeModes) do
  838.             if mode == 0 then manualModeIndex = modeIndex break end -- if possible, choose full manual
  839.             if mode == 1 then manualModeIndex = modeIndex       end -- if not,  fallback to manual autoclutch
  840.         end
  841.         if manualModeIndex == nil then
  842.             gui.message("This vehicle has an automatic gearbox", 5, "shiftermode")
  843.             return
  844.         else
  845.             setShifterMode(manualModeIndex)
  846.             gui.message("Switched to manual shifting mode", 5, "shiftermode")
  847.         end
  848.     end
  849.     M.shifterPosition = val
  850. end
  851.  
  852. local function setDifferentialMode(v)
  853.     M.differentialMode = math.min(math.max(v or 0, 0), 2)
  854.  
  855.     for n,diff in pairs(diffs) do
  856.         if diff.dtype == diffTypeMap.lsd then
  857.             diff.state = M.differentialMode
  858.         end
  859.     end
  860. end
  861.  
  862. local function toggleDifferentialMode()
  863.     setDifferentialMode((M.differentialMode + 1) % 3)
  864. end
  865.  
  866. local function genDiffs()
  867.     diffs = {}
  868.  
  869.     if propWheelsCount ~= 2 then
  870.         return
  871.     end
  872.  
  873.     local diffWheels = {}
  874.     local wn = 0
  875.  
  876.     for n,wd in pairs(M.wheels) do
  877.         if wd.propulsed ~= 0 then
  878.             diffWheels[wn] = wd
  879.             wn = wn + 1
  880.         end
  881.     end
  882.  
  883.     if wn == 2 then
  884.         log('D', "drivetrain.genDiffs", "Found 2 propulsed wheels: generating Open Differential between them")
  885.         diffs[0] = {w1 = diffWheels[0], w2 = diffWheels[1], state = 0, engineTorqueCoef = 1, angle = 0}
  886.     end
  887. end
  888.  
  889. local function toggleESCMode()
  890.     esc.toggleESCMode()
  891. end
  892.  
  893. M.updateEngine = updateEngine
  894. M.updateWheels = updateWheels
  895. M.updateWheelSlip = updateWheelSlip
  896. M.graphicsStepLocal = graphicsStepLocal
  897. M.beamBroke = beamBroke
  898.  
  899. local function init()
  900.     engAV = 0
  901.     axleAV = 0
  902.     clutchTimer = 0
  903.     gearChangedTimer = 0
  904.     M.engineDisabled = false
  905.     M.engineIgnition = true
  906.     engineWorkPerUpdate = 0
  907.     M.gear = 0
  908.     M.shifterPosition = 0
  909.     M.fuelLeakRate = 0
  910.     M.torqueTransmission = 0
  911.     avgPropAV = 0
  912.     M.avgAV = 0
  913.     M.axleAngle = 0
  914.     M.driveshaftAngle = 0
  915.  
  916.     M.wheels = {}
  917.     M.wheelInfo = {}
  918.     local wheelNames = {}
  919.  
  920.     M.updateWheels = updateWheels
  921.  
  922.     avgAVsmoother:reset()
  923.  
  924.  
  925.     if not v or not v.data then
  926.         M.updateEngine = nop
  927.         M.updateWheels = nop
  928.         M.updateWheelSlip = nop
  929.         M.graphicsStepLocal = nop
  930.         M.beamBroke = nop
  931.         return
  932.     end
  933.  
  934.     if v.data.wheels and tableSize(v.data.wheels) > 0 then
  935.         M.wheels = shallowcopy(v.data.wheels)
  936.         M.wheelInfo = shallowcopy(v.data.wheels)
  937.     else
  938.         M.updateWheels = nop
  939.         M.updateWheelSlip = nop
  940.     end
  941.  
  942.     local pressureSmoothWindow = 0
  943.     local stepsForABSrate
  944.     if v.data.engine ~= nil then
  945.         stepsForABSrate = 2000 / (v.data.engine.ABSrate or 15)
  946.         pressureSmoothWindow = (v.data.engine.brakePressureDelay or 0) * 2000
  947.     end
  948.  
  949.     local wobj
  950.     for n,wd in pairs_safe(M.wheelInfo) do
  951.         wobj = obj:getWheel(wd.wheelID)
  952.         if wobj then
  953.             wd.lastTorqueMode = 0
  954.             M.wheelInfo[wd.wheelID].lastSlip = 0
  955.             M.wheelInfo[wd.wheelID].slipEnergy = 0
  956.             M.wheelInfo[wd.wheelID].contactMaterialID1 = -1
  957.             M.wheelInfo[wd.wheelID].contactMaterialID2 = -1
  958.             M.wheelInfo[wd.wheelID].contactDepth = 0
  959.             M.wheelInfo[wd.wheelID].downForceRaw = 0
  960.             M.wheelInfo[wd.wheelID].downForceSmoother = newExponentialSmoothing(60)
  961.             M.wheelInfo[wd.wheelID].slipEnergySmoother = newTemporalSmoothing()
  962.             M.wheelInfo[wd.wheelID].downForce = 0
  963.             M.wheelInfo[wd.wheelID].obj = wobj
  964.             M.wheels[wd.wheelID].obj = wobj
  965.             M.wheels[wd.wheelID].enableABS = M.wheels[wd.wheelID].enableABS or false
  966.             M.wheels[wd.wheelID].ABSthreshold = M.wheels[wd.wheelID].ABSthreshold or 5
  967.             M.wheels[wd.wheelID].brakeTorque = M.wheels[wd.wheelID].brakeTorque or 0
  968.             M.wheels[wd.wheelID].ABStorque = 0
  969.             M.wheels[wd.wheelID].ABSchangeRate = M.wheels[wd.wheelID].brakeTorque / stepsForABSrate
  970.             M.wheels[wd.wheelID].parkingTorque = M.wheels[wd.wheelID].parkingTorque or 0
  971.             M.wheels[wd.wheelID].torque = 0
  972.             M.wheels[wd.wheelID].angularVelocity = 0
  973.             M.wheels[wd.wheelID].brakeInputSplit = math.max(math.min(M.wheels[wd.wheelID].brakeInputSplit or 1, 1), 0)
  974.             M.wheels[wd.wheelID].brakeSplitCoef = math.max(math.min(M.wheels[wd.wheelID].brakeSplitCoef or 1, 1), 0)
  975.             M.wheels[wd.wheelID].brakePressureDelay = newExponentialSmoothing(pressureSmoothWindow)
  976.         else
  977.             M.wheels[wd.wheelID] = nil
  978.             M.wheelInfo[wd.wheelID] = nil
  979.             log('W', "drivetrain.init", 'Wheel "'..M.wheels[wd.wheelID].name..'" could not be added to drivetrain')
  980.         end
  981.     end
  982.  
  983.     updateCounts()
  984.  
  985.     if v.data.differentials == nil then
  986.         genDiffs()
  987.     else
  988.         updateDifferentials()
  989.     end
  990.  
  991.     if v.data.engine then
  992.         clutchDuration = v.data.engine.clutchDuration or 0.5
  993.         invClutchDuration = 1 / clutchDuration
  994.         engIdleAV = v.data.engine.idleAV
  995.         engStallAV = v.data.engine.stallAV or engIdleAV * 0.5
  996.         torsionCoef = v.data.engine.torsionCoef or 40
  997.         engInertia = v.data.engine.inertia or 0.1
  998.         engineDifferential = v.data.engine.differential
  999.  
  1000.         if v.data.engine.torqueReactionNodes_nodes then
  1001.             local t = v.data.engine.torqueReactionNodes_nodes
  1002.             if #t == 3 and v.data.nodes[t[1]] ~= nil and v.data.nodes[t[2]] ~= nil and v.data.nodes[t[3]] ~= nil then
  1003.                 torqueReactionNodes = {t[1], t[2], t[3]}
  1004.             else
  1005.                 torqueReactionNodes = nil
  1006.             end
  1007.         end
  1008.  
  1009.         if v.data.engine.transmissionType == "automatic" then
  1010.             activeModes = autoModes
  1011.         end
  1012.  
  1013.         if v.data.engine.transmissionType == "manual" then
  1014.             activeModes = manualModes
  1015.         end
  1016.  
  1017.         if engInertia ~= 0 then
  1018.             invEngInertia = 1 / engInertia
  1019.         else
  1020.             invEngInertia = 10
  1021.         end
  1022.         halfInvEngInertia = invEngInertia * 0.5
  1023.         -- fuel
  1024.         M.fuelCapacity = v.data.engine.fuelCapacity or 100
  1025.         M.fuel = M.fuelCapacity
  1026.         local fuelEnergyDensity = (v.data.engine.fuelEnergyDensity or 32) * 1000000 -- MJ/liter
  1027.         local burnEfficiency = v.data.engine.burnEfficiency or 1
  1028.         if fuelEnergyDensity * burnEfficiency ~= 0 then
  1029.             invBurnEfficiencyFuelDensity = 1 / (fuelEnergyDensity * burnEfficiency)
  1030.         else
  1031.             invBurnEfficiencyFuelDensity = 1
  1032.         end
  1033.         diffRatio = v.data.engine.diffRatio or 2
  1034.         invDiffRatio = 1 / diffRatio
  1035.         engFriction = v.data.engine.friction or v.data.engine.engineFriction or 20
  1036.         brakingCoef = v.data.engine.brakingCoef or 0
  1037.         if v.data.engine.brakingCoefRPS ~= nil then
  1038.             brakingCoef = v.data.engine.brakingCoefRPS / ( 2 * math.pi )
  1039.         end
  1040.         axleFriction = v.data.engine.axleFriction or v.data.engine.axelFriction or 0
  1041.  
  1042.         if v.data.engine.torqueCurve == nil then
  1043.             v.data.engine.torqueCurve = {}
  1044.         end
  1045.         idleTorque = v.data.engine.torqueCurve[v.data.engine.idleRPM] or 0
  1046.  
  1047.         maxGearRatio = v.data.engine.maxGearRatio or 0
  1048.         gearChangeDelay = v.data.engine.autoGearChangeDelay or 0.5
  1049.         maxTorque = v.data.engine.maxTorque or 0
  1050.  
  1051.         clutchTorque = v.data.engine.clutchTorque or v.data.engine.torqueLimit
  1052.         if not clutchTorque then
  1053.             clutchTorque = v.data.engine.maxTorque
  1054.             log('D', "drivetrain.init", "clutchTorque not set. Set clutchTorque = "..clutchTorque)
  1055.         end
  1056.  
  1057.         viscousCoupling = v.data.engine.viscousCoupling or viscousCouplingOrig
  1058.         if not viscousCoupling then
  1059.             viscousCoupling = (clutchTorque / maxGearRatio) or 3
  1060.             log('D', "drivetrain.init", "viscousCoupling not set. Set viscousCoupling = "..viscousCoupling)
  1061.         end
  1062.  
  1063.         viscousCouplingOrig = viscousCoupling
  1064.  
  1065.         setShifterMode(M.activeModeIndex)
  1066.     else
  1067.         M.updateEngine = nop
  1068.         viscousCoupling = viscousCoupling or 3
  1069.         viscousCouplingOrig = viscousCoupling
  1070.     end
  1071.  
  1072.     --Init the esc module in case we have an escConfig in the car's jbeam
  1073.     if v.data.escConfig then
  1074.         esc = require("esc")
  1075.         esc.init()
  1076.     end
  1077.  
  1078.     -- apply settings if available
  1079.     --[[ THIS IS NOT WORKING YET
  1080.     if settings then
  1081.         local shifterMode = settings.getValue('gameplayDefaultShifterMode')
  1082.         print('#########################################################')
  1083.         print(type(shifterMode))
  1084.         print(tostring(shifterMode))
  1085.         if shifterMode ~= nil then
  1086.             setShifterMode(shifterMode)
  1087.         end
  1088.     end
  1089.     --]]
  1090. end
  1091.  
  1092. local function reset()
  1093.     -- for now: call init again, as it does no harm
  1094.     init()
  1095. end
  1096.  
  1097. local function refill()
  1098.     if M.fuel < M.fuelCapacity then
  1099.         M.fuel = math.min(M.fuel + 2, M.fuelCapacity)
  1100.     end
  1101. end
  1102.  
  1103. local function onDeserialized()
  1104.     setShifterMode(M.activeModeIndex)
  1105. end
  1106.  
  1107. local function setFreezeMode(m)
  1108.     freeze = m
  1109. end
  1110.  
  1111. -- public interface
  1112. M.reset           = reset
  1113. M.init            = init
  1114. M.refill          = refill
  1115.  
  1116. M.shiftUp         = shiftUp
  1117. M.shiftDown       = shiftDown
  1118. M.shiftToGear     = shiftToGear
  1119. M.toggleShifterMode = toggleShifterMode
  1120. M.toggleESCMode = toggleESCMode
  1121. M.setShifterMode  = setShifterMode
  1122. M.onDeserialized  = onDeserialized
  1123. M.toggleDifferentialMode = toggleDifferentialMode
  1124. M.setFreezeMode   = setFreezeMode
  1125. return M
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement