102 lines
5.0 KiB
Lua
102 lines
5.0 KiB
Lua
-- Global credit line / QR chip / 2P invite cloud, drawn on every non-game screen.
|
|
|
|
CoinOverlay = {}
|
|
CoinOverlay.__index = CoinOverlay
|
|
|
|
local ca_ok, cs_anim = pcall(require, "anim/sampler")
|
|
if not ca_ok then cs_anim = { safe = function()
|
|
local n = {}
|
|
n.at = function() return nil end; n.get = function() return nil end
|
|
n.label = function() return nil end; n.has = function() return false end
|
|
n.first = function() return 0 end; n.last = function() return 0 end
|
|
return n
|
|
end } end
|
|
local credit_side = cs_anim.safe("anim/credit_side")
|
|
local credit_side_len = math.max(1, credit_side:last() - credit_side:first() + 1) -- 180 frames = 3 s
|
|
local credit_side_pop_f = 8
|
|
|
|
function CoinOverlay.new()
|
|
local self = setmetatable({}, CoinOverlay)
|
|
self.text = text.create_text("free_play", { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, 3, 5)
|
|
self.config = tex.get_skin_config("free_play")
|
|
self.qr = tex.get_texture("global/overlay/banapass_osaifu_keitai") -- QR chip (0 NG / 1 OK)
|
|
self.bubble = tex.get_texture("global/overlay/camera") -- 2P cloud bubble
|
|
self.bubble_player = text.create_text("credit_side_player", { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, 4, 2)
|
|
self.bubble_msg = text.create_text("credit_side_msg", { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, 4, 2)
|
|
self.bubble_cfg_p = tex.get_skin_config("credit_side_player")
|
|
self.bubble_cfg_m = tex.get_skin_config("credit_side_msg")
|
|
self.blink_t0 = tex.get_current_ms()
|
|
return self
|
|
end
|
|
|
|
function CoinOverlay:update(current_ms) end
|
|
|
|
local FREE_PLAY_CY = 1046
|
|
local BUBBLE_PLAYER_CY = 749
|
|
local BUBBLE_MSG_CY = 802
|
|
local BUBBLE_BOX_W = 416 -- cloud art width
|
|
|
|
-- Centred, whole-pixel-snapped OutlinedText draw clamped to `box_w`.
|
|
local function draw_bubble_line(t, cfg, cx, cy, fade)
|
|
if not t or t.width == nil then return end
|
|
local w = math.floor(math.min(t.width, BUBBLE_BOX_W) + 0.5)
|
|
t:draw({ x = math.floor(cx - w / 2 - cfg.x + 0.5),
|
|
y = math.floor(cy - t.height / 2 - cfg.y + 0.5),
|
|
x2 = w - t.width,
|
|
fade = fade })
|
|
end
|
|
|
|
local CREDIT_SCREENS = {
|
|
ENTRY = true,
|
|
PRACTICE_SELECT = true, AI_SELECT = true,
|
|
TITLE = true, RESULT = true,
|
|
-- DAN_SELECT and SONG_SELECT intentionally absent (no credit line there).
|
|
}
|
|
|
|
function CoinOverlay:draw(x, y)
|
|
local screen = tex.current_screen and tex.current_screen() or ""
|
|
-- unknown/blank screen keeps the always-on behaviour
|
|
local show_credit = (screen == "") or (CREDIT_SCREENS[screen] == true)
|
|
if show_credit then
|
|
local text_x = math.floor(tex.get_screen_width() / 2 - self.text.width / 2 - self.config.x + 0.5)
|
|
local text_y = math.floor(FREE_PLAY_CY - self.text.height / 2 - self.config.y + 0.5)
|
|
self.text:draw({ x = text_x, y = text_y })
|
|
end
|
|
if tex.in_transition and tex.in_transition() then return end
|
|
-- per-frame hook for a screen to draw above the credit text
|
|
if YD_DRAW_ABOVE_CREDIT then
|
|
local fn = YD_DRAW_ABOVE_CREDIT
|
|
YD_DRAW_ABOVE_CREDIT = nil
|
|
fn()
|
|
end
|
|
|
|
local chip_screens = (screen == "ENTRY" or screen == "SONG_SELECT" or screen == "SONG_SELECT_2P"
|
|
or screen == "PRACTICE_SELECT" or screen == "AI_SELECT" or screen == "DAN_SELECT")
|
|
if chip_screens and not (tex.in_transition and tex.in_transition()) then
|
|
tex.draw_texture(self.qr, { frame = 0 })
|
|
end
|
|
|
|
local scr = (screen ~= "") and screen or "ENTRY"
|
|
local on_entry_or_select = (scr == "ENTRY" or scr == "SONG_SELECT" or scr == "SONG_SELECT_2P"
|
|
or scr == "PRACTICE_SELECT" or scr == "AI_SELECT")
|
|
local pn = tex.player_num()
|
|
local both_joined = (pn == 3) or (scr == "SONG_SELECT_2P")
|
|
or (scr == "ENTRY" and YD_ENTRY_BOTH_JOINED == true)
|
|
local credit_up = (scr == "ENTRY") and YD_ENTRY_CREDIT_MS ~= nil
|
|
and (tex.get_current_ms() - YD_ENTRY_CREDIT_MS) < 100
|
|
local join_window = (scr == "ENTRY") or not tex.songs_played or (tex.songs_played() < 2)
|
|
if on_entry_or_select and join_window and not credit_up and not both_joined and (pn == 1 or pn == 2) then
|
|
local side = (pn == 1) and 0 or 1
|
|
local cx_p = (pn == 1) and self.bubble_cfg_p.x or (tex.get_screen_width() - self.bubble_cfg_p.x)
|
|
local cx_m = (pn == 1) and self.bubble_cfg_m.x or (tex.get_screen_width() - self.bubble_cfg_m.x)
|
|
local elapsed = tex.get_current_ms() - self.blink_t0
|
|
local f = (elapsed * 0.06) % credit_side_len -- arcade frame 0..179
|
|
local pop = math.min(1, elapsed * 0.06 / credit_side_pop_f) -- pop-in on first show
|
|
local fade = (credit_side:get("#3@0", f, "a") or 0) * pop
|
|
local fade_t = (credit_side:get("credit_all_instance", f, "a") or 0) * pop
|
|
tex.draw_texture(self.bubble, { index = side, fade = fade })
|
|
draw_bubble_line(self.bubble_player, self.bubble_cfg_p, cx_p, BUBBLE_PLAYER_CY, fade_t)
|
|
draw_bubble_line(self.bubble_msg, self.bubble_cfg_m, cx_m, BUBBLE_MSG_CY, fade_t)
|
|
end
|
|
end
|