556 lines
23 KiB
Lua
556 lines
23 KiB
Lua
BattleResultBoard = {}
|
|
BattleResultBoard.__index = BattleResultBoard
|
|
|
|
local S = tex.get_screen_scale()
|
|
local FRAME_MS = 1000 / 60
|
|
|
|
local PANEL_IN, START = 10, 30
|
|
local LEVEL_FRAMES, COUNT_FRAMES, STEP_WAIT = 30, 40, 20
|
|
local CHEST_STEP, PLAYER_WAIT = 25, 600
|
|
|
|
local PRIZE_FRAMES, PRIZE_X, PRIZE_Y, PRIZE_ENEMY_DY = 120, 879, 426, -64
|
|
local PRIZE_KIND = { song = "ai_reward_song", costume = "battle_reward_costume", title = "ai_reward_title" }
|
|
local BOSS_REWARD_DY = 68
|
|
local CHEST_X, CHEST_Y = { 773, 851, 929 }, 273
|
|
|
|
local MOVE_UNLOCKS = { 0, 1, 2, 3, 5, 6, 7, 8, 9 }
|
|
local MOVE_HACCHAKE, EX_STAGE = 4, 11
|
|
|
|
local ORB_SWAP = 15
|
|
local MOVE_FRAMES, COMPLETE_FRAMES, BANNER_AT = 150, 240, 104
|
|
local BOSS_BANNER_X, BOSS_BANNER_Y = 403, 493
|
|
|
|
local WINDOW_SHAFTS = {
|
|
{ -151.65, 24, 4.801, 0.832, 21, 0.75 }, { 187.15, -93.8, 0.688, 0.466, 21, 1, true },
|
|
{ -241.05, -47.6, 0.828, 0.446, 26, 1, true },
|
|
}
|
|
|
|
local STREAKS = {
|
|
{ 0, 0.75, 0, 57, 94, 392.3, 25, -402.6, 1, 1, 1 },
|
|
{ 47.35, 0.312, 34, 89, 134, 210.3, 70, -422.65, 1, 1, 1 },
|
|
{ 71.35, 0.75, 59, 95, 137, 283.3, -145, -409.25, 0.151, 0.904, 0.151 },
|
|
}
|
|
|
|
local LEVEL_SPARKLES = { { -59, -63, 1, 5 }, { 52, -43, 0.917, 6 }, { 22, 65, 0.667, 7 }, { -76, 3, 0.833, 8 } }
|
|
|
|
local BANNER_SPARKLES = {
|
|
{ "complete_sparkle", 2.35, -41.65, 10 }, { "chest_sparkle", 31, -48.65, 25 }, { "chest_sparkle", -27, -49.65, 0 },
|
|
{ "chest_sparkle", -113, 34.95, 20 }, { "complete_sparkle", 95.35, 33.3, 0 },
|
|
}
|
|
|
|
local WHITE, BLACK = { 255, 255, 255, 255 }, { 0, 0, 0, 255 }
|
|
|
|
local function clamp01(v) return math.max(0, math.min(1, v)) end
|
|
local function ramp(t, at, len) return clamp01((t - at) / len) end
|
|
local function lerp(a, b, u) return a + (b - a) * u end
|
|
|
|
local function swell(u) return 1 - math.abs(2 * u - 1) end
|
|
local function ease_out(u) return 1 - (1 - u) * (1 - u) end
|
|
local function pop(t, at)
|
|
if t < at then return 0 end
|
|
local u = t - at
|
|
return u < 6 and lerp(1.4, 0.9, u / 6) or u < 10 and lerp(0.9, 1, (u - 6) / 4) or 1
|
|
end
|
|
|
|
local function tip_rows(key)
|
|
local rows = {}
|
|
for row in (tex.skin_text(key) .. "\n"):gmatch("(.-)\n") do
|
|
rows[#rows + 1] = text.create_raw_text(row, 20, BLACK, WHITE, false, 4, 2)
|
|
end
|
|
return rows
|
|
end
|
|
|
|
local function play(name)
|
|
if audio.has_sound(name) then audio.play_sound(name, name:find("^vo_") and "voice" or "sound") end
|
|
end
|
|
|
|
function BattleResultBoard.new(data)
|
|
local self = setmetatable({}, BattleResultBoard)
|
|
self.ids, self.sizes = {}, {}
|
|
self.data = data
|
|
self.f = 0
|
|
self.started = false
|
|
self.played = {}
|
|
tex.load_folder("battle_result", "board")
|
|
if audio.has_sound("battle_bgm") then audio.play_sound("battle_bgm", "music") end
|
|
return self
|
|
end
|
|
|
|
local function level_segments(before, after)
|
|
local fill = function(s) return s.exp_next > 0 and s.exp / s.exp_next or 1 end
|
|
if after.bond == before.bond then
|
|
return { { level = before.bond, from = fill(before), to = fill(after) } }
|
|
end
|
|
local segs = { { level = before.bond, from = fill(before), to = 1, up = true } }
|
|
for level = before.bond + 1, after.bond - 1 do
|
|
segs[#segs + 1] = { level = level, from = 0, to = 1, up = true }
|
|
end
|
|
segs[#segs + 1] = { level = after.bond, from = 0, to = fill(after) }
|
|
return segs
|
|
end
|
|
|
|
function BattleResultBoard:begin(answer)
|
|
local d = self.data
|
|
self.answer = answer
|
|
self.start_ms = nil
|
|
self.f = 0
|
|
self.played = {}
|
|
self.leaving = false
|
|
local t = START
|
|
if answer then
|
|
self.segs = level_segments(answer.before, answer.after)
|
|
self.exp_at = t
|
|
t = t + #self.segs * LEVEL_FRAMES + STEP_WAIT
|
|
end
|
|
self.power_at = t
|
|
t = t + COUNT_FRAMES + STEP_WAIT
|
|
self.fight_at = t
|
|
t = t + COUNT_FRAMES + STEP_WAIT
|
|
if d.boss then t = t + 30 end
|
|
self.boss = answer and answer.boss or (d.boss and {
|
|
hp_before = d.boss_hp, hp_after = math.max(0, d.boss_hp - d.damage), max = d.boss_hp_max,
|
|
}) or nil
|
|
if answer then
|
|
self.chest_at = t
|
|
t = t + #answer.chests * CHEST_STEP + (#answer.chests > 0 and STEP_WAIT or 0)
|
|
self.unlocked = answer.after.moves > answer.before.moves
|
|
if self.unlocked then
|
|
self.move_at = t
|
|
self.move_complete = answer.after.move_cost < 0
|
|
self.move_id = MOVE_UNLOCKS[answer.after.moves] or 0
|
|
self.move_kind = text.create_text("battle_reward_move", WHITE, BLACK, false, 5, 2)
|
|
self.tip = tip_rows("battle_tip_move")
|
|
self.move_len = self.move_complete and COMPLETE_FRAMES or MOVE_FRAMES
|
|
t = t + self.move_len
|
|
end
|
|
|
|
if answer.before.orb_cost > 0 then
|
|
self.orb_swap_at = t
|
|
self.orb_at = t + ORB_SWAP
|
|
t = self.orb_at + #answer.orb_chests * CHEST_STEP + STEP_WAIT
|
|
local orb = answer.orb_reward
|
|
if orb then
|
|
self.orb_prize_at = t
|
|
t = t + MOVE_FRAMES
|
|
local move = orb.kind == "move"
|
|
self.orb_kind = text.create_text(move and "battle_reward_move" or PRIZE_KIND.song, WHITE, BLACK, false,
|
|
5, 2)
|
|
self.orb_name = not move and text.create_raw_text(orb.name, 30, WHITE, BLACK, false, 5, 2) or nil
|
|
self.orb_tip = tip_rows(move and "battle_tip_move" or "battle_tip_maou")
|
|
end
|
|
end
|
|
end
|
|
local prize = answer and answer.reward
|
|
if prize and PRIZE_KIND[prize.kind] then
|
|
self.prize_at = t
|
|
t = t + PRIZE_FRAMES
|
|
self.prize_kind = text.create_text(PRIZE_KIND[prize.kind], WHITE, BLACK, false, 5, 2)
|
|
self.prize_name = text.create_raw_text(prize.name, 30, WHITE, BLACK, false, 5, 2)
|
|
end
|
|
self.end_at = t
|
|
self.deadline = t + PLAYER_WAIT
|
|
self.best = answer and d.power > answer.before.best_power
|
|
self.started = true
|
|
play("vo_call")
|
|
end
|
|
|
|
function BattleResultBoard:decide()
|
|
if self.leaving or not self.started then return false end
|
|
if self.f < self.end_at then
|
|
self.start_ms = self.now_ms - self.end_at * FRAME_MS
|
|
self.f = self.end_at
|
|
self.skipped = true
|
|
return true
|
|
end
|
|
self.leaving = true
|
|
return true
|
|
end
|
|
|
|
function BattleResultBoard:is_done()
|
|
return self.leaving
|
|
end
|
|
|
|
function BattleResultBoard:once(key, at)
|
|
if not self.played[key] and self.f >= at then
|
|
self.played[key] = true
|
|
return not self.skipped
|
|
end
|
|
return false
|
|
end
|
|
|
|
function BattleResultBoard:update(ms)
|
|
self.now_ms = ms
|
|
if not self.started then return end
|
|
self.start_ms = self.start_ms or ms
|
|
self.f = (ms - self.start_ms) / FRAME_MS
|
|
local d, a = self.data, self.answer
|
|
if self.segs then
|
|
for i, seg in ipairs(self.segs) do
|
|
local at = self.exp_at + (i - 1) * LEVEL_FRAMES
|
|
if self:once("exp" .. i, at) then play("num_up") end
|
|
if seg.up and self:once("lvup" .. i, at + LEVEL_FRAMES) then
|
|
play(i == 1 and "vo_lvup" or "se_kime")
|
|
end
|
|
end
|
|
end
|
|
if self:once("power", self.power_at) then play("num_up") end
|
|
if self:once("power_end", self.power_at + COUNT_FRAMES) then play("se_kime") end
|
|
if self:once("fight", self.fight_at) then play("num_up") end
|
|
if self:once("fight_end", self.fight_at + COUNT_FRAMES) then
|
|
play("se_kime")
|
|
if self.boss then
|
|
local won = self.boss.hp_after == 0
|
|
play(won and "se_boss_win" or "vo_boss_fail")
|
|
if won then play("vo_boss_win") end
|
|
end
|
|
end
|
|
if a then
|
|
for i, n in ipairs(a.chests) do
|
|
if self:once("chest" .. i, self.chest_at + (i - 1) * CHEST_STEP) then
|
|
play("se_treasure")
|
|
play(n >= 5 and "se_treasure_big" or "se_treasure_small")
|
|
end
|
|
end
|
|
if self.unlocked and self:once("reward", self.move_at) then
|
|
play("se_reward_window")
|
|
play("vo_reward_get")
|
|
end
|
|
if self.move_complete and self:once("complete", self.move_at + BANNER_AT) then play("se_complete") end
|
|
for i, n in ipairs(self.orb_at and a.orb_chests or {}) do
|
|
if self:once("orb_chest" .. i, self.orb_at + (i - 1) * CHEST_STEP) then
|
|
play("se_treasure")
|
|
play(n >= 5 and "se_treasure_big" or "se_treasure_small")
|
|
end
|
|
end
|
|
if self.orb_prize_at and self:once("orb_prize", self.orb_prize_at) then
|
|
play("se_reward_window")
|
|
play("vo_reward_get")
|
|
end
|
|
end
|
|
if self.prize_at and self:once("prize", self.prize_at) then
|
|
play("se_reward_window")
|
|
play("vo_reward_get")
|
|
end
|
|
if self.f >= self.deadline then self.leaving = true end
|
|
end
|
|
|
|
function BattleResultBoard:put(key, cx, cy, o)
|
|
o = o or {}
|
|
local path = (o.dir or "battle_result/board") .. "/" .. key
|
|
local id = self.ids[path]
|
|
if id == nil then
|
|
id = tex.get_texture(path)
|
|
self.ids[path] = id
|
|
self.sizes[path] = tex.get_texture_info(path:match("([^/]+)/[^/]+$"), key)
|
|
end
|
|
local info = self.sizes[path]
|
|
if not info then return end
|
|
local sx, sy = o.sx or o.s or 1, o.sy or o.s or 1
|
|
local w, h = info.width * S, info.height * S
|
|
tex.draw_texture(id, {
|
|
x = cx * S, y = cy * S,
|
|
x2 = w * (sx - 1), y2 = h * (sy - 1),
|
|
origin = { w * sx * 0.5, h * sy * 0.5 },
|
|
fade = o.fade or 1,
|
|
frame = o.frame or 0,
|
|
blend = o.add and "additive" or nil,
|
|
})
|
|
end
|
|
|
|
function BattleResultBoard:bar(key, left, cy, width, u, o)
|
|
if u <= 0 then return end
|
|
o = o or {}
|
|
o.sx = u
|
|
self:put(key, left + width * u * 0.5, cy, o)
|
|
end
|
|
|
|
function BattleResultBoard:number(key, value, right_x, y, step, o)
|
|
value = math.max(0, math.floor(value))
|
|
local x = right_x
|
|
repeat
|
|
o = o or {}
|
|
o.frame = value % 10
|
|
self:put(key, x, y, o)
|
|
value = value // 10
|
|
x = x - step
|
|
until value == 0
|
|
return x
|
|
end
|
|
|
|
function BattleResultBoard:draw_background()
|
|
local stage = self.data.stage
|
|
self:put("stage", 640, 360, { frame = (self.data.boss or stage % 2 == 1) and stage - 1 or stage - 2 })
|
|
self:put("header_band", 638, 47)
|
|
self:put("title", 182, 45)
|
|
self:put("song_count", 323, 44, { frame = math.max(0, math.min(3, self.data.song_number - 1)) })
|
|
self:put("stage_plate", 110, 115)
|
|
if stage == EX_STAGE then
|
|
self:put("stage_ex", 133, 107)
|
|
else
|
|
self:number("stage_digits", stage, 138, 107, 10)
|
|
end
|
|
if self.started and self.f >= self.end_at then
|
|
self:put("skip_hint", 1082, 688, { fade = 0.6 + 0.4 * math.cos(self.f / 20) })
|
|
end
|
|
end
|
|
|
|
function BattleResultBoard:draw_bond(fade)
|
|
local a = self.answer
|
|
self:put("bond_panel", 491, 288, { fade = fade })
|
|
self:put("partner", 369, 282, { s = 0.62, fade = fade })
|
|
self:put("exp_gauge_back", 550, 329, { fade = fade })
|
|
local level, fill, up_at = self.data.bond, 0, nil
|
|
if a then
|
|
local t = self.f - self.exp_at
|
|
local idx = math.max(1, math.min(#self.segs, math.floor(t / LEVEL_FRAMES) + 1))
|
|
local seg = self.segs[idx]
|
|
level = seg.level
|
|
fill = lerp(seg.from, seg.to, ease_out(ramp(t, (idx - 1) * LEVEL_FRAMES, LEVEL_FRAMES)))
|
|
if t >= LEVEL_FRAMES then
|
|
for i = idx - 1, 1, -1 do
|
|
if self.segs[i].up then up_at = self.exp_at + i * LEVEL_FRAMES break end
|
|
end
|
|
end
|
|
if t < 0 then level, fill = a.before.bond, self.segs[1].from end
|
|
end
|
|
self:bar(fill >= 1 and "exp_gauge_full" or "exp_gauge_fill", 440, 329, 220, fill, { fade = fade })
|
|
self:put("exp_gauge_frame", 550, 329, { fade = fade })
|
|
local digits = up_at and "bond_digits_up" or "bond_digits"
|
|
local s = up_at and pop(self.f, up_at) or 1
|
|
self:number(digits, level, 644, 298, 24, { s = s, fade = fade })
|
|
if up_at then
|
|
local u = self.f - up_at
|
|
self:put("bond_glow", 637, 297, { add = true, fade = fade * (1 - ramp(u, 0, 20)) })
|
|
local flash = ramp(u, 0, 15)
|
|
self:put("levelup_flash", 375, 292, { add = true, s = lerp(1, 1.3, flash), fade = fade * (1 - flash) })
|
|
self:put("levelup_gauge", 550, 329, { sx = 0.995, sy = 1.1, fade = fade })
|
|
self:put("levelup_glow", 550, 327, { fade = fade * (0.6 + 0.4 * math.cos(u / 10)) })
|
|
if u >= 25 then self:put("levelup_shine", 550, 329, { sx = 1.032, sy = 1.1, add = true, fade = fade }) end
|
|
self:put("levelup_text", 550, 327, { s = pop(self.f, up_at), fade = fade })
|
|
for _, s in ipairs(LEVEL_SPARKLES) do
|
|
local v = u - s[4]
|
|
if v >= 0 and v < 80 then
|
|
self:put("levelup_sparkle", 374 + s[1], 292 + s[2],
|
|
{ s = s[3], add = true, fade = fade * swell(v % 40 / 40) })
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function BattleResultBoard:draw_power(fade)
|
|
local d = self.data
|
|
local u = ease_out(ramp(self.f, self.power_at, COUNT_FRAMES))
|
|
self:put("power_box", 491, 404, { fade = fade })
|
|
self:number("count_digits", d.power * u, 633, 403, 23, { fade = fade })
|
|
if self.best and self.f >= self.power_at + COUNT_FRAMES then
|
|
local t = self.f - self.power_at - COUNT_FRAMES
|
|
local y = 369 + lerp(47, 0, ease_out(ramp(t, 0, 15))) - 3 * math.sin(t / 20)
|
|
local f = fade * ramp(t, 0, 15)
|
|
self:put("best_bubble", 560, y, { s = 0.934, fade = f })
|
|
local left = self:number("best_digits", d.power - self.answer.before.best_power, 659, y + 1, 15, { fade = f })
|
|
self:put("best_plus", left + 2, y + 1, { fade = f })
|
|
end
|
|
end
|
|
|
|
function BattleResultBoard:draw_fight(fade)
|
|
local d = self.data
|
|
local u = ease_out(ramp(self.f, self.fight_at, COUNT_FRAMES))
|
|
if not self.boss then
|
|
self:put("kills_box", 491, 480, { fade = fade })
|
|
self:number("count_digits", d.kills * u, 633, 493, 23, { fade = fade })
|
|
return
|
|
end
|
|
local b = self.boss
|
|
self:put("damage_box", 491, 527, { fade = fade })
|
|
self:number("damage_digits", d.damage * u, 645, 562, 20, { fade = fade })
|
|
local max = math.max(1, b.max)
|
|
local before, now = b.hp_before / max, lerp(b.hp_before, b.hp_after, u) / max
|
|
self:put("boss_gauge_back", 429, 525, { fade = fade })
|
|
self:bar("boss_gauge_lost", 319, 525, 220, before, { fade = fade })
|
|
local color = now > 0.5 and 0 or now > 0.2 and 1 or 2
|
|
self:bar("boss_gauge_fill", 319, 525, 220, now, { frame = color, fade = fade })
|
|
self:put("boss_life_frame", 427, 518, { fade = fade })
|
|
if now > 0 then self:put("boss_gauge_marker", 319 + 220 * now, 524, { fade = fade }) end
|
|
local t = self.f - self.fight_at - COUNT_FRAMES
|
|
if t >= 0 then self:draw_boss_banner(t, b.hp_after == 0, fade) end
|
|
end
|
|
|
|
function BattleResultBoard:draw_boss_banner(t, won, fade)
|
|
local x, y = BOSS_BANNER_X, BOSS_BANNER_Y
|
|
if won then
|
|
local w = t < 16 and math.min(t / 7, (16 - t) / 9) or t < 21 and 0 or swell((t - 21) % 70 / 70)
|
|
self:put("boss_clear_burst", x, y + 1, { sx = 1 + 0.059 * w, sy = 1 + 0.077 * w, fade = fade })
|
|
self:put("boss_clear_text", x, y - 1, { s = 1 + 0.04 * swell(ramp(t, 0, 15)), fade = fade })
|
|
else
|
|
local w = t < 19 and t / 19 * 0.25 or swell((t - 19) % 71 / 71)
|
|
self:put("boss_replay_cloud", x - 1, y - 8, { s = 1 + 0.035 * w, fade = fade * ramp(t, 0, 6) })
|
|
if t >= 6 then self:put("boss_replay_text", x, y - 10, { fade = fade }) end
|
|
end
|
|
end
|
|
|
|
function BattleResultBoard:draw_reward(fade, orbs)
|
|
local a = self.answer
|
|
local dy = self.data.boss and BOSS_REWARD_DY or 0
|
|
local pre = orbs and "orb_" or ""
|
|
local at0, chests = orbs and self.orb_at or self.chest_at, orbs and a.orb_chests or a.chests
|
|
local got_at = orbs and self.orb_prize_at or self.move_at
|
|
local got = got_at and self.f >= got_at
|
|
local before, after = a.before, a.after
|
|
local complete
|
|
if orbs then
|
|
complete = after.orb_rewards >= 2 and (not got_at or got)
|
|
else
|
|
complete = after.move_cost < 0 and (not self.unlocked or got)
|
|
end
|
|
self:put("reward_back", 849, 343 + dy, { fade = fade })
|
|
if complete then
|
|
self:put("reward_complete", 850, 352 + dy, { fade = fade })
|
|
return
|
|
end
|
|
self:put(orbs and "orb_label" or "stone_label", 848, 194 + dy, { fade = fade })
|
|
local count = orbs and before.orbs or before.stones
|
|
for i, n in ipairs(chests) do
|
|
local at = at0 + (i - 1) * CHEST_STEP
|
|
local x, y = CHEST_X[i], CHEST_Y + dy
|
|
if self.f < at then
|
|
self:put(pre .. "chest_closed", x, y, { fade = fade })
|
|
else
|
|
count = count + n
|
|
local t = self.f - at
|
|
local glow = t < 72 and lerp(1, 0.578, t / 72) or 0.578 + 0.422 * swell((t - 72) % 104 / 104)
|
|
if n >= 5 then
|
|
self:put(pre .. "chest_glow", x, y, { fade = fade * glow })
|
|
self:put(pre .. "chest_open", x, y - 4, { fade = fade })
|
|
else
|
|
self:put(pre .. "chest_glow_small", x, y, { fade = fade * glow })
|
|
self:put(pre .. "chest_open_small", x, y, { fade = fade })
|
|
if n >= 3 then
|
|
local rays = t < 32 and 1 - t / 32 or t < 52 and (t - 32) / 20
|
|
or 1 - 0.22 * swell((t - 52) % 104 / 104)
|
|
self:put("chest_rays", x, y, { fade = fade * rays })
|
|
end
|
|
end
|
|
local frame = n >= 5 and 2 or n >= 3 and 1 or 0
|
|
local rise = 30 + 10 * ease_out(ramp(t, 0, 10))
|
|
self:put(orbs and "orb_chest_orbs" or "chest_stones", x, y - rise, { frame = frame, s = pop(self.f, at),
|
|
fade = fade })
|
|
if t < 20 then
|
|
self:put("chest_sparkle", x + 30, y - 30, { s = 1 + t / 20, fade = fade * (1 - t / 20) })
|
|
end
|
|
end
|
|
end
|
|
local cost = orbs and before.orb_cost or before.move_cost
|
|
if got then
|
|
count, cost = orbs and after.orbs or after.stones, orbs and after.orb_cost or after.move_cost
|
|
end
|
|
self:number("stone_digits", count, 826, 357 + dy, 25, { fade = fade })
|
|
self:put("stone_slash", 862, 357 + dy, { fade = fade })
|
|
if cost >= 0 then self:number("stone_digits", cost, 940, 357 + dy, 25, { fade = fade }) end
|
|
if orbs then
|
|
self:put("orb_next_box", 849, 446 + dy, { fade = fade * 0.891 })
|
|
else
|
|
self:put("next_box", 849, 448 + dy, { fade = fade })
|
|
end
|
|
end
|
|
|
|
function BattleResultBoard:draw_window(fade, t, kind, name, tip, complete, move_id)
|
|
local grow, settle = ramp(t, 0, 16), ramp(t, 16, 3)
|
|
local sx, sy = lerp(lerp(1, 1.25, grow), 1, settle), lerp(lerp(0.14, 1.25, grow), 1, settle)
|
|
local a = fade * grow
|
|
local cy = PRIZE_Y + (self.data.boss and 0 or PRIZE_ENEMY_DY) + lerp(8, 0, grow)
|
|
local function part(key, ox, oy, o)
|
|
o = o or {}
|
|
o.sx, o.sy = (o.sx or o.s or 1) * sx, (o.sy or o.s or 1) * sy
|
|
o.fade = (o.fade or 1) * a
|
|
self:put(key, PRIZE_X + ox * sx, cy + oy * sy, o)
|
|
end
|
|
local function label(obj, oy, f)
|
|
obj:draw({ x = PRIZE_X * S - obj.width / 2, y = (cy + oy * sy) * S - obj.height / 2, fade = f })
|
|
end
|
|
local function shafts(front)
|
|
for _, p in ipairs(WINDOW_SHAFTS) do
|
|
if (p[7] or false) == front and t >= p[5] then
|
|
local l = (t - p[5]) % 138
|
|
for _, s in ipairs(STREAKS) do
|
|
if l >= s[3] and l <= s[5] then
|
|
local rise = l <= s[4]
|
|
local u = rise and (l - s[3]) / (s[4] - s[3]) or (l - s[4]) / (s[5] - s[4])
|
|
local y = rise and lerp(s[6], s[7], u) or lerp(s[7], s[8], u)
|
|
local ys = rise and lerp(s[9], s[10], u) or lerp(s[10], s[11], u)
|
|
part("window_streak", p[1] + s[1] * p[3], p[2] + y * p[4],
|
|
{ sx = s[2] * p[3], sy = ys * p[4], fade = p[6] * (rise and u or 1 - u) })
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
local breath = t < 21 and 1 or 1 - 0.7 * swell((t - 21) % 94 / 94)
|
|
shafts(false)
|
|
part("reward_window_glow", 0, 0, { fade = t < 21 and 1 or 0.6 + 0.4 * swell((t - 21) % 94 / 94) })
|
|
part("reward_window", 0, 0)
|
|
local h = t % 130
|
|
for i, word in ipairs({ { "reward_new", -110, 0 }, { "reward_get", 2, 22 }, { "reward_got", 118, 40 } }) do
|
|
local u = h - word[3]
|
|
local hop = u >= 0 and u < 21 and 7 * (1 - math.abs(u - 10) / 10) or 0
|
|
part(word[1], word[2], -123 - hop)
|
|
end
|
|
local plate = t < 12 and 1 or t < 17 and lerp(1, 1.222, (t - 12) / 5) or lerp(1.222, 1, ramp(t, 17, 3))
|
|
if t >= 21 then part("reward_plate_glow", 1, -16, { fade = breath }) end
|
|
part("reward_plate", 0, -15, { s = plate })
|
|
local tf = a * ramp(t, 12, 8)
|
|
label(kind, -32, tf)
|
|
if name then
|
|
label(name, -2, tf)
|
|
else
|
|
part("skill_name", 0, -2, { dir = "song_select/enso_battle", frame = move_id, fade = ramp(t, 12, 8) })
|
|
end
|
|
if tip and not (complete and t >= BANNER_AT) then
|
|
for i, row in ipairs(tip) do label(row, 80 + (i - (#tip + 1) / 2) * 26, a * ramp(t, 17, 3)) end
|
|
end
|
|
shafts(true)
|
|
if complete and t >= BANNER_AT then
|
|
local u = t - BANNER_AT
|
|
local s = u < 5 and lerp(1, 1.83, u / 5) or u < 14 and lerp(1.715, 0.915, (u - 6) / 8) or
|
|
lerp(0.943, 1, ramp(u, 14, 2))
|
|
part("complete_banner", -1, 85, { s = s, fade = ramp(u, 0, 5) })
|
|
for _, k in ipairs(BANNER_SPARKLES) do
|
|
part(k[1], k[2] - 1, k[3] + 85, { fade = ramp(u, 0, 5) * swell((u - k[4] + 50) % 100 / 100) })
|
|
end
|
|
end
|
|
end
|
|
|
|
function BattleResultBoard:nameplate_pos()
|
|
if not self.started then return nil end
|
|
return { 285 * S, 157 * S, ramp(self.f, 0, PANEL_IN) }
|
|
end
|
|
|
|
function BattleResultBoard:draw()
|
|
if not self.started then return end
|
|
local fade = ramp(self.f, 0, PANEL_IN)
|
|
local d = self.data
|
|
local side = d.player == 2 and "_2p" or ""
|
|
if d.boss then
|
|
self:put("panel_boss" .. side, 646, 380, { fade = fade })
|
|
else
|
|
self:put("panel_enemy" .. side, 645, 345, { fade = fade })
|
|
end
|
|
self:put("difficulty", 620, 212, { frame = math.max(0, math.min(4, d.difficulty)), fade = fade })
|
|
self:draw_bond(fade)
|
|
self:draw_power(fade)
|
|
self:draw_fight(fade)
|
|
if self.prize_at and self.f >= self.prize_at then
|
|
self:draw_window(fade, self.f - self.prize_at, self.prize_kind, self.prize_name)
|
|
elseif self.orb_prize_at and self.f >= self.orb_prize_at then
|
|
self:draw_window(fade, self.f - self.orb_prize_at, self.orb_kind, self.orb_name, self.orb_tip, false,
|
|
MOVE_HACCHAKE)
|
|
elseif self.move_at and self.f >= self.move_at and self.f < self.move_at + self.move_len then
|
|
self:draw_window(fade, self.f - self.move_at, self.move_kind, nil, self.tip, self.move_complete, self.move_id)
|
|
elseif self.orb_swap_at and self.f >= self.orb_swap_at then
|
|
local u = ramp(self.f, self.orb_swap_at, ORB_SWAP)
|
|
if u < 1 then self:draw_reward(fade * (1 - u)) end
|
|
self:draw_reward(fade * u, true)
|
|
elseif self.answer then
|
|
self:draw_reward(fade)
|
|
end
|
|
end
|