Files
2026-07-17 13:03:07 -04:00

428 lines
16 KiB
Lua

local BGFeverBase = {}
BGFeverBase.__index = BGFeverBase
function BGFeverBase.new(index, path)
local self = setmetatable({}, BGFeverBase)
self.name = "bg_fever_" .. index
self.path = path or "background"
tex.load_folder(self.path, "bg_fever/" .. self.name)
self.transitioned = false
return self
end
function BGFeverBase:start() end
function BGFeverBase:update(current_time_ms) end
function BGFeverBase:draw() end
function BGFeverBase:destroy()
tex.unload_folder(self.path, "bg_fever/" .. self.name)
end
-- BGFever0: expanding tiles with wave orbiting a circle (animations 28-30)
local BGFever0 = setmetatable({}, {__index = BGFeverBase})
BGFever0.__index = BGFever0
function BGFever0.new(index, path)
local self = setmetatable({}, BGFever0)
local base = BGFeverBase.new(index, path)
for k, v in pairs(base) do self[k] = v end
self.screen_scale = tex.get_screen_scale()
self.screen_height = tex.get_screen_height()
self.wait = 0
self.bg_tiles = {}
self.is_transitioned = false
-- Copies of anim 29/30 with increasing delays for corner/footer/mountain/overlay
-- anim 29: move 133ms, distance 360, ease_out quadratic
-- anim 30: move 133ms, distance 160, ease_in quadratic, delay=133
self.corner_move_up = anim.move(133, {total_distance = 360, ease_out = "quadratic"})
self.corner_move_down = anim.move(133, {total_distance = 160, ease_in = "quadratic", delay = 133})
self.footer_move_up = anim.move(133, {total_distance = 360, ease_out = "quadratic", delay = 100})
self.footer_move_down = anim.move(133, {total_distance = 160, ease_in = "quadratic", delay = 233})
self.mountain_move_up = anim.move(133, {total_distance = 360, ease_out = "quadratic", delay = 200})
self.mountain_move_down = anim.move(133, {total_distance = 160, ease_in = "quadratic", delay = 333})
self.overlay_move_up = anim.move(133, {total_distance = 360, ease_out = "quadratic", delay = 300})
self.overlay_move_down = anim.move(133, {total_distance = 160, ease_in = "quadratic", delay = 433})
self.wave_spin = tex.get_animation(28)
self.bg_move = tex.get_animation(16)
self.circle = {
center_x = 100 * self.screen_scale,
center_y = 130 * self.screen_scale,
radius = 200 * self.screen_scale
}
self._id_bg = tex.get_id(self.name, "background") or 0
self._id_mountain = tex.get_id(self.name, "mountain") or 0
self._id_wave = tex.get_id(self.name, "wave") or 0
self._id_footer = tex.get_id(self.name, "footer") or 0
self._id_corner = tex.get_id(self.name, "corner") or 0
self._id_overlay = tex.get_id(self.name, "overlay") or 0
return self
end
function BGFever0:_get_wave_position()
local normalized = (self.wave_spin.attribute % 180) / 180.0
local angle = normalized * 2 * math.pi
local x = self.circle.center_x + math.cos(angle) * self.circle.radius
local y = self.circle.center_y + math.sin(angle) * self.circle.radius
return x, y
end
function BGFever0:_new_tile()
local expansion = anim.move(166 * self.screen_scale, {
total_distance = math.floor(self.screen_height / 2)
})
expansion:start()
return {expansion = expansion}
end
function BGFever0:start()
self.corner_move_up:start()
self.corner_move_down:start()
self.footer_move_up:start()
self.footer_move_down:start()
self.mountain_move_up:start()
self.mountain_move_down:start()
self.overlay_move_up:start()
self.overlay_move_down:start()
end
function BGFever0:update(current_time_ms)
if #self.bg_tiles < 20 and current_time_ms >= self.wait + 66 then
table.insert(self.bg_tiles, self:_new_tile())
self.wait = current_time_ms
end
for _, tile in ipairs(self.bg_tiles) do
tile.expansion:update(current_time_ms)
end
self.corner_move_up:update(current_time_ms)
self.corner_move_down:update(current_time_ms)
self.footer_move_up:update(current_time_ms)
self.footer_move_down:update(current_time_ms)
self.mountain_move_up:update(current_time_ms)
self.mountain_move_down:update(current_time_ms)
self.overlay_move_up:update(current_time_ms)
self.overlay_move_down:update(current_time_ms)
self.wave_spin:update(current_time_ms)
local fully_expanded = self.overlay_move_down.is_finished and #self.bg_tiles == 20
if fully_expanded and not self.is_transitioned then
self.bg_move:restart()
end
self.is_transitioned = fully_expanded
if self.is_transitioned then
self.bg_move:update(current_time_ms)
end
end
function BGFever0:draw()
local bg_info = tex.get_texture_info(self.name, "background")
local bg_width = bg_info and bg_info.width or 0
local sh = self.screen_height
for i, tile in ipairs(self.bg_tiles) do
local exp = tile.expansion.attribute
tex.draw_texture(self._id_bg, {
frame = (i - 1) % 10,
x = ((i - 1) * bg_width) - self.bg_move.attribute,
y = sh / 2 + (sh / 4 - exp / 2),
y2 = -sh / 2 + exp
})
end
local corner_y = -self.corner_move_up.attribute + self.corner_move_down.attribute
local footer_y = -self.footer_move_up.attribute + self.footer_move_down.attribute
local mountain_y = -self.mountain_move_up.attribute + self.mountain_move_down.attribute
local overlay_y = self.overlay_move_up.attribute - self.overlay_move_down.attribute
tex.draw_texture(self._id_mountain, {y = mountain_y})
local wave_x, wave_y = self:_get_wave_position()
local wave_info = tex.get_texture_info(self.name, "wave")
local wave_origin = {
(wave_info and wave_info.width or 0) / 2,
(wave_info and wave_info.height or 0) / 2
}
tex.draw_texture(self._id_wave, {x = wave_x, y = wave_y, origin = wave_origin})
tex.draw_texture(self._id_footer, {y = footer_y})
tex.draw_texture(self._id_corner, {y = corner_y})
tex.draw_texture(self._id_overlay, {y = overlay_y})
end
-- BGFever1: ship swooping in (animations 19-23)
local BGFever1 = setmetatable({}, {__index = BGFeverBase})
BGFever1.__index = BGFever1
function BGFever1.new(index, path)
local self = setmetatable({}, BGFever1)
local base = BGFeverBase.new(index, path)
for k, v in pairs(base) do self[k] = v end
self.fadein = tex.get_animation(19)
self.bg_texture_change = tex.get_animation(20)
self.ship_rotation = tex.get_animation(21)
self.move_in = tex.get_animation(22)
self.move_out = tex.get_animation(23)
local ship_info = tex.get_texture_info(self.name, "ship")
self.ship_origin = {
(ship_info and ship_info.width or 0) / 2,
(ship_info and ship_info.height or 0) / 2
}
self._id_bg = tex.get_id(self.name, "background") or 0
self._id_footer_3 = tex.get_id(self.name, "footer_3") or 0
self._id_footer_1 = tex.get_id(self.name, "footer_1") or 0
self._id_footer_2 = tex.get_id(self.name, "footer_2") or 0
self._id_bird = tex.get_id(self.name, "bird") or 0
self._id_ship = tex.get_id(self.name, "ship") or 0
return self
end
function BGFever1:start()
self.fadein:start()
self.move_in:start()
self.move_out:start()
end
function BGFever1:update(current_time_ms)
self.fadein:update(current_time_ms)
self.bg_texture_change:update(current_time_ms)
self.ship_rotation:update(current_time_ms)
self.move_in:update(current_time_ms)
self.move_out:update(current_time_ms)
self.transitioned = self.move_out.is_finished
end
function BGFever1:draw()
local move = self.move_in.attribute - self.move_out.attribute
local fade = self.fadein.attribute
local spin = self.ship_rotation.attribute
tex.draw_texture(self._id_bg, {frame = self.bg_texture_change.attribute, fade = fade})
tex.draw_texture(self._id_footer_3, {y = move, fade = fade})
tex.draw_texture(self._id_footer_1, {y = move, fade = fade})
tex.draw_texture(self._id_footer_2, {y = move, fade = fade})
tex.draw_texture(self._id_bird, {index = 0, x = move, mirror = "horizontal", y = spin * 180})
tex.draw_texture(self._id_bird, {index = 1, x = -move, y = spin * 180})
tex.draw_texture(self._id_ship, {
x = self.ship_origin[1],
y = self.ship_origin[2] + move,
origin = self.ship_origin,
rotation = spin * 100,
center = true
})
end
-- BGFever2: fish orbiting a circle (animations 19-20, 24-28)
local BGFever2 = setmetatable({}, {__index = BGFeverBase})
BGFever2.__index = BGFever2
function BGFever2.new(index, path)
local self = setmetatable({}, BGFever2)
local base = BGFeverBase.new(index, path)
for k, v in pairs(base) do self[k] = v end
self.screen_scale = tex.get_screen_scale()
self.fadein = tex.get_animation(19)
self.move_in = tex.get_animation(24)
self.footer_move_up = tex.get_animation(26)
self.bird_tc = tex.get_animation(20)
self.overlay_tc = tex.get_animation(25)
self.circle_rotate = tex.get_animation(27)
self.fish_spin = tex.get_animation(28)
self.circle = {
center_x = 500 * self.screen_scale,
center_y = 300 * self.screen_scale,
radius = 300 * self.screen_scale
}
self.num_fish = 8
self.fish_spacing = (2 * math.pi) / self.num_fish
self.fish_phase_offsets = {}
for i = 0, self.num_fish - 1 do
self.fish_phase_offsets[i + 1] = i * self.fish_spacing
end
local wave_info = tex.get_texture_info(self.name, "wave")
self.wave_origin = {
(wave_info and wave_info.width or 0) / 2,
(wave_info and wave_info.height or 0) / 2
}
local fish_info = tex.get_texture_info(self.name, "fish")
self.fish_origin = {
(fish_info and fish_info.width or 0) / 2,
(fish_info and fish_info.height or 0) / 2
}
local circle_info = tex.get_texture_info(self.name, "circle")
self.circle_origin = {
(circle_info and circle_info.width or 0) / 2,
(circle_info and circle_info.height or 0) / 2
}
self._id_bg = tex.get_id(self.name, "background") or 0
self._id_overlay = tex.get_id(self.name, "overlay") or 0
self._id_circle = tex.get_id(self.name, "circle") or 0
self._id_wave = tex.get_id(self.name, "wave") or 0
self._id_fish = tex.get_id(self.name, "fish") or 0
self._id_footer_2 = tex.get_id(self.name, "footer_2") or 0
self._id_footer_1 = tex.get_id(self.name, "footer_1") or 0
self._id_bird = tex.get_id(self.name, "bird") or 0
return self
end
function BGFever2:_get_main_position(spin_value, multiplier)
multiplier = multiplier or 1.0
local normalized = ((spin_value * multiplier) % 360) / 360.0
local angle = normalized * 2 * math.pi
local x = self.circle.center_x + math.cos(angle) * self.circle.radius
local y = self.circle.center_y + math.sin(angle) * self.circle.radius
return x, y
end
function BGFever2:_get_small_position(spin_value, multiplier)
multiplier = multiplier or 1.0
local normalized = ((spin_value * multiplier) % 360) / 360.0
local angle = normalized * 2 * math.pi
local x = self.circle.center_x + math.cos(angle) * 20
local y = self.circle.center_y + math.sin(angle) * 20
return x, y
end
function BGFever2:_get_fish_pos_and_rot(spin_value, phase_offset)
local angle_deg = spin_value + math.deg(phase_offset)
local normalized = (angle_deg % 360) / 360.0
local angle = normalized * 2 * math.pi
local x = self.circle.center_x + math.cos(angle) * self.circle.radius
local y = self.circle.center_y + math.sin(angle) * self.circle.radius
local rotation = math.deg(angle + math.pi / 2)
return x, y, rotation
end
function BGFever2:start()
self.fadein:start()
self.move_in:start()
self.footer_move_up:start()
end
function BGFever2:update(current_time_ms)
self.fadein:update(current_time_ms)
self.move_in:update(current_time_ms)
self.bird_tc:update(current_time_ms)
self.overlay_tc:update(current_time_ms)
self.footer_move_up:update(current_time_ms)
self.circle_rotate:update(current_time_ms)
self.fish_spin:update(current_time_ms)
self.transitioned = self.move_in.is_finished
end
function BGFever2:draw()
local fade = self.fadein.attribute
local spin = self.fish_spin.attribute
local sc = self.screen_scale
tex.draw_texture(self._id_bg, {x = -self.move_in.attribute})
tex.draw_texture(self._id_overlay, {frame = self.overlay_tc.attribute, fade = fade})
tex.draw_texture(self._id_circle, {
x = self.circle_origin[1], y = self.circle_origin[2],
fade = fade, origin = self.circle_origin, rotation = self.circle_rotate.attribute
})
local wave_x, wave_y = self:_get_main_position(spin, 2.0)
tex.draw_texture(self._id_wave, {x = wave_x, y = wave_y, fade = fade, origin = self.wave_origin})
for j = 0, 1 do
for _, phase in ipairs(self.fish_phase_offsets) do
local fx, fy, frot = self:_get_fish_pos_and_rot(spin, phase)
tex.draw_texture(self._id_fish, {
x = fx, y = fy, fade = fade,
origin = self.fish_origin, rotation = frot, index = j
})
end
end
local fw_x, fw_y = self:_get_small_position(spin, 3.0)
for i = 0, 2 do
tex.draw_texture(self._id_footer_2, {
x = fw_x + (i * 600 * sc), y = fw_y,
fade = fade, origin = self.wave_origin
})
end
for i = 0, 2 do
tex.draw_texture(self._id_footer_1, {x = i * 450, y = -self.footer_move_up.attribute})
end
tex.draw_texture(self._id_bird, {frame = self.bird_tc.attribute, index = 0, x = -self.move_in.attribute})
tex.draw_texture(self._id_bird, {frame = self.bird_tc.attribute, index = 1, x = -self.move_in.attribute})
end
-- BGFever3: scrolling tiled background (animations 15-18)
local BGFever3 = setmetatable({}, {__index = BGFeverBase})
BGFever3.__index = BGFever3
function BGFever3.new(index, path)
local self = setmetatable({}, BGFever3)
local base = BGFeverBase.new(index, path)
for k, v in pairs(base) do self[k] = v end
self.vertical_move = tex.get_animation(15)
self.horizontal_move = tex.get_animation(16)
self.bg_texture_move_down = tex.get_animation(17)
self.bg_texture_move_up = tex.get_animation(18)
self._id_bg = tex.get_id(self.name, "background") or 0
self._id_overlay_1 = tex.get_id(self.name, "overlay_1") or 0
self._id_overlay_2 = tex.get_id(self.name, "overlay_2") or 0
return self
end
function BGFever3:start()
self.bg_texture_move_down:start()
self.bg_texture_move_up:start()
end
function BGFever3:update(current_time_ms)
self.bg_texture_move_down:update(current_time_ms)
self.bg_texture_move_up:update(current_time_ms)
if self.bg_texture_move_up.is_finished and not self.transitioned then
self.transitioned = true
self.vertical_move:restart()
self.horizontal_move:restart()
end
if self.transitioned then
self.vertical_move:update(current_time_ms)
self.horizontal_move:update(current_time_ms)
end
end
function BGFever3:draw()
local bg_info = tex.get_texture_info(self.name, "background")
local bg_width = bg_info and bg_info.width or 0
local y = self.bg_texture_move_down.attribute - self.bg_texture_move_up.attribute
for i = 0, bg_width * 12, bg_width do
tex.draw_texture(self._id_bg, {x = i, y = y})
end
tex.draw_texture(self._id_overlay_1, {y = -self.vertical_move.attribute - y})
local o2_info = tex.get_texture_info(self.name, "overlay_2")
local o2_width = o2_info and o2_info.width or 0
tex.draw_texture(self._id_overlay_2, {x = -self.horizontal_move.attribute, y = y})
tex.draw_texture(self._id_overlay_2, {x = o2_width - self.horizontal_move.attribute, y = y})
end
local BGFever = {}
BGFever.Base = BGFeverBase
function BGFever.create(index, path)
local map = {BGFever0, BGFever1, BGFever2, BGFever3}
return map[index + 1].new(index, path)
end
return BGFever