Files
YataiDON14/Scripts/entry/entry.lua
T
2026-10-05 10:05:24 +08:00

189 lines
8.2 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