forked from Yonokid/YataiDONNijiiro
The five normal and three cleared backdrops were flat plates plus a few hand rebuilt effects, so the koi, the treasure ships, the lantern glow and the festival stalls never moved as they do in the original. Each movie is now exported per shape instance with its own loop (bg_data/bg_anim/<name>.lua, textures under background/bga_<name>) and replayed by bg_objects/bg_anim.lua at 60 fps on the lower half of the screen. bg_normal.lua and bg_fever.lua use it when the data exists and keep their old drawing as the fallback; the cleared backdrop's rise/fall wipe is unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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_id(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_id(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
|