Files
2026-09-30 15:29:22 -04:00

155 lines
5.7 KiB
Lua

-- 演奏スキップ — the cabinet's on-screen "hits remaining" cue, driven by the
-- engine's rule and pushed here through Background:handle_skip. Drawn from
-- draw_fore() so it lands in front of the whole lane/HUD.
local anim = require("anim/sampler")
local EnsoSkip = {}
EnsoSkip.__index = EnsoSkip
-- 1080p skin pixels; the child skin loads texture.json at scale 1.0.
local CARD_CY = 804 -- root placement of `skip_end` (y)
local NUM_HALF = 172 -- numeral local half-extent
local TEXT_CY = 418 -- banner origin after the reveal tween
local TEXT_TOP = -145 -- lang shape local min y
local TEXT_H = 288 -- lang shape local height
-- skip_card (sprite 35) labels: wait 0 / in 4 / on 9 / out 24, last frame 29.
local IN_F, ON_HOLD_F, OUT_F, END_F = 4, 23, 24, 29
function EnsoSkip.new()
local self = setmetatable({}, EnsoSkip)
self.card_clip = anim.safe("anim/skip_card")
self.panel_clip = anim.safe("anim/skip_panel")
self.count = 0 -- last count the engine reported
self.held = 0 -- kept across the reset fade-out
self.total = 10
self.skipped = false
self.phase = "off" -- off | in | out
self.card_f = IN_F
self.panel_f = 0
self.label = 0 -- frame of the current count_N label
self.last_ms = nil
self.tex = {}
return self
end
local function id(self, name)
local cached = self.tex[name]
if cached == nil then
cached = tex.get_texture("game/skip/" .. name) or false
self.tex[name] = cached
end
return cached or nil
end
-- Engine push, once per frame while the feature is armed.
function EnsoSkip:handle(state)
if not state then return end
local count = state.count or 0
self.total = state.total or 10
self.skipped = state.skipped or false
if count ~= self.count then
if count > 0 then
-- gotoAndPlay("count_N"): the panel restarts at that label
self.phase = "in"
self.label = self.panel_clip:label("count_" .. count) or 0
self.panel_f = self.label
if self.count == 0 then self.card_f = IN_F end -- skip_end "in"
else
-- back to 0 = the arcade reset (a hit on the playing drum)
self.phase = "out"
self.card_f = OUT_F
end
self.count = count
end
end
function EnsoSkip:update(current_ms)
local prev = self.last_ms
self.last_ms = current_ms
if not prev then return end
local df = anim.frames(current_ms - prev)
if df <= 0 then return end
if self.phase == "in" then
self.card_f = math.min(self.card_f + df, ON_HOLD_F)
-- each count_N segment stops on label+9; count_10 keeps playing through
-- the dim and the banner reveal and stops there
local stop = (self.count >= self.total) and (self.label + 25) or (self.label + 9)
self.panel_f = math.min(self.panel_f + df, stop)
elseif self.phase == "out" then
self.card_f = self.card_f + df
if self.card_f >= END_F then self.phase = "off" end
end
end
function EnsoSkip:draw()
if self.phase == "off" then return end
-- card alpha envelope, straight off sprite 35's own track
local a = self.card_clip:get("skip_end_panel", self.card_f, "a")
if a == nil then a = 1 end
if a <= 0 then return end
local panel = id(self, "panel")
if panel then tex.draw_texture(panel, { fade = a }) end
-- the numeral: before label+9 the OLD glyph is still on the card
local off = self.panel_f - self.label
local live = (self.count > 0) and self.count or self.held
local shown = live
if live > 1 and off < 9 then shown = live - 1 end
self.held = live
local digit = (shown > 0) and (self.total - shown) or -1 -- count_N shows (10 - N)
if digit >= 0 and digit <= 9 then
-- frame index i of number.png is the digit 9 - i (baked "9".."0")
local frame = 9 - digit
local sy, ty = 1, 0
if live > 1 then
-- every count_N bounce is the same nine rows; sample #14@1 at label+off
local bty, bsy = self.panel_clip:get("#14@1", 40 + off, "ty"),
self.panel_clip:get("#14@1", 40 + off, "sy")
if bsy then sy, ty = bsy, bty or 0 end
end
local num = id(self, "number")
if num then
local h = 2 * NUM_HALF * sy
tex.draw_texture(num, {
frame = frame, fade = a,
x = 0, y = CARD_CY + ty - NUM_HALF * sy - (CARD_CY - NUM_HALF),
y2 = h - 2 * NUM_HALF,
})
end
end
-- past this point only the fired skip draws anything
if not self.skipped then return end
local dim = id(self, "dim")
if dim then
local da = self.panel_clip:get("#32@2", self.panel_f, "a")
if da and da > 0 then tex.draw_texture(dim, { fade = da }) end
end
local banner = id(self, "text")
if banner then
local ty, sy, ba = self.panel_clip:get("lang_skip_text", self.panel_f, "ty"),
self.panel_clip:get("lang_skip_text", self.panel_f, "sy"),
self.panel_clip:get("lang_skip_text", self.panel_f, "a")
sy = sy or 1
ba = ba or 1
if ba > 0 then
-- texture.json parks the banner at its resting rect; re-anchor on TEXT_CY
local cy = (ty and (CARD_CY + ty)) or TEXT_CY
tex.draw_texture(banner, {
fade = ba,
y = (cy + TEXT_TOP * sy) - (TEXT_CY + TEXT_TOP),
y2 = TEXT_H * sy - TEXT_H,
})
end
end
end
return EnsoSkip