196 lines
7.4 KiB
Lua
196 lines
7.4 KiB
Lua
-- YataiDON-HSS override of PyTaikoGreen/background/bg_objects/renda.lua: Renda1 origin from x2[1]/y2[1]; frame from frame_count
|
|
local BaseRenda = {}
|
|
BaseRenda.__index = BaseRenda
|
|
|
|
function BaseRenda.new(index)
|
|
local self = setmetatable({}, BaseRenda)
|
|
self.name = "renda_" .. index
|
|
local screen_width = tex.get_screen_width()
|
|
local screen_scale = tex.get_screen_scale()
|
|
self.hori_move = anim.move(1500 * screen_scale, {total_distance = screen_width})
|
|
self.hori_move:start()
|
|
return self
|
|
end
|
|
|
|
function BaseRenda:update(current_time_ms)
|
|
self.hori_move:update(current_time_ms)
|
|
end
|
|
|
|
local Renda0 = setmetatable({}, {__index = BaseRenda})
|
|
Renda0.__index = Renda0
|
|
|
|
function Renda0.new(index)
|
|
local self = setmetatable({}, Renda0)
|
|
local base = BaseRenda.new(index)
|
|
for k, v in pairs(base) do self[k] = v end
|
|
local screen_scale = tex.get_screen_scale()
|
|
local screen_height = tex.get_screen_height()
|
|
self.vert_move = anim.move(1500 * screen_scale, {total_distance = screen_height + (80 * screen_scale)})
|
|
self.vert_move:start()
|
|
local tex_info = tex.get_texture_info("renda", self.name)
|
|
local num_frames = (tex_info and tex_info.frame_count) or 1
|
|
self.frame = math.random(0, num_frames - 1)
|
|
self.x = math.random(0, math.floor(500 * screen_scale))
|
|
self.y = math.random(0, math.floor(20 * screen_scale))
|
|
self._id = tex.get_id("renda", self.name) -- nil = missing (ROUND 60: id 0 is valid)
|
|
return self
|
|
end
|
|
|
|
function Renda0:update(current_time_ms)
|
|
BaseRenda.update(self, current_time_ms)
|
|
self.vert_move:update(current_time_ms)
|
|
end
|
|
|
|
function Renda0:draw(y_offset)
|
|
-- ROUND 60 (r60-collab-fix-all): fail soft when the collab ships no renda art
|
|
if not self._id then return end
|
|
tex.draw_texture(self._id, {
|
|
frame = self.frame,
|
|
x = self.hori_move.attribute + self.x,
|
|
y = -self.vert_move.attribute + self.y + (y_offset or 0)
|
|
})
|
|
end
|
|
|
|
local Renda1 = setmetatable({}, {__index = BaseRenda})
|
|
Renda1.__index = Renda1
|
|
|
|
function Renda1.new(index)
|
|
local self = setmetatable({}, Renda1)
|
|
local base = BaseRenda.new(index)
|
|
for k, v in pairs(base) do self[k] = v end
|
|
local screen_scale = tex.get_screen_scale()
|
|
local screen_height = tex.get_screen_height()
|
|
local tex_info = tex.get_texture_info("renda", self.name)
|
|
self.frame = math.random(0, ((tex_info and tex_info.frame_count) or 6) - 1)
|
|
self.y = math.random(0, math.floor(200 * screen_scale))
|
|
self.rotate = anim.move(800 * screen_scale, {total_distance = math.floor(screen_height / 2), loop = true})
|
|
self.rotate:start()
|
|
self.origin = {(tex_info and tex_info.x2[1] or 0) / 2, (tex_info and tex_info.y2[1] or 0) / 2}
|
|
self._id = tex.get_id("renda", self.name) -- nil = missing (ROUND 60: id 0 is valid)
|
|
return self
|
|
end
|
|
|
|
function Renda1:update(current_time_ms)
|
|
BaseRenda.update(self, current_time_ms)
|
|
self.rotate:update(current_time_ms)
|
|
end
|
|
|
|
function Renda1:draw(y_offset)
|
|
-- ROUND 60 (r60-collab-fix-all): fail soft when the collab ships no renda art
|
|
if not self._id then return end
|
|
tex.draw_texture(self._id, {
|
|
frame = self.frame,
|
|
x = self.hori_move.attribute + self.origin[1],
|
|
y = self.y + self.origin[2] + (y_offset or 0),
|
|
origin = self.origin,
|
|
rotation = self.rotate.attribute
|
|
})
|
|
end
|
|
|
|
local Renda2 = setmetatable({}, {__index = BaseRenda})
|
|
Renda2.__index = Renda2
|
|
|
|
function Renda2.new(index)
|
|
local self = setmetatable({}, Renda2)
|
|
local base = BaseRenda.new(index)
|
|
for k, v in pairs(base) do self[k] = v end
|
|
local screen_scale = tex.get_screen_scale()
|
|
local screen_height = tex.get_screen_height()
|
|
self.vert_move = anim.move(1500, {total_distance = screen_height + (80 * screen_scale)})
|
|
self.vert_move:start()
|
|
self.x = math.random(0, math.floor(500 * screen_scale))
|
|
self.y = math.random(0, math.floor(20 * screen_scale))
|
|
self._id = tex.get_id("renda", self.name) -- nil = missing (ROUND 60: id 0 is valid)
|
|
return self
|
|
end
|
|
|
|
function Renda2:update(current_time_ms)
|
|
BaseRenda.update(self, current_time_ms)
|
|
self.vert_move:update(current_time_ms)
|
|
end
|
|
|
|
function Renda2:draw(y_offset)
|
|
-- ROUND 60 (r60-collab-fix-all): fail soft when the collab ships no renda art
|
|
if not self._id then return end
|
|
tex.draw_texture(self._id, {
|
|
x = self.hori_move.attribute + self.x,
|
|
y = -self.vert_move.attribute + self.y + (y_offset or 0)
|
|
})
|
|
end
|
|
|
|
-- ROUND 52 (r52-lua-divergence-fixes): the cabinet's renda effect is a FIXED
|
|
-- round-robin pool, not an unbounded per-hit spawner. the reference build
|
|
-- `EnsoGraphicRendaEffect` (EnsoGraphicRendaEffect.obj.c):
|
|
-- * the pool is 25 movie clips -- `EffectPlayerBase::Initialize(a1, 25, ...)`
|
|
-- (:2379);
|
|
-- * `Process` (0x14012BDA0, :2270-2295) arms AT MOST ONE
|
|
-- `EffectPlayer::Start` per frame (a single flag at +88, set while an
|
|
-- active kind-6/9 roll note is in flight, consumed once);
|
|
-- * `EffectPlayer::Start` (0x14012C640, :2848-2860) takes slot
|
|
-- `counter % pool_size` and REPLACES whatever is there (a still-playing
|
|
-- clip is swapped out via DoSwaping, not skipped), then counter++.
|
|
-- The skin used to push one object per hit with no cap (~40 live at
|
|
-- 20 hit/s over the 1500 ms crossing), so the shower read "how fast you hit"
|
|
-- instead of "a roll is happening". Ported: pool of 25 slots, at most one
|
|
-- spawn per rendered frame, round-robin slot replacement. (The engine hook
|
|
-- is still per-hit -- there is no per-frame "roll active" Lua signal -- so a
|
|
-- slow roll spawns fewer than the cabinet's one-per-frame; the cap and the
|
|
-- steady-state density now match.)
|
|
local POOL_SIZE = 25
|
|
|
|
local RendaController = {}
|
|
RendaController.__index = RendaController
|
|
|
|
-- ROUND 58 (r58-2p-background-polish): optional y_offset -- the cabinet's 2P
|
|
-- enso_post set (target 1) places TWO renda_effect instances, playerNo 0 at
|
|
-- y=0 and playerNo 1 at y=804 (the 2P donbg band), pure translate. A second
|
|
-- controller with y_offset = game_2p_offset.y is that pn1 instance.
|
|
function RendaController.new(path, index, y_offset)
|
|
local self = setmetatable({}, RendaController)
|
|
self.rendas = {} -- slot -> live effect (holes allowed)
|
|
self.rr = 0 -- round-robin counter (EffectPlayer +76)
|
|
self.spawned_this_frame = false
|
|
self.path = path or "background"
|
|
self.index = (index ~= nil) and index or math.random(0, 2)
|
|
self.y_offset = y_offset or 0
|
|
tex.load_folder(self.path, "renda")
|
|
return self
|
|
end
|
|
|
|
function RendaController:add_renda()
|
|
-- <=1 Start per frame, exactly like Process's single +88 flag.
|
|
if self.spawned_this_frame then return end
|
|
self.spawned_this_frame = true
|
|
local classes = {Renda0, Renda1, Renda2}
|
|
local cls = classes[self.index + 1]
|
|
local slot = (self.rr % POOL_SIZE) + 1
|
|
self.rr = self.rr + 1
|
|
self.rendas[slot] = cls.new(self.index) -- replace-in-slot (DoSwaping)
|
|
end
|
|
|
|
function RendaController:update(current_time_ms)
|
|
self.spawned_this_frame = false
|
|
for slot = 1, POOL_SIZE do
|
|
local r = self.rendas[slot]
|
|
if r then
|
|
r:update(current_time_ms)
|
|
if r.hori_move.is_finished then
|
|
self.rendas[slot] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function RendaController:draw()
|
|
for slot = 1, POOL_SIZE do
|
|
local r = self.rendas[slot]
|
|
if r then r:draw(self.y_offset) end
|
|
end
|
|
end
|
|
|
|
function RendaController:destroy()
|
|
tex.unload_folder(self.path, "renda")
|
|
end
|
|
|
|
return RendaController
|