Files
YataiDONNijiiro/Scripts/game/gauge.lua
T
TaikoZhongandClaude Opus 5.5 48660a8b87 dan game: the soul gauge over the lane's top edge, as on the cabinet
The engine draws the lane after the gauge, and the lane's black top edge (y 276) hid the
cells' last six rows; the cabinet's gauge sits over it (cells down to y 281). The gauge
leaves a redraw (g_dan_gauge_redraw) that the dan background's draw_fore repeats, clipped
to that strip (y 276-288).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 21:01:01 +08:00

190 lines
8.8 KiB
Lua

-- This skin's gauge: the parent's script with render() replaced. The parent's render() is laid
-- out for its 87-cell flash gauge; this skin's 50 x 21 px grid fades each new cell in:
-- * gauge_cell_fade_in: the fading sprite is the new cell itself, so it sits on cell
-- length-1 (at length it left a dark gap cell before it)
-- * the clear mark sits gauge_clear_mark_offset cells (skin_config: 1, the cell edge) before
-- the exact clear fraction, not the parent's 87/60
-- The dan gauge is drawn as the cabinet's tamashii_gauge (see draw_dan below).
-- Everything else is the parent's file, loaded from its own copy.
-- the parent skin's copy of a script: the second match on package.path (the first is this file)
local function load_parent(name)
local seen = false
for tmpl in package.path:gmatch("[^;]+") do
local chunk = loadfile((tmpl:gsub("%?", name)))
if chunk then
if seen then return chunk end
seen = true
end
end
end
assert(load_parent("game/gauge"), "game/gauge: the parent skin has no gauge script")()
local function clamp(v, lo, hi) return math.max(lo, math.min(hi, v)) end
local parent_new = Gauge.new
function Gauge.new(is_2p, dan, string_diff, opts)
local self = parent_new(is_2p, dan, string_diff, opts)
local mark = tex.get_skin_config("gauge_clear_mark_offset")
self.clear_mark_offset = mark and mark.x
if dan then
local screen = (opts and opts.screen) or "game"
local p = (opts and opts.player_str and (opts.player_str .. "_")) or (is_2p and "2p_" or "1p_")
local function t(name) return tex.get_texture(screen .. "/gauge_dan/" .. name) end
self.cab = {
track_red = t("track_red"),
lamp = t(p .. "lamp"),
lamp_clear = t("lamp_clear"),
fade_clear = t("bar_fade_clear"),
}
end
return self
end
function Gauge:render(y, mirror, idx, points, previous_points, max_points, clear_points,
is_clear, is_rainbow, anim_active, anim_alpha, rainbow_fade, rainbow_frac, fire_frame)
-- blit(t, mirror, x, y, x2, fade, frame, index, scale, center, cap)
if not self.no_border then self:blit(self.border, mirror, nil, y, nil, nil, nil, idx) end
self:blit(self.unfilled, mirror, nil, y, nil, nil, nil, idx)
local units, bw = self.bar_units, self.bar_width
local length, solid, alpha, show_up, pending, fade_in =
self:cells(points, previous_points, max_points, anim_active, anim_alpha)
local clear_point = clamp(clear_points * units // max_points, 1, units)
-- the parent's art: the clear mark at the exact fraction minus 87/60 cells (x 897/967/1037 on
-- easy/normal/hard), not on a cell edge
local cpx = clear_points * units / max_points - (self.clear_mark_offset or units / 60)
if solid > 0 then
self:blit(self.bar, nil, nil, y,
math.min(solid, cpx) * bw - bw, nil, nil, idx)
end
-- first gold cell lights exactly when the gauge is cleared (not by a cell-count test:
-- on 87 cells 8000 -> 69.6 would light it a cell early/late vs. the clear state)
if is_clear and not (fade_in and pending and length == clear_point) then
self:blit(self.clear_transition, mirror, cpx * bw, y, nil, nil, nil, idx)
end
-- gold zone: cells clear_point .. solid-1, one cell wide piece so stretch is (n-1)*bw
local gold_x = (cpx + 1) * bw
if solid * bw >= gold_x + bw then
local gold_x2 = solid * bw - gold_x - bw
self:blit(self.clear_top, mirror, gold_x, y, gold_x2, nil, nil, idx)
self:blit(self.clear_bottom, nil, gold_x, y, gold_x2, nil, nil, idx)
end
if is_rainbow and rainbow_fade >= 0 then
local frame_a = math.floor(rainbow_frac) % 8
local frame_b = (frame_a + 1) % 8
local f = rainbow_frac - math.floor(rainbow_frac)
self:blit(self.rainbow, mirror, nil, y, nil, rainbow_fade, frame_a, idx)
self:blit(self.rainbow, mirror, nil, y, nil, rainbow_fade * f, frame_b, idx)
end
if show_up then
-- flash: the glow rides the leading edge of the fill; fade-in: the sprite is the new
-- cell itself (the fill stops one cell short until it lands)
local fx = (fade_in and length - 1 or length) * bw
if length == clear_point then
self:blit(self.clear_transition_fade, mirror, cpx * bw, y, nil, alpha, nil, idx)
elseif length > clear_point then
self:blit(self.clear_fade, nil, fx, y, nil, alpha, nil, idx)
else
self:blit(self.bar_fade, nil, fx, y, nil, alpha, nil, idx)
end
end
self:blit(self.overlay, mirror, nil, y, nil, 0.15, nil, idx, nil, nil, true)
if self.footer then self:blit(self.footer, nil, nil, y, nil, nil, nil, idx) end
self:draw_fire(y, idx, is_rainbow, fire_frame)
local label = self.art_tier + idx * 3
if is_clear then
self:blit(self.clear, nil, nil, y, nil, nil, nil, label)
self:blit(self.tamashii, nil, nil, y, nil, nil, nil, idx)
if is_rainbow and (fire_frame == 0 or fire_frame == 1 or fire_frame == 4 or fire_frame == 5) then
self:blit(self.tamashii_overlay, nil, nil, y, nil, 0.5, nil, idx, nil, nil, true)
end
else
self:blit(self.clear_dark, nil, nil, y, nil, nil, nil, label)
self:blit(self.tamashii_dark, nil, nil, y, nil, nil, nil, idx)
end
end
-- The dan gauge as the cabinet's tamashii_gauge draws it: the gold track (border), the red
-- track (track_red, gauge_bg) up to the threshold, the lit cells as one lamp stretched 21 px
-- per cell (lamp_clear, yellow, once the gauge reaches the threshold), the glow on a newly lit
-- cell, the cell separators at the cabinet's 103/255, then 魂: grey, white once cleared, and
-- in flames at full. The threshold comes from the dan exam (background dan_info sets
-- g_dan_gauge_border, in cells); without it, or without the cabinet pieces, the parent draws.
local CAB_CELL = 21
local CAB_TRACK = 20.88 -- gauge_bg: 160 px x 0.1305 per cell
local CAB_SEPARATOR = 103 / 255
local parent_draw_dan = Gauge.draw_dan
-- The cabinet draws the gauge over the lane; the engine draws the lane after it, so its top
-- edge (y 276, 184 px x 1.5) hides the cells' last rows. The gauge leaves a redraw for the
-- dan background's draw_fore (g_dan_gauge_redraw), which repeats it clipped to that strip.
local function draw_cab(self, border, points, previous_points, max_points, is_rainbow,
anim_active, anim_alpha, rainbow_fade, rainbow_frac, fire_frame)
local cab = self.cab
local function layer(t, x, x2, fade, frame, scale, center)
if t then
tex.draw_texture(t, { x = x, x2 = x2, fade = fade, frame = frame, scale = scale, center = center })
end
end
local length, solid, alpha, show_up = self:cells(points, previous_points, max_points, anim_active, anim_alpha)
local clear = length >= border
layer(self.border)
if border > 0 then layer(cab.track_red, nil, CAB_TRACK * border - 160) end
if solid > 0 then layer(clear and cab.lamp_clear or cab.lamp, nil, CAB_CELL * solid - 8) end
if is_rainbow and rainbow_fade >= 0 then
local frame_a = math.floor(rainbow_frac) % 8
local frame_b = (frame_a + 1) % 8
local f = rainbow_frac - math.floor(rainbow_frac)
layer(self.rainbow, nil, nil, rainbow_fade, frame_a)
layer(self.rainbow, nil, nil, rainbow_fade * f, frame_b)
end
if show_up and length > 0 then
layer(clear and cab.fade_clear or self.bar_fade, (length - 1) * CAB_CELL, nil, alpha)
end
layer(self.overlay, nil, nil, CAB_SEPARATOR)
if is_rainbow then
layer(self.fire, nil, nil, nil, fire_frame, 0.75, true)
layer(self.tamashii)
if fire_frame == 0 or fire_frame == 1 or fire_frame == 4 or fire_frame == 5 then
layer(self.tamashii_overlay, nil, nil, 0.5)
end
elseif clear then
layer(self.tamashii)
else
layer(self.tamashii_dark)
end
end
function Gauge:draw_dan(points, previous_points, max_points, is_rainbow,
anim_active, anim_alpha, rainbow_fade, rainbow_frac, fire_frame)
local cab = self.cab
local border = _G.g_dan_gauge_border
if not (cab and cab.track_red and cab.lamp and cab.lamp_clear and border) then
_G.g_dan_gauge_redraw = nil
return parent_draw_dan(self, points, previous_points, max_points, is_rainbow,
anim_active, anim_alpha, rainbow_fade, rainbow_frac, fire_frame)
end
draw_cab(self, border, points, previous_points, max_points, is_rainbow,
anim_active, anim_alpha, rainbow_fade, rainbow_frac, fire_frame)
_G.g_dan_gauge_redraw = function()
draw_cab(self, border, points, previous_points, max_points, is_rainbow,
anim_active, anim_alpha, rainbow_fade, rainbow_frac, fire_frame)
end
end