Skip to content

Commit 1bf14fc

Browse files
committed
Fix conditions in libraries that could lead to errors
1 parent 7ad4d1f commit 1bf14fc

File tree

6 files changed

+843
-168
lines changed

6 files changed

+843
-168
lines changed

lib/konko-mods.lua

Lines changed: 152 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,102 @@ local AUTHOR = 'Sudospective'
2828

2929

3030
local POptions = {}
31+
local POToLower = {}
3132
local plrcount = 0
3233
for i, v in ipairs( GAMESTATE:GetEnabledPlayers() ) do
33-
POptions[i] = GAMESTATE:GetPlayerState(v):GetPlayerOptions('ModsLevel_Current')
34+
POptions[i] = GAMESTATE:GetPlayerState(v):GetPlayerOptions('ModsLevel_Song')
35+
end
36+
for k, v in pairs(PlayerOptions) do
37+
POToLower[k:lower()] = v
3438
end
3539

3640
local instant_tween = function(t) return 1 end
41+
42+
-- From the Mirin template. It just works? Fuck me... ~Sudo
43+
local function insertion_sort(t, l, h, c)
44+
for i = l + 1, h do
45+
local k = l
46+
local v = t[i]
47+
for j = i, l + 1, -1 do
48+
if c(v, t[j - 1]) then
49+
t[j] = t[j - 1]
50+
else
51+
k = j
52+
break
53+
end
54+
end
55+
t[k] = v
56+
end
57+
end
58+
local function merge(t, b, l, m, h, c)
59+
if c(t[m], t[m + 1]) then
60+
return
61+
end
62+
local i, j, k
63+
i = 1
64+
for j = l, m do
65+
b[i] = t[j]
66+
i = i + 1
67+
end
68+
i, j, k = 1, m + 1, l
69+
while k < j and j <= h do
70+
if c(t[j], b[i]) then
71+
t[k] = t[j]
72+
j = j + 1
73+
else
74+
t[k] = b[i]
75+
i = i + 1
76+
end
77+
k = k + 1
78+
end
79+
for k = k, j - 1 do
80+
t[k] = b[i]
81+
i = i + 1
82+
end
83+
end
84+
local magic_number = 12
85+
local function merge_sort(t, b, l, h, c)
86+
if h - l < magic_number then
87+
insertion_sort(t, l, h, c)
88+
else
89+
local m = math.floor((l + h) / 2)
90+
merge_sort(t, b, l, m, c)
91+
merge_sort(t, b, m + 1, h, c)
92+
merge(t, b, l, m, h, c)
93+
end
94+
end
95+
local function default_comparator(a, b) return a < b end
96+
local function flip_comparator(c) return function(a, b) return c(b, a) end end
97+
local function stable_sort(t, c)
98+
if not t[2] then return t end
99+
c = c or default_comparator
100+
local n = t.n
101+
local b = {}
102+
b[math.floor((n + 1) / 2)] = t[1]
103+
merge_sort(t, b, 1, n, c)
104+
return t
105+
end
106+
37107
local modlist = {}
38108
local mod_percents = {}
39109
local note_percents = {}
40110
local custom_mods = {}
41111
local default_mods = {}
42112
local active = {}
113+
local active_mods = {}
43114

44115
local function PlayerCount(num)
116+
if not num then return plrcount end
45117
plrcount = num
46118
for pn = 1, plrcount do
47119
mod_percents[pn] = {}
120+
mod_percents[pn].start_index = 0
48121
note_percents[pn] = {}
49122
custom_mods[pn] = {}
50123
default_mods[pn] = {}
51124
active[pn] = {}
52125
end
126+
return Mods
53127
end
54128

55129
PlayerCount(2)
@@ -79,43 +153,42 @@ local function ApplyMods(mod, percent, pn)
79153
end
80154
--]]
81155
-- TODO: Make sure this doesn't run on unnecessary frames. ~Sudo
156+
-- NOTE: Due to the nature of ModsLevel_Current, EVERY frame is a necessary frame. ~Sudo
157+
local function resolve_customs(mods, pn)
158+
for mod, percent in pairs(mods) do
159+
if custom_mods[pn][mod] ~= nil then
160+
local new_percs = {custom_mods[pn][mod].Function(percent, pn)}
161+
local new_mods = custom_mods[pn][mod].Return
162+
local t = {}
163+
for i = 1, #new_mods do
164+
t[new_mods[i]] = new_percs[i]
165+
end
166+
resolve_customs(t, pn)
167+
else
168+
mod_percents[pn][mod] = percent
169+
end
170+
end
171+
end
82172
local function ApplyMods()
83173
for pn = 1, plrcount do
84174
local modstring = ''
175+
resolve_customs(mod_percents[pn], pn)
85176
for mod, percent in pairs(mod_percents[pn]) do
86-
if custom_mods[pn][mod] ~= nil then
87-
local new_perc = {custom_mods[pn][mod].Function(percent, pn)}
88-
local new_mod = custom_mods[pn][mod].Return
89-
for i = 1, #new_perc do
90-
percent = new_perc[i]
91-
mod = new_mod[i]
92-
if POptions[pn][mod] then
93-
if mod:sub(2) == 'Mod' then
94-
POptions[pn][mod](POptions[pn], percent, 9e9)
95-
else
96-
POptions[pn][mod](POptions[pn], percent * 0.01, 9e9)
97-
end
98-
elseif mod:lower() == 'xmod' then
99-
modstring = modstring..'*-1 '..percent..mod:sub(1, 1):lower()..','
100-
elseif mod:sub(2):lower() == 'mod' then
101-
modstring = modstring..'*-1 '..mod:sub(1, 1):lower()..percent..','
102-
else
103-
modstring = modstring..'*-1 '..(percent)..' '..mod:lower()..','
104-
end
105-
end
106-
elseif mod then
177+
if mod_percents[pn][mod] and not custom_mods[pn][mod] then
107178
if POptions[pn][mod] then
108-
if mod:sub(2) == 'Mod' then
179+
if mod:sub(2, -1):lower() == 'mod' then
109180
POptions[pn][mod](POptions[pn], percent, 9e9)
110181
else
111182
POptions[pn][mod](POptions[pn], percent * 0.01, 9e9)
112183
end
184+
elseif POToLower[mod:lower()] and not mod:find('mod') then
185+
POToLower[mod](POptions[pn], percent * 0.01, 9e9)
113186
elseif mod:lower() == 'xmod' then
114187
modstring = modstring..'*-1 '..percent..mod:sub(1, 1):lower()..','
115188
elseif mod:sub(2):lower() == 'mod' then
116189
modstring = modstring..'*-1 '..mod:sub(1, 1):lower()..percent..','
117190
else
118-
modstring = modstring..'*-1 '..(percent)..' '..mod:lower()..','
191+
modstring = modstring..'*-1 '..percent..' '..mod:lower()..','
119192
end
120193
end
121194
end
@@ -136,13 +209,13 @@ local function ApplyNotes(beat, col, mod, percent, pn)
136209
end
137210

138211
local function UpdateMods()
139-
for i, m in ipairs(modlist) do
212+
for i, m in ipairs(active_mods) do
140213
for j, v in ipairs(m.Modifiers) do
141214
-- If the player where we're trying to access is not available, then don't even update.
142215
if m.Player and not POptions[m.Player] then break end
143216
local BEAT = std.BEAT
144217
local pn = m.Player
145-
if (BEAT >= m.Start and BEAT <= (m.Start + m.Length)) then
218+
if BEAT >= m.Start and BEAT < (m.Start + m.Length) then
146219
if m.Type == 'Blend' then
147220
-- Ease blending is a work in progress. Try to make sure two eases don't use the same mod.
148221
v[3] = v[3] or mod_percents[pn][v[2]] or 0
@@ -151,24 +224,25 @@ local function UpdateMods()
151224
active[pn][v[2]][v[4]] = m
152225
local perc = 0
153226
for n = 1, v[4] do
154-
local offset = (n > v[4]) and 1 or 0
155-
local cur_m = active[pn][v[2]][n]
156-
local cur_v1 = cur_m.Modifiers[j][1]
157-
local cur_v3 = cur_m.Modifiers[j][3]
158-
local cur_ease = cur_m.Ease((BEAT - cur_m.Start) / cur_m.Length) - offset
159-
if m.Length == 0 then cur_ease = cur_m.Ease(1) - offset end
160-
local cur_perc = cur_ease * (cur_v1 - cur_v3)
161-
if #active[pn][v[2]] == n then
162-
perc = perc + (cur_v3 + cur_perc)
227+
if n <= v[4] then
228+
local offset = (n < v[4]) and 1 or 0
229+
local cur_m = active[pn][v[2]][n]
230+
local cur_v1 = cur_m.Modifiers[j][1]
231+
local cur_v3 = cur_m.Modifiers[j][3]
232+
local cur_off = offset
233+
local cur_ease = cur_m.Ease((BEAT - cur_m.Start) * OFMath.oneoverx(cur_m.Length)) - cur_off
234+
if m.Length == 0 then cur_ease = cur_m.Ease(1) - cur_off end
235+
local cur_perc = cur_ease * (cur_v1 - cur_v3) + cur_v3
236+
perc = perc + cur_perc
163237
end
164238
end
165239
mod_percents[pn][v[2]] = perc
166240
elseif m.Type == 'Player' then
167241
v[3] = v[3] or mod_percents[pn][v[2]] or default_mods[pn][v[2]] or 0
168-
local ease = m.Ease((BEAT - m.Start) / m.Length)
242+
local ease = m.Ease((BEAT - m.Start) * OFMath.oneoverx(m.Length))
169243
if m.Length == 0 then ease = m.Ease(1) end
170-
local perc = ease * (v[1] - v[3])
171-
mod_percents[pn][v[2]] = perc + v[3]
244+
local perc = ease * (v[1] - v[3]) + v[3]
245+
mod_percents[pn][v[2]] = perc
172246
elseif m.Type == 'Note' then
173247
local notemod = v[4]..'|'..v[1]..'|'..v[2]
174248
v[5] = v[5] or note_percents[pn][notemod] or default_mods[pn][notemod] or 0
@@ -181,7 +255,7 @@ local function UpdateMods()
181255
local cur_m = active[pn][notemod][n]
182256
local cur_v3 = cur_m.Modifiers[j][3]
183257
local cur_v5 = cur_m.Modifiers[j][5]
184-
local cur_ease = cur_m.Ease((BEAT - cur_m.Start) / cur_m.Length) - offset
258+
local cur_ease = cur_m.Ease((BEAT - cur_m.Start) * OFMath.oneoverx(cur_m.Length)) - offset
185259
if m.Length == 0 then cur_ease = 1 end
186260
local cur_perc = cur_ease * (cur_v3 - cur_v5)
187261
if #active[pn][notemod] == n then
@@ -190,12 +264,13 @@ local function UpdateMods()
190264
end
191265
note_percents[pn][notemod] = perc
192266
end
193-
elseif BEAT > (m.Start + m.Length) then
267+
elseif BEAT >= (m.Start + m.Length) then
194268
if m.Type == 'Player' then
195269
v[3] = v[3] or mod_percents[pn][v[2]] or 0
196270
mod_percents[pn][v[2]] = m.Ease(1) * (v[1] - v[3]) + v[3]
197-
if v[4] and active[pn][v[2]] then
198-
--active[pn][v[2]][v[4]] = nil
271+
if v[4] and active[pn][v[2]][v[4]] then
272+
table.remove(active[pn][v[2]], v[4])
273+
v[4] = v[4] - 1
199274
end
200275
elseif m.Type == 'Note' then
201276
v[5] = v[5] or note_percents[pn][notemod] or 0
@@ -205,9 +280,6 @@ local function UpdateMods()
205280
--active[pn][notemod][v[6]] = nil
206281
end
207282
end
208-
if j == #m.Modifiers then
209-
--m.Modifiers = {}
210-
end
211283
end
212284
end
213285
end
@@ -228,11 +300,13 @@ local function Default(self, modtable)
228300
--printerr('Mods:Default')
229301
for pn = 1, plrcount do
230302
for i = 1, #modtable do
231-
table.insert(default_mods[pn], modtable[i])
303+
default_mods[pn][modtable[i][2]] = modtable[i][1]
304+
mod_percents[pn][modtable[i][2]] = modtable[i][1]
232305
end
233306
end
234-
local res = self:Insert(std.START, 0, instant_tween, modtable)
235-
return res
307+
--local res = self:Insert(std.START, 0, instant_tween, modtable)
308+
--return res
309+
return self
236310
end
237311
-- Define a new mod.
238312
local function Define(self, name, func, ret)
@@ -386,17 +460,43 @@ local function Mirin(self, t, offset, pn)
386460
return res
387461
end
388462

463+
local function GetPercents()
464+
return mod_percents
465+
end
466+
389467
FG[#FG + 1] = Def.Actor {
390468
ReadyCommand = function(self)
391469
for pn = 1, plrcount do
392470
if POptions[pn] then POptions[pn]:FromString('*-1 clearall') end
471+
for mod, percent in pairs(default_mods[pn]) do
472+
mod_percents[pn][mod] = percent
473+
end
474+
end
475+
self:sleep(self:GetEffectDelta()):queuecommand('Sort')
476+
end,
477+
SortCommand = function(self)
478+
local function compare(a, b)
479+
return a.Start < b.Start
393480
end
394-
-- Before we include the Note function, make sure we can actually call the required command.
395-
if std.PL[1].Player.AddNoteMod then Mods.Note = Note end
481+
modlist.n = #modlist
482+
stable_sort(modlist, compare)
396483
end,
397484
UpdateCommand = function(self)
485+
active_mods = {}
486+
for i = 1, #modlist do
487+
local mod = modlist[i]
488+
if std.BEAT >= mod.Start then
489+
table.insert(active_mods, mod)
490+
end
491+
end
398492
UpdateMods()
399493
ApplyMods()
494+
for i = #modlist, 1, -1 do
495+
local mod = modlist[i]
496+
if std.BEAT > mod.Start + mod.Length then
497+
table.remove(modlist, i)
498+
end
499+
end
400500
end
401501
}
402502

@@ -408,9 +508,11 @@ Mods = {
408508
FromFile = FromFile,
409509
Define = Define,
410510
Insert = Insert,
511+
--Note = Note,
411512
Mirin = Mirin,
412513
Exsch = Exsch,
413514
Default = Default,
515+
GetPercents = GetPercents,
414516
}
415517
Mods.__index = Mods
416518

0 commit comments

Comments
 (0)