-- YataiDON-HSS override of PyTaikoGreen/background/bg_objects/fever.lua: bounce total_distance 50*screen_scale -- -- ROUND 52 (r52-lua-divergence-fixes): the 魂-max crowd is now EDGE-DRIVEN on -- both sides and re-triggerable, matching the reference build `EnsoGraphicFeverEffect::Process` -- (EnsoGraphicFeverEffect.obj.c:123-129): the cached flag at +88 is compared -- against `IsTamashiiMax` every frame and each change plays a clip -- -- `normal_fever` rising, `fever_normal` falling. The skin used to pop the -- crowd in and out in a single frame (draw gated on the raw is_rainbow flag in -- background.lua) and never replayed the entrance on a re-max. The entry/exit -- clips themselves are not exported (the cabinet's 40-frame 1920x540 flipbook -- stays out -- ROUND 12 trade), so both edges are an alpha ramp of the same -- 29-frame length BgFever's measured wipe uses (a documented stand-in, not a -- measured FeverEffect number). `is_visible()` replaces background.lua's -- is_rainbow draw gate so the exit ramp actually gets drawn. local FEVER_EDGE_MS = 29000 / 60 local BaseFever = {} BaseFever.__index = BaseFever function BaseFever.new(index, bpm, path) local self = setmetatable({}, BaseFever) self.name = "fever_" .. index self.path = path or "background" tex.load_folder(self.path, "fever/" .. self.name) local half_beat = (60000 / bpm) / 2 self.bounce_up = anim.move(half_beat, {total_distance = 50 * tex.get_screen_scale(), ease_out = "quadratic"}) self.bounce_down = anim.move(half_beat, {total_distance = 50 * tex.get_screen_scale(), ease_in = "quadratic", delay = half_beat}) -- ROUND 60: nil = missing. id 0 is a VALID texture id (the global -- name->id map starts at 0), so "or 0" hid real textures and, worse, made -- a missing folder draw texture id 0 (an unrelated sheet). self._id_overlay_l = tex.get_id(self.name, "overlay_l") self._id_overlay_r = tex.get_id(self.name, "overlay_r") self._id_overlay = tex.get_id(self.name, "overlay") self.active = false self.edge_fade = anim.fade(FEVER_EDGE_MS, {initial_opacity = 0.0, final_opacity = 0.0}) return self end function BaseFever:start() if self.active then return end self.active = true local from = self.edge_fade and self.edge_fade.attribute or 0.0 self.edge_fade = anim.fade(FEVER_EDGE_MS, {initial_opacity = from, final_opacity = 1.0}) self.edge_fade:start() self.bounce_up:start() self.bounce_down:start() end -- ROUND 52: falling edge (`fever_normal`); re-arms start(). function BaseFever:stop() if not self.active then return end self.active = false local from = self.edge_fade and self.edge_fade.attribute or 1.0 self.edge_fade = anim.fade(FEVER_EDGE_MS, {initial_opacity = from, final_opacity = 0.0}) self.edge_fade:start() end function BaseFever:is_visible() if self.active then return true end return (self.edge_fade.attribute or 0) > 0.001 and not self.edge_fade.is_finished end function BaseFever:alpha() if self.active and self.edge_fade.is_finished then return 1.0 end return self.edge_fade.attribute or 0.0 end function BaseFever:update(current_time_ms, bpm) self.edge_fade:update(current_time_ms) self.bounce_up:update(current_time_ms) self.bounce_down:update(current_time_ms) if self.bounce_down.is_finished then local half_beat = (60000 / bpm) / 2 self.bounce_up = anim.move(half_beat, {total_distance = 50 * tex.get_screen_scale(), ease_out = "quadratic"}) self.bounce_down = anim.move(half_beat, {total_distance = 50 * tex.get_screen_scale(), ease_in = "quadratic", delay = half_beat}) self.bounce_up:start() self.bounce_down:start() end end function BaseFever:destroy() tex.unload_folder(self.path, "fever/" .. self.name) end local Fever0 = setmetatable({}, {__index = BaseFever}) Fever0.__index = Fever0 function Fever0.new(index, bpm, path) local self = setmetatable({}, Fever0) local base = BaseFever.new(index, bpm, path) for k, v in pairs(base) do self[k] = v end return self end function Fever0:draw() local a = self:alpha() if a <= 0.001 then return end local y = self.bounce_down.attribute - self.bounce_up.attribute -- ROUND 60 (r60-collab-fix-all): fail soft when the folder shipped no art. if self._id_overlay_l then tex.draw_texture(self._id_overlay_l, {y = y, fade = a}) end if self._id_overlay_r then tex.draw_texture(self._id_overlay_r, {y = y, fade = a}) end end -- Fever1 and Fever2 share the same draw as Fever0 local Fever1 = setmetatable({}, {__index = Fever0}) Fever1.__index = Fever1 function Fever1.new(index, bpm, path) local self = setmetatable({}, Fever1) local base = BaseFever.new(index, bpm, path) for k, v in pairs(base) do self[k] = v end return self end function Fever1:draw() Fever0.draw(self) end local Fever2 = setmetatable({}, {__index = Fever0}) Fever2.__index = Fever2 function Fever2.new(index, bpm, path) local self = setmetatable({}, Fever2) local base = BaseFever.new(index, bpm, path) for k, v in pairs(base) do self[k] = v end return self end function Fever2:draw() Fever0.draw(self) end local Fever3 = setmetatable({}, {__index = BaseFever}) Fever3.__index = Fever3 function Fever3.new(index, bpm, path) local self = setmetatable({}, Fever3) local base = BaseFever.new(index, bpm, path) for k, v in pairs(base) do self[k] = v end return self end function Fever3:draw() local a = self:alpha() if a <= 0.001 then return end -- ROUND 60: fail soft on a missing fever folder (see Fever0:draw). if not self._id_overlay then return end local y = self.bounce_down.attribute - self.bounce_up.attribute tex.draw_texture(self._id_overlay, {y = y, fade = a}) end local Fever = {} Fever.Base = BaseFever Fever.Fever0 = Fever0 Fever.Fever1 = Fever1 Fever.Fever2 = Fever2 Fever.Fever3 = Fever3 function Fever.create(index, bpm, path) local map = {Fever0, Fever1, Fever2, Fever3} return map[index + 1].new(index, bpm, path) end return Fever