Skip to content

Commit fbc14d4

Browse files
committed
update
1 parent 42208c2 commit fbc14d4

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

cars_physics/turbo_map/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Turbo with a LUT
2+
3+
Instead of using gamma and reference RPM, this script allows turbos to use an RPM-boost LUT. Also includes original turbo implementation for reference.

cars_physics/turbo_map/script.lua

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
local data = ac.accessCarPhysics()
2+
local engineINI = ac.INIConfig.carData(car.index, 'engine.ini')
3+
4+
---Turbo acting similar to original Kunos turbo with CSP extensions. Only for illustrative purposes.
5+
---@return fun(dt: number)
6+
local DefaultTurbo = function (index)
7+
local section = 'TURBO_'..index
8+
local gamma = engineINI:get(section, 'GAMMA', 2)
9+
local rpmRef = engineINI:get(section, 'REFERENCE_RPM', 2000)
10+
local lagDown = engineINI:get(section, 'LAG_DN', 0.99)
11+
local lagUp = engineINI:get(section, 'LAG_UP', 0.99)
12+
local wastegate = engineINI:get(section, 'WASTEGATE', 0)
13+
local maxBoost = engineINI:get(section, 'MAX_BOOST', 1)
14+
local controllerMaxBoost = ac.getDynamicController('ctrl_turbo'..index..'.ini')
15+
local controllerWastegate = ac.getDynamicController('ctrl_wastegate'..index..'.ini')
16+
local gasCurve = engineINI:tryGetLut(section, 'EXT_GAS_CURVE')
17+
local spinDelay = engineINI:get(section, 'EXT_SPIN_DELAY', 0)
18+
local spinning = 0
19+
20+
return function (dt)
21+
if controllerMaxBoost then
22+
maxBoost = controllerMaxBoost()
23+
end
24+
if controllerWastegate then
25+
wastegate = controllerWastegate()
26+
end
27+
28+
local gas = data.gas
29+
if gasCurve then
30+
gas = gasCurve:get(gas)
31+
end
32+
33+
local intensity = math.pow(math.saturateN(data.rpm * gas / rpmRef), gamma)
34+
spinning = spinning + (intensity - spinning) * (intensity > spinning and lagUp or lagDown) * dt
35+
36+
if wastegate ~= 0 then
37+
local adjustedWastegate = wastegate * ac.getTurboUserWastegate(index)
38+
if maxBoost * spinning > adjustedWastegate then
39+
spinning = adjustedWastegate / maxBoost
40+
end
41+
end
42+
43+
local finalBoost = maxBoost * (spinning * (1 + spinDelay) - spinDelay)
44+
ac.overrideTurboBoost(index, finalBoost)
45+
46+
-- Of course final version shouldn’t have this debugging data printed:
47+
ac.debug('boost:'..index, finalBoost)
48+
end
49+
end
50+
51+
---Turbo using LUTs instead of gamma and reference RPM. Based on:
52+
---https://docs.google.com/document/d/1uBc-bHx3yiR905IoTuWzJJIMKHdtDtz1mMplsrRbyzc
53+
---@return fun(dt: number)
54+
local MapTurbo = function (index)
55+
local section = 'TURBO_'..index
56+
local gamma = engineINI:get(section, 'GAMMA', 2)
57+
local rpmRef = engineINI:get(section, 'REFERENCE_RPM', 2000)
58+
local lagDown = engineINI:get(section, 'LAG_DN', 0.99)
59+
local lagUp = engineINI:get(section, 'LAG_UP', 0.99)
60+
local wastegate = engineINI:get(section, 'WASTEGATE', 0)
61+
local maxBoost = engineINI:get(section, 'MAX_BOOST', 1)
62+
local controllerWastegate = ac.getDynamicController('ctrl_wastegate'..index..'.ini')
63+
local gasCurve = engineINI:tryGetLut(section, 'EXT_GAS_CURVE')
64+
local spinDelay = engineINI:get(section, 'EXT_SPIN_DELAY', 0)
65+
local setupItem = ac.getScriptSetupValue('MAP_TURBO_'..index) or refnumber(0)
66+
local spinning = 0
67+
68+
---@type ac.DataLUT11[]
69+
local mapNamesLut = engineINI:get(section, 'MAP_NAMES', '')
70+
local mapNames = {}
71+
if #mapNamesLut > 0 then
72+
local lut = ac.readDataFile(ac.getFolder(ac.FolderID.ContentCars)..'/'..ac.getCarID(car.index)..'/data/'..mapNamesLut)
73+
if lut and #lut > 0 then
74+
mapNames = table.map(table.map(lut:split('\n'), function (x)
75+
return x:split('|', 2, true)
76+
end), function (x)
77+
if #x ~= 2 then return end
78+
return x[1], tostring(x[2]) + 1
79+
end)
80+
end
81+
end
82+
83+
local maps = {}
84+
for i = 0, 999 do
85+
local lut = engineINI:tryGetLut(section, 'MAP_'..i)
86+
if not lut then break end
87+
table.insert(maps, lut)
88+
end
89+
90+
-- Silly trick for using user setting for switching between maps. First, set it to 100% (0 digit):
91+
ac.setTurboUserWastegate(index, 1)
92+
93+
return function (dt)
94+
95+
-- Continuing user setting trick here. Checking the current value:
96+
local currentUserSetting = ac.getTurboUserWastegate(index)
97+
if currentUserSetting ~= 1 then -- if it’s not 1, user changed it
98+
local selectedMap = math.round(currentUserSetting * 10) - 1 -- compute the new value based on whatever user has set
99+
ac.setTurboUserWastegate(index, 1) -- and reset it to 100%: this way default message wouldn’t be shown
100+
if maps[selectedMap + 1] then
101+
ac.setScriptSetupValue('MAP_TURBO_'..index, selectedMap)
102+
ac.setSystemMessage('Turbo', mapNames[selectedMap + 1] or ('Unnamed turbo map #'..(selectedMap + 1))) -- and we can add a custom message
103+
else
104+
ac.setSystemMessage('Turbo', 'No such map')
105+
end
106+
end
107+
108+
local map = maps[setupItem() + 1]
109+
if not map then return end
110+
111+
if map then
112+
maxBoost = map:get(data.rpm)
113+
end
114+
115+
if controllerWastegate then
116+
wastegate = controllerWastegate()
117+
end
118+
119+
local gas = data.gas
120+
if gasCurve then
121+
gas = gasCurve:get(gas)
122+
end
123+
124+
local intensity = math.pow(math.saturateN(data.rpm * gas / rpmRef), gamma)
125+
spinning = spinning + (intensity - spinning) * (intensity > spinning and lagUp or lagDown) * dt
126+
127+
if wastegate ~= 0 then
128+
local adjustedWastegate = wastegate * ac.getTurboUserWastegate(index)
129+
if maxBoost * spinning > adjustedWastegate then
130+
spinning = adjustedWastegate / maxBoost
131+
end
132+
end
133+
134+
local finalBoost = maxBoost * (spinning * (1 + spinDelay) - spinDelay)
135+
ac.overrideTurboBoost(index, finalBoost)
136+
137+
-- Of course final version shouldn’t have this debugging data printed:
138+
ac.debug('boost:'..index, finalBoost)
139+
ac.debug('setupItem():'..index, setupItem())
140+
-- ac.debug('setupItem.value:'..index, setupItem.value)
141+
end
142+
end
143+
144+
local turbos = {}
145+
for i, section in engineINI:iterate('TURBO') do
146+
if engineINI:tryGetLut(section, 'MAP_0') then
147+
turbos[i] = MapTurbo(i - 1)
148+
else
149+
turbos[i] = DefaultTurbo(i - 1)
150+
end
151+
end
152+
153+
function script.update(dt)
154+
for i = 1, #turbos do
155+
turbos[i](dt)
156+
end
157+
end

0 commit comments

Comments
 (0)