-- 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