217 lines
9.1 KiB
Lua
217 lines
9.1 KiB
Lua
-- YataiDONJuuyon entry screen. PyTaikoGreen's Entry with juu-yon's look (scenes/entry.tscn,
|
|
-- scenes/main_menu.tscn, scenes/objects/bumpin_panel.tscn, scenes/objects/control_banner.tscn):
|
|
-- * SELECT_SIDE = juu-yon's "Player Entry": closed curtain, the two drum holes with their name
|
|
-- banners, and the bouncing "P1 / P2 太鼓を叩いてスタート" panels (no side-select dialog);
|
|
-- * SELECT_MODE = juu-yon's "Main Menu" (boards: Scripts/entry/box.lua);
|
|
-- * header TaikoText "Player Entry" / "Main Menu" in the BannerTop; control banner at the bottom.
|
|
-- Numbers: Graphics/entry/MAPPING.md "Round 2". No engine change.
|
|
Entry = {}
|
|
Entry.__index = Entry
|
|
|
|
local SS = tex.get_screen_scale()
|
|
-- juu-yon's outline widths look too heavy at this skin's 960 px (user, 2026-09-27): every text
|
|
-- outline is drawn at OUTLINE_K of the juu-yon value.
|
|
local OUTLINE_K = 0.6
|
|
local WHITE, BLACK, DARK = { 255, 255, 255 }, { 0, 0, 0 }, { 27, 27, 27 }
|
|
local function rgba(c) return { c[1], c[2], c[3], 255 } end
|
|
|
|
-- keyed str -> colours -> size / outline radius (no key string built per lookup)
|
|
local text_cache = {}
|
|
local function raw_text(str, size, fill, outline, radius_px)
|
|
if not str or str == "" then return nil end
|
|
local k2 = ((fill[1] * 256 + fill[2]) * 256 + fill[3]) * 16777216
|
|
+ (outline[1] * 256 + outline[2]) * 256 + outline[3]
|
|
local k3 = size * 4096 + radius_px * 16
|
|
local by_str = text_cache[str]
|
|
local by_col = by_str and by_str[k2]
|
|
local t = by_col and by_col[k3]
|
|
if t == nil then
|
|
t = text.create_raw_text(str, size, rgba(fill), rgba(outline), false, radius_px * OUTLINE_K / SS, 2.0) or false
|
|
if not by_str then by_str = {}; text_cache[str] = by_str end
|
|
if not by_col then by_col = {}; by_str[k2] = by_col end
|
|
by_col[k3] = t
|
|
end
|
|
return t or nil
|
|
end
|
|
|
|
-- draw params reused call to call (tex.draw_texture / text:draw read them on the spot)
|
|
local DRAW_C = {}
|
|
local function draw_c(t, cx, cy, fade)
|
|
if t then
|
|
DRAW_C.x, DRAW_C.y, DRAW_C.fade = math.floor(cx - t.width / 2 + 0.5), math.floor(cy - t.height / 2 + 0.5), fade
|
|
t:draw(DRAW_C)
|
|
end
|
|
end
|
|
local XY_P = {}
|
|
local function XY(x, y) XY_P.x, XY_P.y = x, y; return XY_P end
|
|
|
|
-- TaikoText: second outline (outer), first outline, white fill (radius = outline_size / 2)
|
|
local function taiko_text(str, size, first_size, first_col, second_size, second_col, cx, cy, fade)
|
|
local o = raw_text(str, size, second_col, second_col, second_size / 2)
|
|
local i = raw_text(str, size, WHITE, first_col, first_size / 2)
|
|
draw_c(o, cx, cy, fade)
|
|
draw_c(i, cx, cy, fade)
|
|
return i
|
|
end
|
|
|
|
local function lines_of(s)
|
|
local out = {}
|
|
for line in (s .. "\n"):gmatch("(.-)\n") do out[#out + 1] = line end
|
|
return out
|
|
end
|
|
|
|
function Entry.new()
|
|
local self = setmetatable({}, Entry)
|
|
|
|
self.bg_flicker = tex.get_animation(1, "entry")
|
|
self.side_select_fade = tex.get_animation(0, "entry")
|
|
self.bg_flicker:start()
|
|
|
|
self.bg_bg = tex.get_texture("entry/background/bg")
|
|
self.ss_box_center = tex.get_texture("entry/side_select/box_center")
|
|
self.ss_footer = tex.get_texture("entry/side_select/footer")
|
|
|
|
self.hole = tex.get_texture("entry/jy_entry/hole")
|
|
self.hole_bottom = tex.get_texture("entry/jy_entry/hole_bottom")
|
|
self.banner = tex.get_texture("entry/jy_entry/banner")
|
|
self.bumper = { tex.get_texture("entry/jy_entry/bumper_p1"), tex.get_texture("entry/jy_entry/bumper_p2") }
|
|
self.taiko_guide = tex.get_texture("song_select/jy_select/taiko")
|
|
self.start_ms = tex.get_current_ms()
|
|
self.side_frame_ms = -1
|
|
return self
|
|
end
|
|
|
|
function Entry:update(current_ms)
|
|
self.bg_flicker:update(current_ms)
|
|
self.side_select_fade:update(current_ms)
|
|
end
|
|
|
|
function Entry:start_side_select() self.side_select_fade:start() end
|
|
function Entry:restart_side_select() self.side_select_fade:restart() end
|
|
function Entry:get_side_select_fade() return self.side_select_fade.attribute end
|
|
|
|
-- menu_bg.tscn (gradient + mainmenu/back.png), shared by entry.tscn and main_menu.tscn
|
|
function Entry:draw_background()
|
|
tex.draw_texture(self.bg_bg)
|
|
end
|
|
|
|
local BUMPER_RECTS = { { 48, 192 }, { 528, 184 } }
|
|
local PANEL_KEYS = { "jy_taiko_start_p1_panel", "jy_taiko_start_p2_panel" }
|
|
|
|
-- entry.tscn: Curtain (closed) + BigDons (y + 40): Player1 hole at (0, 424), Player2 at (480, 424),
|
|
-- HoleBottom in front (png = svg rows 72..276 -> y 496), Banner (88, 216) -> (88, 640) / (568, 640);
|
|
-- BumperP1 (48,192)-(440,360), BumperP2 (528,184)-(920,352) bouncing 0 -> -24 -> 0 every 0.6 s.
|
|
function Entry:draw_side_select()
|
|
self.side_frame_ms = tex.get_current_ms()
|
|
tex.draw_texture(self.ss_box_center)
|
|
for i = 0, 1 do
|
|
local ox = i * 480
|
|
tex.draw_texture(self.hole, XY(ox, 424))
|
|
tex.draw_texture(self.hole_bottom, XY(ox, 424 + 72))
|
|
tex.draw_texture(self.banner, XY(ox + 88, 640))
|
|
end
|
|
local t = ((tex.get_current_ms() - self.start_ms) / 600.0) % 1.0
|
|
local bump = -24 * math.sin(math.pi * t)
|
|
for i = 1, 2 do
|
|
local x, y = BUMPER_RECTS[i][1], BUMPER_RECTS[i][2] + bump
|
|
tex.draw_texture(self.bumper[i], XY(x, y))
|
|
-- Label: font 42 black, centred in the inner panel below margin_top 40 -> (12, 52)-(380, 156)
|
|
-- (the lines and their texts are built once per screen)
|
|
self.panel_labels = self.panel_labels or {}
|
|
local lab = self.panel_labels[i]
|
|
if not lab then
|
|
local ts, h = {}, 0
|
|
for k, s in ipairs(lines_of(tex.skin_text(PANEL_KEYS[i]))) do
|
|
ts[k] = raw_text(s, 42, BLACK, BLACK, 0.5); h = h + (ts[k] and ts[k].height or 0)
|
|
end
|
|
lab = { ts = ts, h = h }
|
|
self.panel_labels[i] = lab
|
|
end
|
|
local ts, h = lab.ts, lab.h
|
|
local cy = y + 104 - h / 2
|
|
for k = 1, #ts do
|
|
if ts[k] then draw_c(ts[k], x + 196, cy + ts[k].height / 2); cy = cy + ts[k].height end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- juu-yon joins by hitting your own drum: there are no 1P / cancel / 2P buttons.
|
|
function Entry:draw_side_select_buttons(side) end
|
|
|
|
-- BannerTop + ControlBanner chrome (side_select/footer.png), then per half either the join label
|
|
-- (ControlLabelP1/P2, font 32, outline 18) or, once that player is in, the select_taiko drum guide.
|
|
function Entry:draw_footer(p1_joined, p2_joined)
|
|
tex.draw_texture(self.ss_footer)
|
|
if p1_joined then
|
|
self:draw_drum_guide()
|
|
else
|
|
local t = raw_text(tex.skin_text("jy_taiko_start_p1"), 32, WHITE, BLACK, 9)
|
|
draw_c(t, 476 / 2, (606.656 + 720) / 2)
|
|
end
|
|
if not p2_joined then
|
|
local t = raw_text(tex.skin_text("jy_taiko_start_p2"), 32, WHITE, BLACK, 9)
|
|
draw_c(t, (484.16 + 960) / 2, (606.656 + 720) / 2)
|
|
end
|
|
end
|
|
|
|
local DECIDE_IN, DECIDE_OUT = { 240, 22, 8 }, { 67, 8, 1 }
|
|
local SIDE_IN, SIDE_OUT = { 65, 125, 173 }, { 16, 21, 59 }
|
|
local ENTRY_COL, MENU_COL = { 248, 72, 40 }, { 255, 39, 55 }
|
|
|
|
-- control_banner.tscn Player1 > TaikoP1 (224, 568) 192x192 + ControlLabels (see song_select.lua)
|
|
function Entry:draw_drum_guide()
|
|
local tx, ty = 224, 568
|
|
if self.taiko_guide then tex.draw_texture(self.taiko_guide, XY(tx, ty)) end
|
|
taiko_text(tex.skin_text("jy_ui_decide"), 36, 24, DECIDE_IN, 36, DECIDE_OUT, tx + 96, ty + 68)
|
|
taiko_text(tex.skin_text("jy_ui_left"), 36, 24, SIDE_IN, 36, SIDE_OUT, tx - 8, ty + 80)
|
|
taiko_text(tex.skin_text("jy_ui_right"), 36, 24, SIDE_IN, 36, SIDE_OUT, tx + 200, ty + 80)
|
|
end
|
|
|
|
-- BannerTop/TaikoText (32, 40)-(240, 80), font 42, outlines 28 / 42: "Player Entry" (first outline
|
|
-- (0.973, 0.282, 0.157)) while the curtain is shown, "Main Menu" ((1, 0.153, 0.216)) after.
|
|
function Entry:draw_player_entry()
|
|
local in_side = (tex.get_current_ms() - self.side_frame_ms) < 100
|
|
local key = in_side and "jy_player_entry" or "jy_main_menu"
|
|
local col = in_side and ENTRY_COL or MENU_COL
|
|
local s = tex.skin_text(key)
|
|
local i = raw_text(s, 42, WHITE, col, 14)
|
|
if i then taiko_text(s, 42, 28, col, 42, DARK, 32 + i.width / 2, 44) end
|
|
end
|
|
|
|
do
|
|
local T14_HC = require("global.t14_herecome")
|
|
local draw_player_entry = Entry.draw_player_entry
|
|
function Entry:draw_player_entry(...)
|
|
if draw_player_entry then draw_player_entry(self, ...) end
|
|
T14_HC.entry()
|
|
end
|
|
end
|
|
|
|
do
|
|
local entry_new = Entry.new
|
|
function Entry.new(...)
|
|
T8_PROGRESS = nil
|
|
return entry_new(...)
|
|
end
|
|
local IND_FRAMES, IND_FPS = 49, 60
|
|
local IND = {}
|
|
local function ind(i)
|
|
local t = IND[i]
|
|
if t == nil then
|
|
t = tex.get_texture(string.format("entry/t8_indicator/ind1p_%02d", i)) or false
|
|
IND[i] = t
|
|
end
|
|
return t or nil
|
|
end
|
|
function Entry:draw_footer(p1_joined, p2_joined)
|
|
tex.draw_texture(self.ss_footer)
|
|
local i = math.floor((tex.get_current_ms() or 0) * IND_FPS / 1000) % IND_FRAMES
|
|
local t = ind(i)
|
|
if t then tex.draw_texture(t, { x = 0, y = 600 }) end
|
|
if not p2_joined then
|
|
local p2 = raw_text(tex.skin_text("jy_taiko_start_p2"), 32, WHITE, BLACK, 9)
|
|
draw_c(p2, (484.16 + 960) / 2, (606.656 + 720) / 2)
|
|
end
|
|
end
|
|
end
|