Files
PyTaikoGreen/Scripts/entry/entry_info.lua
T
2026-11-04 01:06:48 -05:00

233 lines
8.1 KiB
Lua

EntryInfo = {}
EntryInfo.__index = EntryInfo
local S = tex.get_screen_scale()
local F = 1000 / 60
local PAGE_MS = { 7500, 9100, 10500, 10500 }
local OPEN_F, CLOSE_F, CONTENT_OUT_F = 15, 10, 4
local PANEL_MIN = 0.008
local PANEL_W = 1280 * S
local TEXT_FADE_F, TEXT_SLIDE_F, TEXT_SLIDE = 10, 15, -182
local function clamp01(v) return math.max(0.0, math.min(1.0, v)) end
local function lerp(a, b, t) return a + (b - a) * t end
local PAGES = {
{ text = "text_1", slide = 79, items = {
{ k = "shot_1", fade = 173 },
{ k = "hand_1", fade = 173, bounce = true },
{ k = "art_1", pop = { 97, 107, 112, 0.2, 1.12 } },
{ k = "icons_1", pop = { 97, 107, 112, 0.2, 1.12 } },
} },
{ text = "text_2", slide = 89, items = {
{ k = "bubble_2", pop = { 322, 333, 336, 0.3, 1.1 } },
{ k = "fan_2", fade = 181 },
{ coins = true, fade = 181 },
{ k = "bonus_2", pop = { 181, 192, 197, 0.2, 1.2 } },
{ k = "card_2", pop = { 110, 119, 125, 0.2, 1.2 } },
} },
{ text = "text_3", slide = 179, items = {
{ k = "shop_3", fade = 179 },
{ cursor = true, fade = 179 },
{ k = "bubble_3b", pop = { 425, 436, 439, 0.3, 1.1 } },
{ k = "bubble_3a", pop = { 215, 226, 229, 0.3, 1.1 } },
} },
{ text = "text_4", slide = 79, items = {
{ k = "season_spring", pop = { 97, 106, 112, 0.2, 1.2 } },
{ k = "season_summer", pop = { 120, 129, 135, 0.3, 1.2 } },
{ k = "season_autumn", pop = { 143, 152, 158, 0.3, 1.2 } },
{ k = "season_winter", pop = { 166, 175, 181, 0.3, 1.2 } },
{ sparks = 181 },
{ k = "note_4", fade = 211 },
} },
}
-- x, start frame
local COINS = {
{ 0, 0 }, { 60, 8 }, { -110, 16 }, { -60, 24 }, { 110, 32 }, { 0, 36 }, { -100, 40 }, { 60, 43 },
{ -110, 50 }, { -60, 56 }, { 110, 64 }, { -100, 68 },
{ 100, 0 }, { -50, 6 }, { 20, 13 }, { 80, 18 }, { -100, 24 }, { 20, 29 },
{ 100, 36 }, { -50, 42 }, { 20, 49 }, { 80, 54 }, { -100, 60 }, { 20, 65 },
}
local COINS_LOOP, COIN_FALL_F, COIN_FALL = 100, 33, 140
local COINS_X, COINS_Y, COINS_SCALE = -35.9, -61.1, 1.3
local COIN_SPIN = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1 }
local COIN_SPARKLES = { { -100, 80 }, { 50, 20 }, { -60, 0 }, { 20, 100 } }
local CURSOR_F = 15
local CURSOR = {
{ -209, -71.5 }, { -126, -71.5 }, { -43, -71.5 }, { 40, -71.5 }, { 123, -71.5 }, { 206, -71.5 },
{ -209, 18.5 }, { -126, 18.5 },
{ -209, 131.5 }, { -126, 131.5 }, { -43, 131.5 }, { 40, 131.5 },
}
-- start frame, x, y, peak scale; each grows for SPARK_GROW_F then fades for SPARK_FADE_F
local SPARKS = {
{ 0, 76, -64, 0.7 }, { 40, -70, -50, 0.8 }, { 83, -136, -18, 0.8 },
{ 18, -100, 26, 0.7 }, { 61, 90, 20, 0.7 }, { 95, 20, 26, 0.5 },
{ 5, 50, 20, 0.4 }, { 57, -50, 80, 0.5 }, { 87, 28, -90, 0.4 },
{ 31, 130, 10, 0.5 },
}
local SPARK_GROW_F, SPARK_FADE_F, SPARKS_LOOP = 18, 11, 124
-- root x, y, then scale per axis
local SPARK_GROUPS = { { 0, 15, 1.5, -1.5 }, { -384, 14, 1.2, -1.2 }, { 376, 41, -1.2, -1.2 } }
function EntryInfo.new()
local self = setmetatable({}, EntryInfo)
self.t = {}
self.now = tex.get_current_ms()
self.t0 = self.now
self.page = nil -- nil: panel still opening
audio.play_sound("info_page", "sound")
return self
end
function EntryInfo:draw_tex(key, p)
local t = self.t[key]
if t == nil then
t = tex.get_texture("entry/entry_info/" .. key) or false
self.t[key] = t
end
if t then tex.draw_texture(t, p or {}) end
end
function EntryInfo:next_page()
if self.page == #PAGE_MS then
self.out_t0 = self.now
return
end
self.page = (self.page or 0) + 1
self.page_t0 = self.now
if self.page > 1 then audio.play_sound("info_page", "sound") end
end
function EntryInfo:update(current_ms)
self.now = current_ms
if self.out_t0 then return end
if not self.page then
if self.now - self.t0 >= OPEN_F * F then self:next_page() end
elseif self.now - self.page_t0 >= PAGE_MS[self.page] then
self:next_page()
end
end
function EntryInfo:input()
if self.out_t0 or not self.page then return false end
self:next_page()
return true
end
function EntryInfo:is_done()
return self.out_t0 ~= nil and self.now - self.out_t0 >= (CLOSE_F + 1) * F
end
function EntryInfo:draw_panel()
local sx
if self.out_t0 then
sx = lerp(0.9, PANEL_MIN, clamp01((self.now - self.out_t0) / (CLOSE_F * F)))
else
sx = lerp(PANEL_MIN, 1, clamp01((self.now - self.t0) / (OPEN_F * F)))
end
self:draw_tex("panel", { x = PANEL_W * (1 - sx) / 2, x2 = -PANEL_W * (1 - sx) })
end
function EntryInfo:draw_coins(f, fade)
f = f % COINS_LOOP
for _, c in ipairs(COINS) do
local u = f - c[2]
if u >= 0 and u <= COIN_FALL_F then
local spin = math.floor(u) % #COIN_SPIN
self:draw_tex("coin", {
center = true, scale = COINS_SCALE, frame = COIN_SPIN[spin + 1],
mirror = spin >= 13 and "horizontal" or nil,
x = (COINS_X + COINS_SCALE * c[1]) * S,
y = (COINS_Y + COINS_SCALE * COIN_FALL * u / COIN_FALL_F) * S,
fade = fade * clamp01(0.1 + 0.9 * u / 10),
})
end
end
local u = f % 10
local spot = COIN_SPARKLES[math.floor(f / 10) % #COIN_SPARKLES + 1]
local s = u < 4 and lerp(0.1, 1, u / 4) or lerp(1, 0.5, (u - 4) / 5)
self:draw_tex("sparkle", {
center = true, scale = COINS_SCALE * s,
x = (COINS_X + COINS_SCALE * spot[1]) * S,
y = (COINS_Y + COINS_SCALE * spot[2]) * S,
fade = fade * (u < 4 and 1 or lerp(0.8, 0, (u - 4) / 5)),
})
end
function EntryInfo:draw_sparks(f, fade)
f = f % SPARKS_LOOP
for _, g in ipairs(SPARK_GROUPS) do
for _, sp in ipairs(SPARKS) do
local u = f - sp[1]
if u >= 0 and u <= SPARK_GROW_F + SPARK_FADE_F then
local grow = clamp01(u / SPARK_GROW_F)
self:draw_tex("sparkle", {
center = true, scale = lerp(0.1, sp[4], grow) * math.abs(g[3]),
x = (g[1] + g[3] * sp[2]) * S,
y = (g[2] + g[4] * sp[3]) * S,
fade = fade * (1 - clamp01((u - SPARK_GROW_F) / SPARK_FADE_F)),
})
end
end
end
end
function EntryInfo:draw_item(it, f, fade)
local base = fade
if it.fade then
if f < it.fade then return end
base = fade * clamp01((f - it.fade) / 15)
end
if it.coins then
self:draw_coins(f - it.fade, base)
elseif it.cursor then
local c = CURSOR[math.floor((f - it.fade) / CURSOR_F) % #CURSOR + 1]
self:draw_tex("cursor_3", { x = c[1] * S, y = c[2] * S, fade = base })
elseif it.sparks then
if f >= it.sparks then self:draw_sparks(f - it.sparks, fade) end
elseif it.pop then
local p = it.pop
if f < p[1] then return end
local s, a
if f < p[2] then
local t = (f - p[1]) / (p[2] - p[1])
s, a = lerp(p[4], p[5], t), t
else
s, a = lerp(p[5], 1, clamp01((f - p[2]) / (p[3] - p[2]))), 1
end
self:draw_tex(it.k, { center = true, scale = s, fade = fade * a })
else
local y = 0
if it.bounce then
local b = (f - it.fade) % 50
y = (b < 25 and b / 25 or (50 - b) / 25) * 20
end
self:draw_tex(it.k, { y = y * S, fade = base })
end
end
function EntryInfo:draw()
self:draw_panel()
if not self.page then return end
local fade = 1
if self.out_t0 then
fade = 0.75 * (1 - clamp01((self.now - self.out_t0) / (CONTENT_OUT_F * F)))
if fade <= 0 then return end
end
self:draw_tex("pager", { fade = fade })
self:draw_tex("pager_dot", { x = 30 * (self.page - 1) * S, fade = fade })
local page = PAGES[self.page]
local f = (self.now - self.page_t0) / F
for _, it in ipairs(page.items) do self:draw_item(it, f, fade) end
local t = clamp01((f - page.slide) / TEXT_SLIDE_F)
local y = TEXT_SLIDE * (1 - (1 - t) * (1 - t))
self:draw_tex(page.text, { y = y * S, fade = fade * clamp01(f / TEXT_FADE_F) })
end