-- Auto Transmission Type-E v0.8 by Vegetable Studio -- Please visit "https://www.patreon.com/vegetable_studio" for instructions -- Essentials local raw = ac.accessCarPhysics() local car = ac.getCar(0) local engine = ac.INIConfig.carData(0, 'engine.ini') local drivetrain = ac.INIConfig.carData(0, 'drivetrain.ini') local tyre = ac.INIConfig.carData(0, 'tyre.ini') local gearCount = car.gearCount local limiter = car.rpmLimiter local torque = ac.DataLUT11.load(engine:get('HEADER', 'POWER_CURVE', 'power.lut')) local idleRpm = engine:get('ENGINE_DATA', 'MINIMUM', 800) local clutchMaxTorque = drivetrain:get('CLUTCH', 'MAX_TORQUE', 600) local gearsFinalRatio = drivetrain:get('GEARS', 'FINAL', 4.4) local circumference = tyre:get('REAR', 'RADIUS', 0.32) * 2 * math.pi local rpmToKmh = circumference / 1000 * 60 local gearRatios = {} local topSpeeds = {} for i = 1, gearCount do gearRatios[i] = drivetrain:get('GEARS', 'GEAR_' .. tostring(i), 0) topSpeeds[i] = limiter * 0.99 / gearRatios[i] / gearsFinalRatio * rpmToKmh end local gear, speed, rpmEngine, throttle = 1, 0, 0, 0 -- Values to calculate speed target for auto shifting local throttleMap = ac.DataLUT11.parse('(|0.1=0.25|0.5=0.5|0.9=0.95)') local targetSpeedUp = 0 local targetSpeedDown = 0 -- Values for torque converter simulation local stallRpm = 2000 * math.round(idleRpm / 1000) local stallTorque = torque:get(stallRpm) local stallPower = stallRpm * stallTorque / 5250 local kFactor = math.round(stallRpm / math.sqrt(stallTorque), -1) local lockUpMap = ac.DataLUT11.parse('(|' .. tostring(stallRpm * 1 / gearsFinalRatio * rpmToKmh) .. '=0|'.. tostring((stallRpm * 1.25) / gearsFinalRatio * rpmToKmh) ..'=1|)') local speedLag = 0 local rpmWheel, rpmDiff = 0, 0 local tcPressure = 0 local tcLoad = 0 local torqueMult = 1 local torqueEngine = 0 local targetFinal = gearsFinalRatio local torqueConverter, lockUp = 0, 0 -- Values for shifting operation local gearLimitUp = false local gearLimitDown = false local delay = 0.75 local autoUp = 0 local autoDown = 0 local clutchUnlock = false local unlockTimer = 0 local shiftSpeed = 0.5 local unlockMap = ac.DataLUT11.parse('(|0=0|' .. tostring(shiftSpeed) .. '=1)') function script.update(dt) -- Disable H-shifter to stop overriding engaged gear if raw.isShifterSupported == true then raw.isShifterSupported = false end -- -- Update final ratio & top speeds when setup is changed, Not working at the moment -- if math.abs(raw.gearsFinalRatio - targetFinal) > 0.1 then -- gearsFinalRatio = raw.gearsFinalRatio -- for i = 1, gearCount do -- topSpeeds[i] = limiter * 0.99 / gearRatios[i] / gearsFinalRatio * rpmToKmh -- end -- end -- Essentials gear = math.max(1, car.gear) speed = math.round(car.poweredWheelsSpeed, 2) rpmEngine = math.max(raw.rpm, 1) throttle = throttleMap:get(raw.gas) torqueEngine = math.max(car.drivetrainTorque, 0) -- Torque converter simulation speedLag = math.applyLag(speedLag, speed, 0.95, dt) rpmWheel = math.max(speed / rpmToKmh * gearsFinalRatio * gearRatios[gear], 1) rpmDiff = math.max(rpmEngine - rpmWheel, 0) tcPressure = math.pow(rpmDiff / kFactor, 2) tcLoad = math.min(car.drivetrainPower / stallPower, 1) torqueMult = 1 + (rpmDiff / stallRpm) * (1 - math.min(rpmWheel / stallRpm, 1)) targetFinal = gearsFinalRatio * torqueMult torqueConverter = math.clamp((tcPressure / clutchMaxTorque * (1 - tcLoad) + math.sqrt(torqueEngine / clutchMaxTorque) * tcLoad), 0, 1) -- Clutch lock-up feature if gearRatios[gear] < 1 then lockUp = 1 else lockUp = lockUpMap:get(speedLag * gearRatios[gear]) end -- Calculate speed target for auto shifting targetSpeedUp = (topSpeeds[gear] - gearRatios[gear] * gearsFinalRatio) * throttle if gear > 1 then targetSpeedDown = (topSpeeds[gear - 1] - gearRatios[gear - 1] * gearsFinalRatio) * throttle - 5 else targetSpeedDown = 0 end -- Shifting mechanism if car.gear > 0 then if ac.isControllerGearUpPressed() then raw.gearUp = false gearLimitUp = true end if gearLimitUp and ac.isControllerGearUpPressed() == false then if speed > 1 then gearCount = math.min(car.gearCount, gearCount + 1) end gearLimitUp = false end if ac.isControllerGearDownPressed() then raw.gearDown = false gearLimitDown = true end if gearLimitDown and ac.isControllerGearDownPressed() == false then if speed > 1 then gearCount = math.max(1, gearCount - 1) else raw.gearDown = true end gearLimitDown = false end if speed > targetSpeedUp and gear < gearCount then autoUp = autoUp + dt autoDown = 0 elseif (speed < targetSpeedDown and gear > 1 ) or (gear > gearCount and speed < topSpeeds[gear - 1]) then autoDown = autoDown + dt autoUp = 0 else autoUp = 0 autoDown = 0 end if autoUp > delay then raw.gearUp = true clutchUnlock = true autoUp = delay - 0.01 end if autoDown > delay then raw.gearDown = true clutchUnlock = true autoDown = delay - 0.01 end if clutchUnlock then unlockTimer = unlockTimer + dt lockUp = lockUp * unlockMap:get(unlockTimer) end if unlockTimer > shiftSpeed then clutchUnlock = false unlockTimer = 0 end end -- Actual physics override ac.setGearsFinalRatio(targetFinal) raw.clutch = torqueConverter + (1 - torqueConverter) * lockUp --Debug ac.debug("Shift Mode", 'D' .. gearCount) -- ac.debug("Current Gear", gear) -- ac.debug("Current Gear Ratio", gearRatios[gear]) -- ac.debug("Current Gear Top Speed", math.round(topSpeeds[gear])) -- ac.debug("Target Speed Up", math.round(targetSpeedUp)) -- ac.debug("Target Speed Down", math.round(targetSpeedDown)) -- ac.debug("Shift Threshold Up", math.round(autoUp, 1)) -- ac.debug("Shift Threshold Down", math.round(autoDown, 1)) -- ac.debug("K Factor", kFactor) -- ac.debug("Stator Pressure", math.round(tcPressure) .. ' Nm') -- ac.debug("Torque Multiplication", math.round(torqueMult, 2)) -- ac.debug("Clutch Lock-Up", math.round(lockUp * 100) .. '%') -- ac.debug("Torque Converter", math.round(torqueConverter, 2)) -- ac.debug("Slippage", math.round(((rpmEngine / rpmWheel) - 1) * 100) .. '%') -- ac.debug("Torque Output", math.round(torqueEngine * torqueMult) .. ' Nm') end