155 lines
5.7 KiB
Lua
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
|