183 lines
6.9 KiB
Lua
183 lines
6.9 KiB
Lua
-- YataiDON-HSS override of PyTaikoGreen/background/bg_objects/bg_fever.lua
|
|
--
|
|
-- ROUND 12. The cabinet's gogo/clear backdrop is
|
|
-- enso/background/bg_fever_a_{01,02,03}.nulm: a 1920x540 stage (the lower half
|
|
-- of the screen, same anchor as bg_nomal) made of one static plate plus one to
|
|
-- three named `scroll_*_mc` strips, each sliding at a constant px/frame with a
|
|
-- fixed repeat period. There is no flipbook anywhere in it, so the whole rig
|
|
-- ports as: plate + per-strip {tile, period, px/s}, replayed here.
|
|
--
|
|
-- The measured numbers live in Scripts/background/bg_data/bg_fever.lua,
|
|
-- generated by scratchpad/r12bg/bgfever.py. If that table is missing this
|
|
-- falls back to drawing the static plate only -- never to the parent's art,
|
|
-- because Graphics/background/bg_fever/* is fully ours (every texture name the
|
|
-- generated id map declares is either a shipped layer or an 8x8 transparent
|
|
-- stub).
|
|
local ok, DATA = pcall(require, "background/bg_data/bg_fever")
|
|
if not ok or type(DATA) ~= "table" then DATA = {} end
|
|
-- per-element replay of the cabinet movie (koi, fans, tops... each on its own
|
|
-- loop) when bg_data/bg_anim/bg_fever_N.lua has been exported; the layer lists
|
|
-- above stay as the fallback. The rise/fall wipe is still this file's fade.
|
|
local ok_anim, BGAnim = pcall(require, "background/bg_objects/bg_anim")
|
|
if not ok_anim or type(BGAnim) ~= "table" then BGAnim = nil end
|
|
|
|
local ArcadeBGFever = {}
|
|
ArcadeBGFever.__index = ArcadeBGFever
|
|
|
|
-- The cabinet wipes normal->fever over `normal_fever` (root frames 1..29 at
|
|
-- 60 fps). We cannot reproduce the wipe with one texture, so it is a fade of
|
|
-- the same length, and `transitioned` flips when it ends -- that is the flag
|
|
-- background.lua uses to stop drawing bg_normal underneath.
|
|
--
|
|
-- ROUND 52 (r52-lua-divergence-fixes): the wipe now runs on BOTH edges and is
|
|
-- re-triggerable, matching the reference build `EnsoGraphicBgFever::Process`
|
|
-- (EnsoGraphicBgFever.obj.c:297-308): the cached flag at +88 is compared
|
|
-- against `IsNormaClear` EVERY frame, and each change of state GotoAndPlay's a
|
|
-- clip -- `normal_fever` on the rising edge, `fever_normal` on the falling
|
|
-- edge. The old `started`/`transitioned` one-way latch meant only the FIRST
|
|
-- clear ever wiped and a gauge dropping below the norma hard-cut the fever
|
|
-- backdrop in a single frame. `stop()` is the falling-edge clip (a fade of
|
|
-- the same 29-frame length, from wherever the current fade sits, so an edge
|
|
-- mid-wipe reverses smoothly), and `start()` re-arms after it.
|
|
-- `is_visible()` is the new flag background.lua uses to keep drawing this
|
|
-- object while the exit fade is still alive.
|
|
local TRANSITION_MS = 29000 / 60
|
|
|
|
function ArcadeBGFever.new(index, path)
|
|
local self = setmetatable({}, ArcadeBGFever)
|
|
self.name = "bg_fever_" .. index
|
|
self.path = path or "background"
|
|
tex.load_folder(self.path, "bg_fever/" .. self.name)
|
|
|
|
self.transitioned = false
|
|
self.started = false
|
|
self.elapsed = 0
|
|
self.last_ms = nil
|
|
|
|
self.fade = anim.fade(TRANSITION_MS, {
|
|
initial_opacity = 0.0,
|
|
final_opacity = 1.0,
|
|
loop = false
|
|
})
|
|
|
|
self.anim = nil
|
|
if BGAnim and (path or "background") == "background" then
|
|
self.anim = BGAnim.new(self.name, path)
|
|
end
|
|
|
|
self.layers = {}
|
|
local d = DATA[self.name]
|
|
if d and d.layers then
|
|
for _, l in ipairs(d.layers) do
|
|
local id = tex.get_texture(self.path .. "/" .. self.name .. "/" .. l.tex)
|
|
if id then
|
|
local period = l.period or 0
|
|
table.insert(self.layers, {
|
|
id = id,
|
|
period = period,
|
|
vx = l.vx or 0,
|
|
-- enough copies to cover 1920 px whatever the phase
|
|
n = (period > 0) and (math.ceil(1920 / period) + 1) or 0
|
|
})
|
|
end
|
|
end
|
|
end
|
|
if #self.layers == 0 then
|
|
-- fail soft: the generated table is missing or named textures this
|
|
-- folder does not have. Draw the one name every slot ships.
|
|
local id = tex.get_texture(self.path .. "/" .. self.name .. "/background")
|
|
if id then table.insert(self.layers, {id = id, period = 0, vx = 0, n = 0}) end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
function ArcadeBGFever:start()
|
|
if self.started then return end
|
|
self.started = true
|
|
self.transitioned = false
|
|
-- `normal_fever`: wipe in from wherever the (possibly mid-exit) fade sits.
|
|
local from = self.fade and self.fade.attribute or 0.0
|
|
self.fade = anim.fade(TRANSITION_MS, {
|
|
initial_opacity = from,
|
|
final_opacity = 1.0,
|
|
loop = false
|
|
})
|
|
self.fade:start()
|
|
end
|
|
|
|
-- ROUND 52: falling edge (`fever_normal`). Re-arms start() for the next clear.
|
|
function ArcadeBGFever:stop()
|
|
if not self.started then return end
|
|
self.started = false
|
|
self.transitioned = false
|
|
local from = self.fade and self.fade.attribute or 1.0
|
|
self.fade = anim.fade(TRANSITION_MS, {
|
|
initial_opacity = from,
|
|
final_opacity = 0.0,
|
|
loop = false
|
|
})
|
|
self.fade:start()
|
|
end
|
|
|
|
-- ROUND 52: true while anything of this backdrop is on screen -- entering,
|
|
-- steady, or exiting. background.lua draws bg_normal beneath whenever the
|
|
-- fever plate is not yet (or no longer) fully opaque.
|
|
function ArcadeBGFever:is_visible()
|
|
if self.started then return true end
|
|
return (self.fade.attribute or 0) > 0.001 and not self.fade.is_finished
|
|
end
|
|
|
|
function ArcadeBGFever:update(current_time_ms)
|
|
if self.last_ms then
|
|
local dt = current_time_ms - self.last_ms
|
|
if dt > 0 and dt < 500 then self.elapsed = self.elapsed + dt end
|
|
end
|
|
self.last_ms = current_time_ms
|
|
if self.anim then self.anim:update(current_time_ms) end
|
|
|
|
if not self.transitioned then
|
|
self.fade:update(current_time_ms)
|
|
if self.started and self.fade.is_finished then self.transitioned = true end
|
|
end
|
|
end
|
|
|
|
function ArcadeBGFever:draw()
|
|
local fade = self.transitioned and 1.0 or self.fade.attribute
|
|
if self.anim then
|
|
self.anim:draw(fade)
|
|
return
|
|
end
|
|
|
|
-- back to front, in the cabinet's own depth order: the static art is NOT
|
|
-- all behind the strips (bg_fever_a_02's spinning tops sit in front of an
|
|
-- opaque checker strip), so the order in the table is load-bearing.
|
|
for _, l in ipairs(self.layers) do
|
|
if l.period > 0 then
|
|
local off = (self.elapsed / 1000.0) * l.vx
|
|
off = off % l.period
|
|
if off > 0 then off = off - l.period end
|
|
for i = 0, l.n do
|
|
tex.draw_texture(l.id, { x = off + i * l.period, fade = fade })
|
|
end
|
|
else
|
|
tex.draw_texture(l.id, { fade = fade })
|
|
end
|
|
end
|
|
end
|
|
|
|
function ArcadeBGFever:destroy()
|
|
tex.unload_folder(self.path, "bg_fever/" .. self.name)
|
|
if self.anim then self.anim:destroy() end
|
|
end
|
|
|
|
local BGFever = {}
|
|
BGFever.Base = ArcadeBGFever
|
|
BGFever.Arcade = ArcadeBGFever
|
|
|
|
function BGFever.create(index, path)
|
|
return ArcadeBGFever.new(index, path)
|
|
end
|
|
|
|
return BGFever
|