Files
TaikoZhongandClaude Opus 5.5 f239bc156c background: cabinet backdrops for the collab presets
Collab songs (#SCENEPRESET) now get their own cabinet backdrop, replayed by
the same objects as the default backdrop instead of the parent's collab art:

  miku, toho, gumi, ia, lovelive, i7 (id7 / tri / rev / natsu), imas
  (765 / cg / ml / sidem), yo-kai (base / matsuri / hatsukoi / tokoroten /
  yougota), mario, a3

Each preset is a pack in bg_data/collab_packs.lua naming its parts: donbg
band (1P and 2P), normal and clear backdrops, troupe, stand under the
troupe, drumroll effect and soul-max crowd.  Shared parts (the i7, imas
and yo-kai families) are shared the way the cabinet shares them.  A pack is
used only when every part it names is present, otherwise the preset falls
back to the collab script as before.  Packs also apply in 2P (donbg bands).

The objects take a part name where they took a random index:
DonBG.create_named, BGNormal.create_named, BGFever.create_named,
ArcadeDancerGroup.new("<name>"), Fever.Anim.new("<name>").  New:
renda_clip.lua (each hit replays one of the effect's parts along its own
path), and a beat-synced BGAnim for the whole-troupe dancer movies (i7,
a3).  Collab troupes stand in fixed positions (lead in the centre) and
grow from 1 to the full troupe with the gauge.

Exported placements may now mirror: bg_anim, donbg and dancer data carry a
mirror flag (drawn with mirror = horizontal and the origin moved to the
other side of the png).  Existing data has no flag and draws as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 15:55:05 +08:00

266 lines
11 KiB
Lua

-- YataiDON-HSS override of PyTaikoGreen/background/bg_objects/bg_normal.lua: petal spawn band 260/540 *screen_scale
local BGNormalBase = {}
BGNormalBase.__index = BGNormalBase
function BGNormalBase.new(index, path)
local self = setmetatable({}, BGNormalBase)
self.name = "bg_" .. index
self.path = path or "background"
tex.load_folder(self.path, "bg_normal/" .. self.name)
self._id_bg = tex.get_texture(self.path .. "/" .. self.name .. "/background") or 0
return self
end
function BGNormalBase:update(current_time_ms) end
function BGNormalBase:draw()
tex.draw_texture(self._id_bg)
end
function BGNormalBase:destroy()
tex.unload_folder(self.path, "bg_normal/" .. self.name)
end
-- Index 0 and 1: background + flicker overlay (animation 9)
local BGNormal01 = setmetatable({}, {__index = BGNormalBase})
BGNormal01.__index = BGNormal01
function BGNormal01.new(index, path)
local self = setmetatable({}, BGNormal01)
local base = BGNormalBase.new(index, path)
for k, v in pairs(base) do self[k] = v end
self.flicker = tex.get_animation(9, "background")
self._id_overlay = tex.get_texture(self.path .. "/" .. self.name .. "/overlay") or 0
return self
end
function BGNormal01:update(current_time_ms)
self.flicker:update(current_time_ms)
end
function BGNormal01:draw()
tex.draw_texture(self._id_bg)
tex.draw_texture(self._id_overlay, {fade = self.flicker.attribute})
end
-- Index 2: stadium lights with flicker (animation 10)
local BGNormal2 = setmetatable({}, {__index = BGNormalBase})
BGNormal2.__index = BGNormal2
function BGNormal2.new(index, path)
local self = setmetatable({}, BGNormal2)
local base = BGNormalBase.new(index, path)
for k, v in pairs(base) do self[k] = v end
self.flicker = tex.get_animation(10, "background")
self._id_center = tex.get_texture(self.path .. "/" .. self.name .. "/center") or 0
self._id_overlay = tex.get_texture(self.path .. "/" .. self.name .. "/overlay") or 0
self._id_lamps = tex.get_texture(self.path .. "/" .. self.name .. "/lamps") or 0
self._id_light_orange = tex.get_texture(self.path .. "/" .. self.name .. "/light_orange") or 0
self._id_light_red = tex.get_texture(self.path .. "/" .. self.name .. "/light_red") or 0
self._id_light_green = tex.get_texture(self.path .. "/" .. self.name .. "/light_green") or 0
self._id_light_yellow = tex.get_texture(self.path .. "/" .. self.name .. "/light_yellow") or 0
self._id_side_l = tex.get_texture(self.path .. "/" .. self.name .. "/side_l") or 0
self._id_side_l_2 = tex.get_texture(self.path .. "/" .. self.name .. "/side_l_2") or 0
self._id_side_r = tex.get_texture(self.path .. "/" .. self.name .. "/side_r") or 0
return self
end
function BGNormal2:update(current_time_ms)
self.flicker:update(current_time_ms)
end
function BGNormal2:draw()
local f = self.flicker.attribute
tex.draw_texture(self._id_bg)
tex.draw_texture(self._id_center)
tex.draw_texture(self._id_overlay)
tex.draw_texture(self._id_lamps, {index = 0})
tex.draw_texture(self._id_lamps, {index = 1, mirror = "horizontal"})
tex.draw_texture(self._id_light_orange, {index = 0, fade = f})
tex.draw_texture(self._id_light_orange, {index = 1, fade = f})
tex.draw_texture(self._id_light_red, {fade = f})
tex.draw_texture(self._id_light_green, {fade = f})
tex.draw_texture(self._id_light_orange, {index = 2, fade = f})
tex.draw_texture(self._id_light_yellow, {index = 0, fade = f})
tex.draw_texture(self._id_light_yellow, {index = 1, fade = f})
tex.draw_texture(self._id_side_l)
tex.draw_texture(self._id_side_l_2)
tex.draw_texture(self._id_side_r)
end
-- Index 3: cherry blossoms with turtle and petals (animations 11, 12, 13)
local function new_petal(screen_scale, screen_width, screen_height)
local spawn_point
repeat
spawn_point = math.random(0, math.floor(screen_width))
until spawn_point < 260 * screen_scale or spawn_point > 540 * screen_scale
local duration = math.random(1400, 2000)
local dist_x = math.random(math.floor(-300 * screen_scale), math.floor(300 * screen_scale))
local petal = {
spawn_point = spawn_point,
move_x = anim.move(duration, {total_distance = dist_x}),
move_y = anim.move(duration, {total_distance = math.floor(screen_height / 2)})
}
petal.move_x:start()
petal.move_y:start()
return petal
end
local BGNormal3 = setmetatable({}, {__index = BGNormalBase})
BGNormal3.__index = BGNormal3
function BGNormal3.new(index, path)
local self = setmetatable({}, BGNormal3)
local base = BGNormalBase.new(index, path)
for k, v in pairs(base) do self[k] = v end
self.flicker = tex.get_animation(11, "background")
self.turtle_move = tex.get_animation(12, "background")
self.turtle_change = tex.get_animation(13, "background")
self.screen_scale = tex.get_screen_scale()
self.screen_width = tex.get_screen_width()
self.screen_height = tex.get_screen_height()
self.petals = {}
for _ = 1, 5 do
table.insert(self.petals, new_petal(self.screen_scale, self.screen_width, self.screen_height))
end
self._id_chara = tex.get_texture(self.path .. "/" .. self.name .. "/chara") or 0
self._id_turtle = tex.get_texture(self.path .. "/" .. self.name .. "/turtle") or 0
self._id_overlay= tex.get_texture(self.path .. "/" .. self.name .. "/overlay") or 0
self._id_petal = tex.get_texture(self.path .. "/" .. self.name .. "/petal") or 0
return self
end
function BGNormal3:update(current_time_ms)
self.flicker:update(current_time_ms)
self.turtle_move:update(current_time_ms)
self.turtle_change:update(current_time_ms)
for i = #self.petals, 1, -1 do
local petal = self.petals[i]
petal.move_x:update(current_time_ms)
petal.move_y:update(current_time_ms)
if petal.move_y.is_finished then
table.remove(self.petals, i)
table.insert(self.petals, new_petal(self.screen_scale, self.screen_width, self.screen_height))
end
end
end
function BGNormal3:draw()
tex.draw_texture(self._id_bg)
tex.draw_texture(self._id_chara)
tex.draw_texture(self._id_turtle, {
frame = self.turtle_change.attribute,
x = self.turtle_move.attribute
})
tex.draw_texture(self._id_overlay)
for _, petal in ipairs(self.petals) do
tex.draw_texture(self._id_petal, {
x = petal.spawn_point + petal.move_x.attribute,
y = self.screen_height / 2 + petal.move_y.attribute,
fade = 0.75
})
end
end
-- Index 4: paper lanterns with flicker (animation 14)
local BGNormal4 = setmetatable({}, {__index = BGNormalBase})
BGNormal4.__index = BGNormal4
local GLOW_HALF_MS = 25000 / 60 -- 25 cabinet frames
function BGNormal4.new(index, path)
local self = setmetatable({}, BGNormal4)
local base = BGNormalBase.new(index, path)
for k, v in pairs(base) do self[k] = v end
self.glow_phase_ms = 0
self.glow_last_ms = nil
self._id_paper_lamp = tex.get_texture(self.path .. "/" .. self.name .. "/paper_lamp") or 0
self._id_light_overlay= tex.get_texture(self.path .. "/" .. self.name .. "/light_overlay") or 0
self._id_overlay = tex.get_texture(self.path .. "/" .. self.name .. "/overlay") or 0
self._id_lamp_overlay = tex.get_texture(self.path .. "/" .. self.name .. "/lamp_overlay") or 0
self._id_lamp = tex.get_texture(self.path .. "/" .. self.name .. "/lamp") or 0
return self
end
function BGNormal4:update(current_time_ms)
if self.glow_last_ms then
local dt = current_time_ms - self.glow_last_ms
if dt > 0 then
self.glow_phase_ms = (self.glow_phase_ms + dt) % (2 * GLOW_HALF_MS)
end
end
self.glow_last_ms = current_time_ms
end
-- {scale, mirrored} index 0..9 == texture.json light_overlay entry 0..9
local BG4_GLOW = {
{0.95, true}, {1.25, true}, {1.00, true}, {1.15, true}, {0.90, true},
{0.90, false}, {1.10, false}, {1.05, false}, {1.25, false}, {1.00, false},
}
function BGNormal4:draw()
tex.draw_texture(self._id_bg)
for i = 0, 9 do
tex.draw_texture(self._id_paper_lamp, {frame = 9 - i, index = i})
end
local p = self.glow_phase_ms / GLOW_HALF_MS -- 0..2
if p > 1 then p = 2 - p end -- triangle 0..1..0
local ga = 0.5 - p * (0.5 - 0.164) -- 0.5 dim to 0.164, back
if ga < 0 then ga = 0 elseif ga > 1 then ga = 1 end
for i = 0, 9 do
local g = BG4_GLOW[i + 1]
tex.draw_texture(self._id_light_overlay, {
index = i, fade = ga, scale = g[1], blend = "additive",
mirror = g[2] and "horizontal" or "none",
})
end
-- shape 8 (the eave glow) and shape 3 (the stone-lantern glows) are additive at
-- full alpha on the cabinet, not 0.75 alpha-blended.
tex.draw_texture(self._id_overlay, {blend = "additive"})
tex.draw_texture(self._id_lamp_overlay, {index = 0, blend = "additive"})
tex.draw_texture(self._id_lamp_overlay, {index = 1, blend = "additive"})
tex.draw_texture(self._id_lamp, {index = 0})
tex.draw_texture(self._id_lamp, {index = 1})
end
local BGNormal = {}
BGNormal.Base = BGNormalBase
BGNormal.BGNormal2 = BGNormal2
-- Exact replay of the cabinet movie when bg_data/bg_anim/bg_N.lua is exported;
-- the hand-built classes below stay as the fallback.
local ok_anim, BGAnim = pcall(require, "background/bg_objects/bg_anim")
if not ok_anim or type(BGAnim) ~= "table" then BGAnim = nil end
local BGNormalAnim = {}
BGNormalAnim.__index = BGNormalAnim
-- name: a collab pack's backdrop ("b_001_n"); nil for the default bg_<index>
function BGNormalAnim.new(index, path, name)
name = name or ("bg_" .. index)
local anim = BGAnim.new(name, path)
if not anim then return nil end
return setmetatable({ anim = anim, name = name }, BGNormalAnim)
end
function BGNormalAnim:update(current_time_ms) self.anim:update(current_time_ms) end
function BGNormalAnim:draw() self.anim:draw(1.0) end
function BGNormalAnim:destroy() self.anim:destroy() end
function BGNormal.create(index, path)
if BGAnim and (path or "background") == "background" and BGAnim.available("bg_" .. index) then
local obj = BGNormalAnim.new(index, path)
if obj then return obj end
end
local map = {BGNormal01, BGNormal01, BGNormal2, BGNormal3, BGNormal4}
return map[index + 1].new(index, path)
end
-- a collab pack's backdrop, replayed from its exported movie; nil when it is missing
function BGNormal.create_named(name, path)
if not BGAnim then return nil end
return BGNormalAnim.new(nil, path, name)
end
return BGNormal