148 lines
5.5 KiB
Lua
148 lines
5.5 KiB
Lua
BattleSelectInfo = {}
|
|
BattleSelectInfo.__index = BattleSelectInfo
|
|
|
|
local S = tex.get_screen_scale()
|
|
local FRAME_MS = 1000 / 60
|
|
local DIR = "song_select/enso_battle/"
|
|
local WHITE = { 255, 255, 255, 255 }
|
|
local BLACK = { 0, 0, 0, 255 }
|
|
|
|
local SLIDE_FRAMES, SLIDE_FROM = 18, -202
|
|
local BOB_FRAMES = 35
|
|
local CARD = { { 101, 357 }, { 1184, 356 } }
|
|
local PARTNER = { { 93, 535 }, { 1202, 535 } }
|
|
local EXP_FULL_SCALE = 1.192
|
|
local EXP_FULL_WIDTH = 104 * EXP_FULL_SCALE
|
|
local STAGE_NAME_WIDTH = 140
|
|
local BOSS_LIFE_RIGHT, BOSS_LIFE_WIDTH = 696.3, 136
|
|
local TOKEN_X, TOKEN_Y = 431, 660
|
|
-- during the Maou event the stones token moves up for the orbs token below it
|
|
local EVENT_STONES_DY, EVENT_ORBS_DY = -14, 24
|
|
local EX_STAGE = 11
|
|
local CURRENT_ONES_X = { 427, 433, 440 }
|
|
local GOAL_ONES_X = { 473.5, 478.5, 485.5 }
|
|
|
|
local function clamp01(v) return math.max(0, math.min(1, v)) end
|
|
local function triangle(f, period) return 1 - math.abs(2 * (f % period) / period - 1) end
|
|
|
|
function BattleSelectInfo.new(data)
|
|
local self = setmetatable({}, BattleSelectInfo)
|
|
self.ids, self.sizes = {}, {}
|
|
self.data = data
|
|
self.start_ms = nil
|
|
tex.load_folder("song_select", "enso_battle")
|
|
self.partner_name = text.create_text("battle_partner_amitie", WHITE, BLACK, false, 3)
|
|
self.stage_name = text.create_text("battle_stage_" .. data.stage, WHITE, BLACK, false, 3)
|
|
return self
|
|
end
|
|
|
|
function BattleSelectInfo:put(key, cx, cy, o)
|
|
o = o or {}
|
|
local id = self.ids[key]
|
|
if id == nil then
|
|
id = tex.get_texture(DIR .. key)
|
|
self.ids[key] = id
|
|
self.sizes[key] = tex.get_texture_info("enso_battle", key)
|
|
end
|
|
local info = self.sizes[key]
|
|
if not info then return end
|
|
local sx, sy = o.sx or 1, o.sy 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 },
|
|
frame = o.frame or 0,
|
|
mirror = o.mirror,
|
|
})
|
|
end
|
|
|
|
function BattleSelectInfo:digits(key, value, ones_x, y, step)
|
|
value = math.max(0, math.floor(value))
|
|
local x = ones_x
|
|
repeat
|
|
self:put(key, x, y, { frame = value % 10 })
|
|
value = value // 10
|
|
x = x - step
|
|
until value == 0
|
|
end
|
|
|
|
local function digit_count(value)
|
|
return #tostring(math.max(0, math.floor(value)))
|
|
end
|
|
|
|
local function draw_label(label, cx, cy, max_width)
|
|
local squash = max_width and math.max(0, label.width - max_width * S) or 0
|
|
label:draw({ x = cx * S - (label.width - squash) / 2, y = cy * S - label.height / 2, x2 = -squash })
|
|
end
|
|
|
|
function BattleSelectInfo:draw_partner(f)
|
|
local d = self.data
|
|
local side = d.player == 2 and 2 or 1
|
|
local slide = SLIDE_FROM * (1 - clamp01(f / SLIDE_FRAMES)) * (side == 2 and -1 or 1)
|
|
local bob = triangle(f, BOB_FRAMES)
|
|
local px, py = PARTNER[side][1] + slide, PARTNER[side][2]
|
|
local mirror = side == 2 and "horizontal" or nil
|
|
self:put("partner_body", px, py + 3 * bob, { sy = 1 - 0.037 * bob, mirror = mirror })
|
|
self:put("partner_front", px, py + 5 * bob, { mirror = mirror })
|
|
|
|
local cx, cy = CARD[side][1] + slide, CARD[side][2]
|
|
self:put("card", cx, cy, { frame = side - 1 })
|
|
draw_label(self.partner_name, cx, cy - 55, 116)
|
|
self:digits("card_digits", d.bond, cx + (d.bond < 10 and 29 or 35), cy - 27, 13)
|
|
local fill = d.exp_next > 0 and clamp01(d.exp / d.exp_next) or 1
|
|
self:put("exp_back", cx, cy - 7)
|
|
if fill > 0 then
|
|
self:put("exp_fill", cx - 60.7 + EXP_FULL_WIDTH * fill / 2, cy - 7.7, { sx = EXP_FULL_SCALE * fill })
|
|
end
|
|
self:put("exp_frame", cx, cy - 7)
|
|
self:digits("card_digits", math.min(d.best_power, 99999), cx + 27, cy + 43, 13.5)
|
|
end
|
|
|
|
function BattleSelectInfo:draw_stage()
|
|
local d = self.data
|
|
local boss = d.boss_hp_max > 0
|
|
self:put(boss and "stage_box_boss" or "stage_box", 640, 653)
|
|
self:put("stage_thumb", 732, 652, { frame = d.stage - 1 })
|
|
if d.stage == EX_STAGE then
|
|
self:put("stage_ex", 530.8, 658.3)
|
|
else
|
|
self:digits("stage_digits", d.stage, d.stage < 10 and 531.8 or 540.8, 658.3, 19)
|
|
end
|
|
draw_label(self.stage_name, 627, boss and 646.3 or 657.3, STAGE_NAME_WIDTH)
|
|
if not boss then return end
|
|
local life = clamp01(d.boss_hp / d.boss_hp_max)
|
|
self:put("boss_life_back", 627.9, 661.3)
|
|
if life > 0 then
|
|
local colour = life > 0.65 and 0 or life > 0.32 and 1 or 2
|
|
self:put("boss_life_fill", BOSS_LIFE_RIGHT - BOSS_LIFE_WIDTH * life / 2, 663.2, { sx = life, frame = colour })
|
|
end
|
|
self:put("boss_life_frame", 627.8, 661.3)
|
|
end
|
|
|
|
function BattleSelectInfo:draw_token(kind, count, cost, y)
|
|
if cost < 0 then
|
|
self:put(kind .. "_complete", TOKEN_X, y)
|
|
return
|
|
end
|
|
count, cost = math.min(count, 999), math.min(cost, 999)
|
|
self:put(kind .. "_token", TOKEN_X, y)
|
|
self:digits("card_digits", count, CURRENT_ONES_X[digit_count(count)], y - 1, 14)
|
|
self:put("token_slash", 452.5, y)
|
|
self:digits("token_digits", cost, GOAL_ONES_X[digit_count(cost)], y, 12)
|
|
end
|
|
|
|
function BattleSelectInfo:draw(ms)
|
|
self.start_ms = self.start_ms or ms
|
|
local f = (ms - self.start_ms) / FRAME_MS
|
|
self:draw_stage()
|
|
local d = self.data
|
|
if d.orb_cost > 0 or d.orbs_done then
|
|
self:draw_token("stone", d.stones, d.move_cost, TOKEN_Y + EVENT_STONES_DY)
|
|
self:draw_token("orb", d.orbs, d.orbs_done and -1 or d.orb_cost, TOKEN_Y + EVENT_ORBS_DY)
|
|
else
|
|
self:draw_token("stone", d.stones, d.move_cost, TOKEN_Y)
|
|
end
|
|
self:draw_partner(f)
|
|
end
|