485 lines
18 KiB
Lua
485 lines
18 KiB
Lua
|
|
local M = {}
|
|
M.__index = M
|
|
|
|
local SCR, SUB = "game", "nk_hud"
|
|
local RAD = 0.01745329251944444
|
|
|
|
-- Resolution independence: every screen-space number below is in taikonantoka's 640x480
|
|
-- pixels and is multiplied by K = screen width / 640 (a skin that reuses this script at
|
|
-- 960x720 ships the art 1.5x, so K = 1.5). Texture sizes (t.w / t.h) are already in screen
|
|
-- pixels and are never scaled. K is the integer 1 at 640 wide, so the native skin keeps
|
|
-- exactly the same (integer) arithmetic.
|
|
local K = tex.get_screen_width() / 640
|
|
K = math.tointeger(K) or K
|
|
|
|
-- dispconf.ini [演奏] (640x480 px, scaled by K below)
|
|
local C = {
|
|
combo_x = 55, combo_y = 158, combo_w = 20, combo_over100_w = 28, combo_over1000_w = 28,
|
|
cb_x = 278, cb_y = 83, cb_num_x = 292, cb_num_y = 85, cb_num_w = 32, cb_num_w1000 = 26,
|
|
roll_x = 245, roll_y = 31, roll_num_x = 230, roll_num_y = 30, roll_num_w = 28, roll_num_x100 = 238, roll_num_w100 = 26,
|
|
sg_x = 442, sg_y = 42, meter_x = 416, meter_y = 42, meter_grow = 6,
|
|
soul_x = 592, soul_y = 40,
|
|
}
|
|
for k, v in pairs(C) do C[k] = v * K end
|
|
-- 2P (skin_config game_p2_y 231 vs 1P 184*0.5 = 92): the 2P lane is the 1P lane mirrored about
|
|
-- y 237.5, so lane-attached parts (combo digits on the drum) move down P2_DY and the 1P HUD parts
|
|
-- above the lane (soul gauge, soul, roll / combo balloons) are mirrored to the bottom: y -> 475 - y,
|
|
-- balloons flipped vertically so their tails point at the 2P lane.
|
|
local P2_DY = 139 * K
|
|
local SCREEN_H = 475 * K -- mirror constant (not the screen height)
|
|
local BRIGHT_RISE = 20 * K -- combo_bright drifts up 20 px over its 250 ms
|
|
|
|
-- combo_bright spots (stack arrays in sub_40F6D0 @0x4171CF)
|
|
local BRIGHT_X = { -40, -30, 0, 30, 10, 40, -8, -38 }
|
|
local BRIGHT_Y = { 30, -15, -20, -20, 16, 16, 14, -20 }
|
|
local BRIGHT_T = { 0, 30, 100, 100, 160, 160, 250, 180 }
|
|
for i = 1, #BRIGHT_X do BRIGHT_X[i] = BRIGHT_X[i] * K; BRIGHT_Y[i] = BRIGHT_Y[i] * K end
|
|
|
|
local function trunc(v) if v >= 0 then return math.floor(v) else return math.ceil(v) end end
|
|
local function fade_out_alpha(k) return math.max(0, math.min(255, 255 + k)) end
|
|
|
|
local TC = {}
|
|
local function T(name)
|
|
local c = TC[name]
|
|
if c ~= nil then return c or nil end
|
|
local id = tex.get_texture(SCR .. "/" .. SUB .. "/" .. name)
|
|
local info = id and tex.get_texture_info(SUB, name)
|
|
if not (id and info) then TC[name] = false; return nil end
|
|
c = { id = id, w = info.width, h = info.height }
|
|
TC[name] = c
|
|
return c
|
|
end
|
|
|
|
local function now_ms(self)
|
|
local ok, v = pcall(tex.get_current_ms)
|
|
if ok and type(v) == "number" then return v end
|
|
return self.last_update or 0
|
|
end
|
|
|
|
-- centred draw, integer top-left like the round-1 textures (sub_431B30 / 431BF0)
|
|
local function draw_c(t, cx, cy, alpha, frame, blend, mirror)
|
|
if not t or (alpha and alpha <= 0) then return end
|
|
local p = { x = math.floor(cx - t.w / 2), y = math.floor(cy - t.h / 2), mirror = mirror }
|
|
if frame then p.frame = frame end
|
|
if alpha and alpha < 255 then p.fade = alpha / 255 end
|
|
if blend then p.blend = blend end
|
|
tex.draw_texture(t.id, p)
|
|
end
|
|
|
|
-- centred draw scaled by (s, s) (sub_431CC0 / 431DA0 / 432030)
|
|
local function draw_cs(t, cx, cy, s, alpha, frame, blend, mirror)
|
|
if not t or s <= 0 or (alpha and alpha <= 0) then return end
|
|
local p = { x = cx - t.w / 2, y = cy - t.h / 2, center = true, scale = s, mirror = mirror }
|
|
if frame then p.frame = frame end
|
|
if alpha and alpha < 255 then p.fade = alpha / 255 end
|
|
if blend then p.blend = blend end
|
|
tex.draw_texture(t.id, p)
|
|
end
|
|
|
|
-- centred draw with sx = 1, sy = s, y already moved so the bottom edge stays put
|
|
local function draw_sy(t, cx, cy, s, alpha, frame)
|
|
if not t or (alpha and alpha <= 0) then return end
|
|
local p = { x = cx - t.w / 2, y = cy - t.h * s / 2, y2 = (s - 1) * t.h, frame = frame }
|
|
if alpha and alpha < 255 then p.fade = alpha / 255 end
|
|
tex.draw_texture(t.id, p)
|
|
end
|
|
|
|
local function pop(t) -- 1 + 0.22 sin(1.2 t deg) for 150 ms (combo, roll digits)
|
|
if t > 150 or t < 0 then return 1.0 end
|
|
return math.sin(t * 1.2 * RAD) * 0.22 + 1.0
|
|
end
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
function M.new(player_num)
|
|
local self = setmetatable({}, M)
|
|
self.two = (player_num == 3)
|
|
self.solo2 = (player_num == 2) -- 2P playing alone, on the top lane
|
|
self.p = {}
|
|
for i = 1, 2 do
|
|
self.p[i] = { combo = 0, t_combo = -1e9, t10 = nil, t100 = nil,
|
|
roll = 0, roll_last = nil, roll_break = true, gauge = nil }
|
|
end
|
|
tex.load_folder(SCR, SUB)
|
|
return self
|
|
end
|
|
|
|
function M:st(pn)
|
|
return self.p[(pn == 2) and 2 or 1]
|
|
end
|
|
|
|
function M:dy(pn)
|
|
return (self.two and pn == 2) and P2_DY or 0
|
|
end
|
|
|
|
-- HUD y of a 1P part for player pn (2P: mirrored to the bottom HUD)
|
|
function M:hy(pn, y)
|
|
if self.two and pn == 2 then return SCREEN_H - y end
|
|
return y
|
|
end
|
|
|
|
function M:is_p2(pn) return self.two and pn == 2 end
|
|
|
|
function M:t2(pn, name)
|
|
if self:is_p2(pn) then return T(name .. "_2p") end
|
|
if self.solo2 then return T(name .. "_2pt") end
|
|
end
|
|
|
|
function M:update(current_ms)
|
|
self.last_update = current_ms
|
|
self.restart_st = self.restart_st or {}
|
|
if NK_RESTARTED and NK_RESTARTED(self.restart_st) then
|
|
for i = 1, 2 do
|
|
self.p[i] = { combo = 0, t_combo = -1e9, t10 = nil, t100 = nil,
|
|
roll = 0, roll_last = nil, roll_break = true, gauge = nil }
|
|
end
|
|
end
|
|
end
|
|
|
|
local function judged(self, pn, good)
|
|
local s = self:st(pn)
|
|
local n = now_ms(self)
|
|
s.roll_break = true
|
|
if not good then
|
|
s.combo = 0; s.t10 = nil; s.t100 = nil
|
|
return
|
|
end
|
|
s.combo = s.combo + 1
|
|
s.t_combo = n
|
|
if s.combo % 10 == 0 then s.t10 = n end
|
|
if s.combo % 100 == 0 then s.t100 = n end
|
|
end
|
|
|
|
function M:handle_good(pn) judged(self, pn, true) end
|
|
function M:handle_ok(pn) judged(self, pn, true) end
|
|
function M:handle_bad(pn) judged(self, pn, false) end
|
|
|
|
function M:handle_drumroll(pn)
|
|
local s = self:st(pn)
|
|
local n = now_ms(self)
|
|
if s.roll_break or not s.roll_last or n - s.roll_last >= 1550 then s.roll = 0 end
|
|
s.roll = s.roll + 1
|
|
s.roll_last = n
|
|
s.roll_break = false
|
|
end
|
|
|
|
function M:handle_gauge(pn, progress, is_clear, is_rainbow)
|
|
local s = self:st(pn)
|
|
s.gauge = { g = math.max(0, math.min(1, progress or 0)) * 100,
|
|
clear = is_clear and true or false, rainbow = is_rainbow and true or false }
|
|
end
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
-- Norma line. taikonantoka's gauge art has it at 80 % (the bar's red / yellow split at column 234 of
|
|
-- 298, i.e. 40 of 50 cells; the frame's dark-red step and the ノルマ label above it). The engine's
|
|
-- norma is 60 % on easy, 70 % on normal / hard, 80 % on oni / ura; in a dan course it is the soul
|
|
-- gauge exam's red value. Lua gets no difficulty here: the song select (YataiDON14 / Juuyon
|
|
-- song_select.lua) leaves the chosen course in NK_COURSE_BY_PLAYER[player], the dan background leaves
|
|
-- the exam's value in NK_DAN_RED. The art is cut at the line and drawn with it moved: 3 art px / %.
|
|
local NORMA_PCT = { [0] = 60, [1] = 70, [2] = 70, [3] = 80, [4] = 80 }
|
|
function M:norma_shift(pn)
|
|
local pct = 80
|
|
if NK_DAN_RED then pct = NK_DAN_RED
|
|
elseif type(NK_COURSE_BY_PLAYER) == "table" and NORMA_PCT[NK_COURSE_BY_PLAYER[pn]] then
|
|
pct = NORMA_PCT[NK_COURSE_BY_PLAYER[pn]]
|
|
end
|
|
-- whole cells (6 art px = 2 %), so the overlay's cell stripes stay in step
|
|
return 6 * math.floor((math.max(50, math.min(100, pct)) - 80) / 2 + 0.5)
|
|
end
|
|
|
|
-- art columns sx0..sx0+w of t, full height, drawn at art column dx; frame top-left (X, Y), u = texture px per art px
|
|
local function cols(t, u, sx0, w, dx, X, Y)
|
|
if not t or w <= 0 then return end
|
|
tex.draw_texture(t.id, { x = X + dx * u, y = Y, src = { x = sx0 * u, y = 0, width = w * u, height = t.h },
|
|
x2 = w * u - t.w })
|
|
end
|
|
-- dest art columns d0..d1 filled with src columns s0.. repeated in 60-px (10-cell) runs
|
|
local function tile(t, u, s0, s1, d0, d1, X, Y)
|
|
local run = math.min(60, s1 - s0)
|
|
local d = d0
|
|
while d < d1 and run > 0 do
|
|
local w = math.min(run, d1 - d)
|
|
cols(t, u, s0, w, d, X, Y)
|
|
d = d + w
|
|
end
|
|
end
|
|
|
|
local FRAME_COLS = { sg_1 = { 234, 242, 302 }, sg_2 = { 196, 242, 302 },
|
|
sg_1_2p = { 196, 242, 302 }, sg_2_2p = { 196, 242, 302 },
|
|
sg_1_2pt = { 234, 242, 302 }, sg_2_2pt = { 196, 242, 302 } }
|
|
local function draw_frame(t, key, cx, cy, sh)
|
|
if not t then return end
|
|
local c = FRAME_COLS[key]
|
|
if sh == 0 or not c then return draw_c(t, cx, cy) end
|
|
local m0, m1, R = c[1], c[2], c[3]
|
|
local u = t.w / 360
|
|
local X, Y = math.floor(cx - t.w / 2), math.floor(cy - t.h / 2)
|
|
cols(t, u, 0, 6, 0, X, Y)
|
|
if sh < 0 then cols(t, u, 6, m0 + sh - 6, 6, X, Y) else tile(t, u, 6, m0, 6, m0 + sh, X, Y) end
|
|
cols(t, u, m0, m1 - m0, m0 + sh, X, Y)
|
|
if sh < 0 then tile(t, u, m1, R, m1 + sh, R, X, Y) else cols(t, u, m1, R - m1 - sh, m1 + sh, X, Y) end
|
|
cols(t, u, R, 360 - R, R, X, Y)
|
|
end
|
|
|
|
-- bar (298 x 23 art), filled to w texture px: red 0..234 -> 0..split, yellow 234..298 -> split..298
|
|
local function draw_bar(t, x, y, w, sh, fade)
|
|
local u = t.w / 298
|
|
local sp, s0 = (234 + sh) * u, 234 * u
|
|
local function seg(src0, src1, d0, d1)
|
|
if d1 <= d0 or src1 <= src0 then return end
|
|
tex.draw_texture(t.id, { x = x + d0, y = y, src = { x = src0, y = 0, width = src1 - src0, height = t.h },
|
|
x2 = (d1 - d0) - t.w, fade = fade })
|
|
end
|
|
local r = math.min(w, sp)
|
|
seg(0, r * s0 / sp, 0, r)
|
|
if w > sp then seg(s0, s0 + (w - sp) * (t.w - s0) / (t.w - sp), sp, w) end
|
|
end
|
|
|
|
local function draw_rainbow(t, x, y, bar, sh, y0)
|
|
if not t then return end
|
|
local u = bar.w / 298
|
|
local s0, sp = 234 * u, (234 + sh) * u
|
|
local function seg(src0, src1, d0, d1)
|
|
if d1 <= d0 or src1 <= src0 then return end
|
|
tex.draw_texture(t.id, { x = x + d0, y = y, src = { x = 6 + src0, y = y0, width = src1 - src0, height = 34 },
|
|
x2 = (d1 - d0) - t.w, y2 = bar.h - t.h })
|
|
end
|
|
seg(0, s0, 0, sp)
|
|
seg(s0, bar.w, sp, bar.w)
|
|
end
|
|
|
|
local T8_FPS = 60
|
|
local FEVER_X0, FEVER_Y0 = -20, -120
|
|
local function t8_course(pn)
|
|
local pct = 80
|
|
if NK_DAN_RED then pct = NK_DAN_RED
|
|
elseif type(NK_COURSE_BY_PLAYER) == "table" and NORMA_PCT[NK_COURSE_BY_PLAYER[pn]] then
|
|
pct = NORMA_PCT[NK_COURSE_BY_PLAYER[pn]]
|
|
end
|
|
if pct < 65 then return "e" elseif pct < 75 then return "n" end
|
|
return "h"
|
|
end
|
|
|
|
function M:draw_gauge(pn)
|
|
local s = self:st(pn)
|
|
if not s.gauge then return end
|
|
local g = s.gauge.g
|
|
local n = trunc(now_ms(self))
|
|
local key = "t8g_" .. (self:is_p2(pn) and "katsu" or "don") .. "_" .. t8_course(pn) .. "_"
|
|
local fv = s.t8_fever
|
|
if g >= 100 then
|
|
if not (fv and fv.on) then fv = { on = true, t0 = n }; s.t8_fever = fv end
|
|
elseif fv and fv.on then
|
|
fv = { on = false, t0 = n }; s.t8_fever = fv
|
|
end
|
|
local cx, cy = C.sg_x, self:hy(pn, C.sg_y)
|
|
local f = fv and math.floor((n - fv.t0) * T8_FPS / 1000) or 0
|
|
local ff
|
|
if fv and fv.on then
|
|
f = f + 1
|
|
ff = f > 9 and 10 + (f - 10) % 24 or f
|
|
elseif fv and f < 12 then
|
|
ff = 34 + f
|
|
end
|
|
if not ff then
|
|
draw_c(T(string.format("%s%02d", key, math.max(0, math.min(50, trunc(g / 2))))), cx, cy)
|
|
return
|
|
end
|
|
-- the gauge's top-left (360 x 64 movie px, centred on (cx, cy)) + the fever canvas offset
|
|
local x = math.floor(cx - 180 * K + FEVER_X0 * K)
|
|
local y = math.floor(cy - 32 * K + FEVER_Y0 * K)
|
|
local body, glow = T(string.format("%sf%02d", key, ff)), T(string.format("%sa%02d", key, ff))
|
|
if body then tex.draw_texture(body.id, { x = x, y = y }) end
|
|
if glow then tex.draw_texture(glow.id, { x = x, y = y, blend = "additive" }) end
|
|
end
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
function M:draw_combo(s, n, dy)
|
|
local c = s.combo
|
|
local X, Y = C.combo_x, C.combo_y + dy
|
|
|
|
-- flower (drawn before the digits)
|
|
if c >= 100 and s.t100 then
|
|
local t = n - s.t100
|
|
local fl, fm = T("flower"), T("flower_m")
|
|
if t < 170 then
|
|
local sc = math.sin(t * 0.6588235294117647 * RAD) * 1.083333333333333
|
|
draw_cs(fl, X, Y, sc); draw_cs(fm, X, Y, sc)
|
|
elseif t < 1970 then
|
|
draw_c(fl, X, Y); draw_c(fm, X, Y)
|
|
elseif t < 2070 then
|
|
draw_c(fl, X, Y); draw_c(fm, X, Y, fade_out_alpha(trunc((t - 1970) * -2.55)))
|
|
elseif t < 4670 then
|
|
draw_c(fl, X, Y)
|
|
elseif t < 4770 then
|
|
draw_c(fl, X, Y, fade_out_alpha(trunc((t - 4670) * -2.55)))
|
|
end
|
|
end
|
|
|
|
if c < 10 then return end
|
|
local sc = pop(n - s.t_combo)
|
|
local dig, count, xat
|
|
if c < 100 then
|
|
dig, count = T("combo"), 2
|
|
xat = function(j) return 0.5 * C.combo_w + X - (j - 1) * C.combo_w end
|
|
elseif c < 1000 then
|
|
dig, count = T("combo_l"), 3
|
|
xat = function(j) return X + (2 - j) * C.combo_over100_w end
|
|
elseif c < 10000 then
|
|
dig, count = T("combo_l"), 4
|
|
xat = function(j) return C.combo_over1000_w * 1.5 + X - (j - 1) * C.combo_over1000_w end
|
|
elseif c < 100000 then
|
|
dig, count = T("combo_l"), 5
|
|
xat = function(j) return C.combo_over1000_w * 2 + X - (j - 1) * C.combo_over1000_w end
|
|
end
|
|
if dig then
|
|
for j = 1, count do
|
|
local d = (c % (10 ^ j)) // (10 ^ (j - 1))
|
|
-- centre y = Y - (s*h/2 - h/2): the digit grows upwards from its bottom edge
|
|
draw_sy(dig, xat(j), Y - (sc * dig.h * 0.5 - dig.h * 0.5), sc, nil, math.floor(d))
|
|
end
|
|
end
|
|
|
|
if c >= 100 then
|
|
local b = T("combo_bright")
|
|
local t = n % 500
|
|
for i = 1, 8 do
|
|
local t0 = BRIGHT_T[i]
|
|
if t >= t0 and t < t0 + 250 then
|
|
local tt = t - t0
|
|
draw_cs(b, X + BRIGHT_X[i], Y + BRIGHT_Y[i] - tt / 250.0 * BRIGHT_RISE, 1.0 - tt / 375.0,
|
|
fade_out_alpha(trunc(tt / -250.0 * 255.0)), nil, "additive")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function M:draw_callout(s, n, pn)
|
|
if s.combo < 10 or not s.t10 then return end
|
|
local t = n - s.t10
|
|
if t >= 830 then return end
|
|
local bal2 = self:t2(pn, "combo_balloon") -- already drawn for the bottom HUD
|
|
local bal = bal2 or T("combo_balloon")
|
|
local mir = (self:is_p2(pn) and not bal2) and "vertical" or nil
|
|
local a, sc = 255, 1.0
|
|
if t <= 50 then a = trunc(t / 50.0 * 255.0)
|
|
elseif t < 200 then sc = math.sin((t - 50.0) * 180.0 / 150.0 * RAD) * 0.22 + 1.0
|
|
elseif t >= 730 then a = fade_out_alpha(trunc((t - 730.0) / -100.0 * 255.0)) end
|
|
if bal then
|
|
if sc ~= 1.0 then
|
|
-- the pop keeps the tail edge put (bottom for 1P, top for the flipped 2P balloon)
|
|
local grow = (sc * bal.h * 0.5 - bal.h * 0.5) * (self:is_p2(pn) and -1 or 1)
|
|
draw_cs(bal, C.cb_x, self:hy(pn, C.cb_y) - grow, sc, a, nil, nil, mir)
|
|
else
|
|
draw_c(bal, C.cb_x, self:hy(pn, C.cb_y), a, nil, nil, mir)
|
|
end
|
|
end
|
|
local num = self:t2(pn, "cb_num") or T("cb_num")
|
|
if not num then return end
|
|
local v = 10 * (s.combo // 10)
|
|
local w = (s.combo < 1000) and C.cb_num_w or C.cb_num_w1000
|
|
for i = 4, 0, -1 do
|
|
local p = 10 ^ i
|
|
if s.combo >= p then
|
|
draw_c(num, C.cb_num_x - w * i, self:hy(pn, C.cb_num_y), a, math.floor((v % (10 ^ (i + 1))) // p))
|
|
end
|
|
end
|
|
end
|
|
|
|
function M:draw_roll(s, n, pn)
|
|
if not s.roll_last or s.roll <= 0 then return end
|
|
local t = n - s.roll_last
|
|
if t >= 1550 then return end
|
|
local a = (t >= 1400) and fade_out_alpha(trunc((t - 1400.0) / -150.0 * 255.0)) or 255
|
|
local sc = pop(t)
|
|
-- 2P: the burst (and its 連打!!) is not flipped; it moves to the mirrored centre and the
|
|
-- digits keep their 1P offset from it, so number and 連打!! stay on one row
|
|
local ry = self:hy(pn, C.roll_y)
|
|
draw_c(T("roll_balloon"), C.roll_x, ry, a)
|
|
local num = T("roll")
|
|
if not num then return end
|
|
local cnt = s.roll
|
|
local function put(i, x)
|
|
local d = (cnt % (10 ^ (i + 1))) // (10 ^ i)
|
|
local ny = ry + (C.roll_num_y - C.roll_y)
|
|
local yc = num.h * 0.5 + ny - sc * (num.h * 0.5)
|
|
draw_sy(num, x, yc, sc, a, math.floor(d))
|
|
end
|
|
if cnt >= 100 then
|
|
for i = 0, 4 do
|
|
if 10 ^ i > cnt then break end
|
|
put(i, C.roll_num_x100 - i * C.roll_num_w100)
|
|
end
|
|
else
|
|
for i = 1, 0, -1 do
|
|
if 10 ^ i <= cnt then put(i, C.roll_num_x - C.roll_num_w * i) end
|
|
end
|
|
end
|
|
end
|
|
|
|
function M:draw_fore_pre()
|
|
local n = now_ms(self)
|
|
for pn = 1, (self.two and 2 or 1) do
|
|
self:draw_combo(self.p[pn], n, self:dy(pn))
|
|
end
|
|
end
|
|
|
|
function M:draw_fore_post()
|
|
local n = now_ms(self)
|
|
for pn = 1, (self.two and 2 or 1) do
|
|
local s = self.p[pn]
|
|
self:draw_roll(s, n, pn)
|
|
self:draw_callout(s, n, pn)
|
|
end
|
|
end
|
|
|
|
function M:destroy()
|
|
TC = {}
|
|
tex.unload_folder(SCR, SUB)
|
|
end
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
local function guard(f, ...)
|
|
local ok, err = pcall(f, ...)
|
|
if not ok then tex.log("nk_hud: " .. tostring(err)) end
|
|
end
|
|
|
|
function M.attach(obj, player_num)
|
|
if type(obj) ~= "table" or rawget(obj, "__nk_hud") then return obj end
|
|
local ok, hud = pcall(M.new, player_num)
|
|
if not ok then tex.log("nk_hud: " .. tostring(hud)); return obj end
|
|
rawset(obj, "__nk_hud", hud)
|
|
|
|
local function chain(name, pre, post)
|
|
local orig = obj[name]
|
|
rawset(obj, name, function(self, ...)
|
|
if pre then guard(pre, hud, ...) end
|
|
local r
|
|
if type(orig) == "function" then r = orig(self, ...) end
|
|
if post then guard(post, hud, ...) end
|
|
return r
|
|
end)
|
|
end
|
|
chain("update", M.update)
|
|
chain("handle_good", M.handle_good)
|
|
chain("handle_ok", M.handle_ok)
|
|
chain("handle_bad", M.handle_bad)
|
|
chain("handle_drumroll", M.handle_drumroll)
|
|
chain("handle_gauge", M.handle_gauge)
|
|
chain("draw_gauge", nil, M.draw_gauge) -- after anything the background draws there
|
|
chain("draw_fore", M.draw_fore_pre, M.draw_fore_post)
|
|
chain("destroy", nil, M.destroy)
|
|
return obj
|
|
end
|
|
|
|
function M.install(cls)
|
|
if type(cls) ~= "table" or rawget(cls, "__nk_hud_installed") then return end
|
|
rawset(cls, "__nk_hud_installed", true)
|
|
local orig_new = cls.new
|
|
cls.new = function(player_num, ...)
|
|
return M.attach(orig_new(player_num, ...), player_num)
|
|
end
|
|
end
|
|
|
|
return M
|