-- YataiDON-HSS override of PyTaikoGreen/entry/entry.lua: cancel text centring uses cancel_info.x2[1]/y2[1]; -- sets __hss_entry_reset for the arcade mode-select list in box.lua Entry = {} Entry.__index = Entry function Entry.new() local self = setmetatable({}, Entry) -- EntryScreen::on_screen_start creates BoxManager (4 EntryBox) then this script; -- flag the box list so the NEXT batch of EntryBox.new starts fresh (see box.lua). __hss_entry_reset = true tex.load_animations("entry") self.bg_flicker = tex.get_animation(1, "entry") self.side_select_fade = tex.get_animation(0, "entry") self.bg_flicker:start() -- ROUND 11 -- the arcade "credit wait" screen (lumen entry/entry_credit) has no -- 「どちらでつかいますか?」 box: two pills carrying 「1人プレイ」/「2人プレイ」 on the pale -- left half and 「太鼓をたたいてスタート!」 on the yellow right half. Strings are the -- cabinet's own wordlist rows credit_play_1p / credit_play_2p / credit_start. -- Outline thickness is scaled by screen_scale (1.5) in OutlinedText's ctor, so the -- arcade's DefineEditText border 7 is passed as 5 (= 7.5 px). -- ROUND 11b: 「つかわない」 is drawn as a small CAPTION, only while side 1 is armed. -- The arcade credit screen has no cancel widget at all (entry_main.lua leaves the screen -- on the 60 s timer, never on a button), but the engine's side 1 is real and reachable. self.text_cancel = text.create_text("entry_cancel", { 255, 255, 255, 255 }, { 40, 24, 12, 255 }, false, 3, 0) self.text_credit_p = { -- ROUND 15 -- outline thickness 0, NOT the record's border 7. ET7 is `#000000` with -- border 7, and the cabinet's outline colour is the renderer default (black), so the -- border on this field is a pure 7.5-screen-px BLACK-ON-BLACK dilation: it carries no -- colour information at all, it only fattens the glyphs. On 「1人プレイ」 that is -- invisible (kana strokes are far apart), but at font 56 it closes every counter of a -- Latin string and「1-Player」/「2-Player」 render as an unreadable black smear -- (`scratchpad/r15ae/z_1player_en.png`). Deliberate deviation, documented here: the -- fill colour is unchanged, so the label still reads exactly as the cabinet's black -- text, and it is legible in every language this skin ships. -- black ink with the cabinet's WHITE outline (same 7 stage-px border as the message) text.create_text("entry_credit_1p", { 0, 0, 0, 255 }, { 255, 255, 255, 255 }, false, 7.0 / tex.get_screen_scale(), 0), text.create_text("entry_credit_2p", { 0, 0, 0, 255 }, { 255, 255, 255, 255 }, false, 7.0 / tex.get_screen_scale(), 0), } -- the message is ONE string drawn in two colourways: the arcade stacks a black-tinted -- outline copy (ET3 via cmul (0,0,0)) under a white fill copy (ET5), and its blink -- recolours that outline to (256,236,67). Cross-fading these two reproduces it. -- ROUND 16 (r16-outline): `entry/entry_credit` ET3 `text_credit` carries border 7.0, -- which is already in 1080p stage px; OutlinedText multiplies by screen_scale (1.5), -- so it is divided out rather than rounded to 5 (which drew 7.5 px). local CREDIT_BORDER = 7.0 / tex.get_screen_scale() self.text_credit_msg = text.create_text("entry_credit_start", { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, CREDIT_BORDER, 0) self.text_credit_msg_hl = text.create_text("entry_credit_start", { 255, 255, 255, 255 }, { 255, 236, 67, 255 }, false, CREDIT_BORDER, 0) self.bg_bg = tex.load_texture("entry/background/bg") self.bg_tower = tex.load_texture("entry/background/tower") self.bg_shops_center = tex.load_texture("entry/background/shops_center") self.bg_people = tex.load_texture("entry/background/people") self.bg_shops_left = tex.load_texture("entry/background/shops_left") self.bg_shops_right = tex.load_texture("entry/background/shops_right") self.bg_lights = tex.load_texture("entry/background/lights") -- ROUND 6 — layered arcade backdrop (lumen entry/entry, entrybg_instance MC 19). -- Arcade display list: d0 shape1 (gold sky) / d1 MC11 twinkles / d2 shape12 (street, sky -- transparent) / d3-6 MC16 glow x4 (blend=add) / d7 shape17 (fully lit street, opaque). -- `bg` is byte-exact shape1+shape12, so only d3-d7 have to be re-added. self.bg_street_lit = tex.load_texture("entry/background/street_lit") self.bg_glow = tex.load_texture("entry/background/glow") self.bg_twinkle = tex.load_texture("entry/background/twinkle") self.bg_t0 = tex.get_current_ms() -- ROUND 11: the parent's nine-slice box / 1P / 2P / cancel / footer art is no longer -- drawn (the arcade credit screen has none of it). These four are the arcade's own -- shapes, baked by Graphics/entry/bake_credit.py; both pills are the SAME 1160x200 -- plate placed twice (texture.json carries the two placements). self.cr_pill = tex.load_texture("entry/side_select/credit_pill") self.cr_flash = tex.load_texture("entry/side_select/credit_flash") self.cr_t0 = tex.get_current_ms() self.cr_blink_t0 = self.cr_t0 self.cr_side = 1 self.cr_frame = 0 self.cr_seen_frame = nil self.cr_decide_t0 = nil self.cr_decide_row = nil -- ROUND 12 -- opt-in arcade CREDIT WAIT interaction model. skin_config_entry.json's -- `entry_credit_arcade` = 1 switches the engine (EntryScreen::handle_input) to the -- cabinet's rule: the two rows are PROMPTS, both lit, no cursor, no 「つかわない」; -- whichever SEAT hits its own don enters as that player. PyTaikoGreen leaves the key -- out and keeps the kat-moved side cursor. local arcade_cfg = tex.get_skin_config("entry_credit_arcade") self.cr_arcade = (arcade_cfg ~= nil and (arcade_cfg.x or 0) >= 1) self.cr_pending_decide = nil self.global_player_entry = tex.load_texture("entry/global/player_entry") -- ROUND 18 (r18-misc) -- the top-left control guide belongs on the CREDIT WAIT -- screen and we were not drawing it there at all. -- -- The cabinet's own source settles it. `entry.nulm` root (sprite 54) carries -- `controlguide_instance` at depth 28, i.e. a sibling of `entrycredit_instance` -- (depth 23) and drawn OVER it. `script_lua/entry/entry_main.lua` CreditWait, -- lines 957-966: -- if this.start_guide_ == false then -- if PlayDataManager.GameCost1 <= PlayDataManager.GetNowCoin() -- or PlayDataManager.IsFreePlay() == true then -- this.control_guide_:SetVisible(true) -- this.control_guide_:Start(1) -- and `common/ControlGuide.lua` `Start(mode)` -> `ChangeMode(1)` -> -- `taiko_small:GotoAndStop("decide")`. So on a free-play cabinet the guide is up -- from the first frame of the credit screen, in its **decide** state -- exactly the -- second half of the loop `global/indicator/background` already bakes (arcade frames -- 420..649; see Scripts/global/indicator.lua). It is torn down again at -- ModeSelectFinishActionWait (l.1233) and at each TaikoSelect start (l.481, l.797). -- -- Engine-side, `Indicator` is owned by `EntryPlayer`, so it only ever draws once a -- seat has ENTERED; before that `players` is empty and nothing draws the panel. -- Drawing it from here is the whole fix -- same texture, same (0,0), same frames. -- -- NOT ported: `ControlGuide.Update` slides the panel to screen centre after 3 s with -- no input (`to_center`) and back on the next hit (`to_default`). The baked loop has -- no centre variant, so the guide stays parked top-left. self.guide = tex.load_texture("global/indicator/background") self.guide_t0 = self.cr_t0 self.any_joined = false return self end -- Same split as Scripts/global/indicator.lua: the bake is two guides back to back at -- one cell per 2 arcade frames, and cells GUIDE_SPLIT..GUIDE_END-1 are the 「決定」 half. local GUIDE_STEP = 2 local GUIDE_SPLIT = math.floor(420 / GUIDE_STEP) local GUIDE_END = math.floor(650 / GUIDE_STEP) -- NOTE: do NOT gate this on `tex.get_texture_info("indicator","background").frame_count`. -- The bake is a `crop` list in texture.json, not a frame-count sheet, and -- `get_texture_info` only reports a real count for `FramedTexture` -- for this one it -- returns 1, so a `frame_count >= 325` guard silently drew nothing. `indicator.lua` -- reads the same value into `self.frame_count` and never uses it, which is why the -- discrepancy had not been noticed. `draw_texture{frame=N}` indexes the crop list fine. function Entry:draw_control_guide() if not self.guide then return end -- One frame of overlap with EntryPlayer's own Indicator on the join frame is -- possible (draw_footer publishes the join flags after this runs); both draws are -- the same cell at the same place, so it is invisible. if self.any_joined then return end local n = GUIDE_END - GUIDE_SPLIT local f = GUIDE_SPLIT + math.floor((tex.get_current_ms() - self.guide_t0) * 0.06 / GUIDE_STEP) % n tex.draw_texture(self.guide, { frame = f, x = 0, y = 0 }) end function Entry:update(current_ms) self.bg_flicker:update(current_ms) self.side_select_fade:update(current_ms) -- ROUND 11: a frame counter is the only way Lua can see that the engine has LEFT -- EntryState::SELECT_SIDE (draw_side_select_buttons simply stops being called), which -- is what triggers the arcade's `choose` flash + fade_out. update() runs once per -- frame, before draw(). self.cr_frame = (self.cr_frame or 0) + 1 end function Entry:start_side_select() self.side_select_fade:start() self:restart_credit() end function Entry:restart_side_select() self.side_select_fade:restart() self:restart_credit() end -- credit_instance `fade_in` (sprite 11 f5..f15) restarts, and so does the row's attract -- loop; any pending decide overlay is dropped (the 2P join re-enters SELECT_SIDE). function Entry:restart_credit() local now = tex.get_current_ms() self.cr_t0 = now self.cr_blink_t0 = now self.cr_side = 1 self.cr_decide_t0 = nil self.cr_decide_row = nil self.cr_seen_frame = nil self.cr_pending_decide = nil end function Entry:get_side_select_fade() return self.side_select_fade.attribute end -- ROUND 8 -- the whole `entrybg_instance` rig (lumen `entry/entry.nulm` MC 19) is now -- SAMPLED out of `Scripts/anim/entry_bg.lua` instead of the closed forms round 6 fitted -- to it. See ANIM_PIPELINE.md. Tracks, in the cabinet's own display order: -- d1 twinkles `#11@1/#5@0/#3@0` (f0), `#11@1/#8@1/#6@0` (f90), -- `#11@1/#9@2/#3@0` (f120), `#11@1/#10@3/#6@0` (f219) -- d3-d6 glows `#16@3/#14@0` (all four are the same 120-frame curve, in phase) -- d7 lit street `#17@7` -- The table covers a whole 360-frame (6 s) cycle, so every channel is just read at -- `f % 360` -- no per-channel modulo bookkeeping. -- -- What the export changed: the two SMALL twinkles were drawn 25 % too small at the end of -- their burst. Round 6 modelled every burst as one envelope times a per-burst multiplier -- (0.5 for the small pair), which gives 0.25 -> 0.5 -> 0.75. The cabinet runs them -- 0.25 -> 0.5 -> 1.0: the multiplier applies to the GROW phase only, and the expand phase -- adds the same absolute +0.5 to big and small alike. Alpha, the big bursts, the glow -- triangle and the street blink were all confirmed exact. -- ROUND 8: fail soft. `pcall` the require and use `anim.safe`, which hands back a NULL -- clip when a generated table is missing or malformed, so every reader below falls -- through to its `or ` default instead of taking the screen down. local _ea_ok, entry_anim = pcall(require, "anim/sampler") if not _ea_ok then entry_anim = { safe = function() -- sampler.lua itself is missing: hand back the same NULL clip shape it would 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 EBG = entry_anim.safe("anim/entry_bg") -- ROUND 11 -- entry/entry_credit.nulm, exported by scratchpad/anim_export.py: -- CR = sprite 10 (one player row): labels init 0 / start 5 / choose 125. Tracks -- `text_message_instance` (the white fill copy), `text_message_instance_2` (the -- outline copy -- fields cr,cg,cb carry its black<->yellow recolour) and `#8@4` -- (the white decide flash, shape 8, only placed from f125). -- CF = sprite 11 (credit_instance): fade_in f5..f15, fade_out f16..f35. local CR = entry_anim.safe("anim/credit_row") local CF = entry_anim.safe("anim/credit_fade") -- Layout, straight out of the lumen (stage 1920x1080; the root places credit_instance at -- (960,432) and the row sprite is placed twice, at ty +72 and +248): local CREDIT_CX = 960 local ROW_CY = { 432 + 72, 432 + 248 } -- 504 / 680 -- DefineEditText records (payload map: [2] text sym, [4] colour, [5] rect, byte 32 align, -- f32@44 size, f32@60 outline -- Graphics/result/MAPPING.md ROUND 6): -- ET7 text_player rect (-2,-2,306,94) placed at (-448,-62.5), align 0 (LEFT), size 56, border 7 -- ET3 message rect (-2,-2,638,94) placed at (-137,0)+(2,-62.5), align 2 (CENTRE), size 56, border 7 -- The cabinet text rule is pen.y = box.top + (box.h - lineHeight)/2 + border, so the INK -- CENTRE is box.top + box.h/2 + border -- independent of which font raster is used: local LABEL_INK_X = CREDIT_CX - 443 -- box.left(-450) + border(7), left-aligned local MSG_INK_X = CREDIT_CX + 190 -- box.left(-137) + border(7) + box.w/2(320) local TEXT_INK_DY = 0.5 -- box.top(-64.5) + box.h/2(48) + border(7), +10: measured -- against the cabinet the ink sat ~10 px above the pill centre local PAD5 = 9 -- OutlinedText pad for thickness 5: (int)(5*1.5)+2 -- ROUND 15: the two player labels are now built with thickness 0 (see `text_credit_p` above), -- so their texture pad is (int)(0*1.5)+2 = 2, not 9. Using PAD5 here would shift the ink 7 px -- right of the cabinet's pen at box.left + border. local PAD_LABEL = 2 -- The cancel widget is NOT an arcade element (MAPPING.md ROUND 11): the same pill at 0.5, -- centred under the two rows. local CANCEL_CX, CANCEL_CY = 960, 838 local ROW_LOOP_F0, ROW_LOOP_LEN = 5, 120 -- the row timeline loops `start`..f124 -- NOT arcade: the cabinet lights both rows equally because it has no cursor (each row is -- armed for that side's own drum). The engine DOES have a cursor, so the row that is not -- armed is dimmed and the armed one carries a pulse of the arcade white `choose` overlay. local DIM_UNSELECTED = 0.72 local DECIDE_FLASH_F = 24 -- `choose` blink f125..f149 local EBG_LEN = math.max(1, EBG:last() - EBG:first() + 1) -- 360 frames = 6 s -- `entrybg_instance` is 30 frames and STOPS at f29 (see draw_background); after that the -- lit-street layer is gone for good. 19 is where its alpha first reaches 0. local BG_LIT_END = 19 -- {json index, texture frame (0 = shape3, 1 = shape6), track} local ENTRY_TWINKLES = { { 0, 0, "#11@1/#5@0/#3@0" }, { 1, 0, "#11@1/#9@2/#3@0" }, { 2, 1, "#11@1/#8@1/#6@0" }, { 3, 1, "#11@1/#10@3/#6@0" }, } function Entry:draw_background() local f = ((tex.get_current_ms() - self.bg_t0) * 0.06) % EBG_LEN -- arcade frames @ 60 fps tex.draw_texture(self.bg_bg) -- d1 twinkles (arcade draws them under the street; the street is baked into `bg`, so -- they sit on top here -- only visible where a burst overlaps stall art). A burst is -- only placed on the frames it is alive, so a track that has no row at `f` returns its -- clamped end value (alpha 0) and draws nothing. if self.bg_twinkle then for i = 1, #ENTRY_TWINKLES do local tw = ENTRY_TWINKLES[i] local s, a = EBG:at(tw[3], f) if a and a > 0.002 then tex.draw_texture(self.bg_twinkle, { index = tw[1], frame = tw[2], center = true, scale = s, fade = a }) end end end -- d3-d6 warm glows. The arcade blends these additively; each patch is pre-composited -- (bg + glow, clamped) so a plain alpha fade reproduces `bg + a*glow` exactly. if self.bg_glow then local ga = EBG:get("#16@3/#14@0", f, "a") or 1.0 for i = 0, 3 do tex.draw_texture(self.bg_glow, { index = i, frame = i, fade = ga }) end end -- d7 lit street: a ONE-SHOT "blur in", NOT a loop. `entrybg_instance` (MC 19) is only -- 30 frames long and carries DoAction index 0 at BOTH f4 and f29. f4 must be Stop() -- -- `entry_main.lua` StartBGIn is what starts the clip (`this.bg_:GotoAndPlay("start")`, -- label `start` = f5), so the clip is parked at f4 until then -- and f29 carries the -- SAME action index, therefore f29 is Stop() too. So the cabinet plays f5..f29 once and -- holds: shape17 (the SHARP, fully-lit street, lapvar 1508) fades 1 -> 0 over f5..f19, -- leaving shape12 (the DEPTH-OF-FIELD BLURRED street, lapvar 48) as the steady state. -- That matches every arcade reference capture ("festival street, blurred"). -- `Scripts/anim/entry_bg.lua` was exported with `--range 0,359`, which wrapped this -- 30-frame clip twelve times and turned the one-shot into a 2 Hz sharp/blurry strobe -- (the user's 「背景模糊亂跳」). Only THIS channel wraps: the twinkle MCs (5/8/9/10) -- really are 360 frames and the glow MC (16) really is 120, so `f` stays modulo for them. if self.bg_street_lit then local lf = (tex.get_current_ms() - self.bg_t0) * 0.06 -- monotonic, NOT wrapped if lf < BG_LIT_END then local la = EBG:get("#17@7", lf, "a") or 0.0 if la > 0.002 then tex.draw_texture(self.bg_street_lit, { fade = la }) end end end end -- ROUND 11 -- the arcade credit screen has no panel behind the buttons: the pills sit -- straight on the festival street. The parent nine-slice box and its -- japanese caption are therefore not drawn at all. function Entry:draw_side_select() end -- One player row. `row` is 1 (upper, 1P) or 2 (lower, 2P); `f` is the row timeline frame. function Entry:draw_credit_row(row, f, a) if a <= 0.002 then return end tex.draw_texture(self.cr_pill, { index = row - 1, fade = a }) local cy = ROW_CY[row] local lbl = self.text_credit_p[row] if lbl then lbl:draw({ x = LABEL_INK_X - PAD_LABEL, y = cy + TEXT_INK_DY - lbl.height / 2, fade = a }) end -- fill alpha and the outline copy colour multiply, both read from the export local ma = CR:get("text_message_instance", f, "a") or 1 local _, cr = CR:at("text_message_instance_2", f) local yellow = (cr and cr / 256.0) or 0.0 -- 0 = black outline, 1 = (256,236,67) local msg = self.text_credit_msg if msg and ma > 0.002 then local x = MSG_INK_X - msg.width / 2 local y = cy + TEXT_INK_DY - msg.height / 2 -- ROUND 26 (r26-entrytextfade): `msg`/`msg_hl` are each a whole baked -- OutlinedText -- white fill AND its outline in ONE texture (OutlinedText -- bakes them together; text.cpp's draw() only has a single `fade` alpha for -- the whole quad, there is no separate fill/outline alpha). The old code -- faded BOTH copies down independently ((1-yellow) and yellow), so around -- the blink midpoint BOTH copies were simultaneously translucent: the white -- fill of each stopped being opaque, the pill's yellow bled through it, and -- the outline ring (itself fading through a yellow close to the pill's own -- colour) lost all contrast -- exactly the reported "白字跟外框fade時機不同, -- 出現純白字" flash (captured live at scratchpad/r26etf/before/f20_9530ms.png, -- ~9.5s into the credit-wait loop, i.e. inside the `choose` blink f64..f95). -- Fix: draw the black-outline copy ALWAYS fully opaque as the base (fade = -- a*ma, no `(1-yellow)` term), then cross-dissolve the yellow-outline copy -- ON TOP of it at fade = a*ma*yellow. Back-to-front opaque compositing means -- the result is fully opaque at every point of the blend -- the fill stays -- solid white throughout (yellow copy's white fill lands on the already- -- opaque white fill beneath, a no-op), and the outline smoothly darkens from -- black to yellow while never dropping below full alpha, so it is never -- washed out by the pill background behind it. msg:draw({ x = x, y = y, fade = a * ma }) if yellow > 0.001 and self.text_credit_msg_hl then self.text_credit_msg_hl:draw({ x = x, y = y, fade = a * ma * yellow }) end end end -- The whole credit_instance: both rows + the cancel widget, at `a` (its fade_in/out alpha). -- `sel` is the highlighted row: 1 / 2 / 0 = the cancel widget / nil = nothing (the decide -- overlay, where the selection has already been consumed). `flash_row`/`flash_a` drive the -- `choose` overlay. function Entry:draw_credit(a, sel, blink_f, flash_row, flash_a, loop_rows) for row = 1, 2 do local armed = (row == sel) local ra = (sel == nil or sel == 0 or armed) and a or (a * DIM_UNSELECTED) -- Arcade: the cabinet runs the row attract loop (`start`..f124, the yellow-outline -- blink at f64..f95) on BOTH rows in CreditWait, because neither is "armed". The -- cursor model only animated the armed row and froze the other at f5. local rf = (armed or loop_rows) and blink_f or ROW_LOOP_F0 self:draw_credit_row(row, rf, ra) end local now = tex.get_current_ms() if sel and sel > 0 then -- the selected pill also carries a gentle version of the arcade white `choose` -- overlay, standing in for a cursor the cabinet does not need (there, a row is -- picked by hitting that side's own drum). local pulse = 0.08 + 0.10 * math.sin((now - self.cr_blink_t0) * 0.006) tex.draw_texture(self.cr_flash, { index = sel - 1, fade = a * pulse }) end -- The cabinet never shows a 「つかわない」 caption on this screen (the cancel side is -- just the un-armed state), so nothing is drawn for sel == 0. if flash_row and flash_a and flash_a > 0.002 then tex.draw_texture(self.cr_flash, { index = flash_row - 1, fade = a * flash_a }) end end -- The engine thinks in SIDES, not in a player COUNT: `side` is 0 = left/1P, 1 = cancel -- (back to title, or back to mode select when a 2nd player is joining), 2 = right/2P, -- moved with kat and confirmed with don. The arcade screen has no cursor at all -- each -- row is armed for that side's own drum -- so side 0/2 map onto the upper/lower row and -- side 1 onto the cancel widget. See Graphics/entry/MAPPING.md ROUND 11. function Entry:draw_side_select_buttons(side) local now = tex.get_current_ms() if side ~= self.cr_side then self.cr_side = side self.cr_blink_t0 = now -- a newly armed row restarts its attract cycle end self.cr_seen_frame = self.cr_frame self.cr_decide_t0 = nil -- credit_instance fade_in: sprite 11, f5..f15 (10 frames), clamped after local fi = math.min(15, 5 + (now - self.cr_t0) * 0.06) local a = CF:get("player1_text_instance", fi, "a") or 1.0 -- Arcade: no cursor at all -- `sel = nil` keeps BOTH rows at full alpha, draws no -- selection pulse and no 「つかわない」 caption (the cabinet has neither). local sel = (not self.cr_arcade) and ((side == 0 and 1) or (side == 2 and 2) or 0) or nil local blink_f = ROW_LOOP_F0 + ((now - self.cr_blink_t0) * 0.06) % ROW_LOOP_LEN self:draw_credit(a, sel, blink_f, nil, nil, self.cr_arcade) -- depth 28 > depth 23: the guide sits OVER the credit rows. self:draw_control_guide() -- entry_main.lua only makes `credit_side_[n]` visible in ModeSelectStartWait, i.e. AFTER -- the credit screen is finished; coin_overlay.lua reads this to keep the 2P invite cloud -- off the credit screen. EntryScreen::draw runs the screen scripts before the overlay. YD_ENTRY_CREDIT_MS = now end -- The parent's floor band starts at y=862 (575*1.5) and is drawn AFTER the mode-select / -- costume menu, so it would cover the arcade costume panel bottom (y<=957) and the -- えらぶ/決定 drum hint (833..921). Squeeze it to start at y=940 (nameplate / フリープレイ -- still sit on it). Values are screen px (1080p). -- The arcade entry screen has no floor band: the nameplate and フリープレイ sit -- straight on the street background. Nothing to draw. -- ROUND 6 (2P): the engine has no "two players are in" flag Lua can read (entry.cpp resets -- global_data.player_num to P1 when the 2nd player joins), but it does pass the two join flags -- here, and EntryScreen::draw calls draw_footer BEFORE coin_overlay.draw() - so publish them. function Entry:draw_footer(p1_joined, p2_joined) YD_ENTRY_BOTH_JOINED = (p1_joined == true and p2_joined == true) -- ROUND 18: once a seat is in, EntryPlayer's own Indicator draws the guide, so the -- credit screen must stop drawing its own copy (see draw_control_guide). self.any_joined = (p1_joined == true or p2_joined == true) end function Entry:draw_player_entry() tex.draw_texture(self.global_player_entry) self:draw_credit_decide() end -- ROUND 11 -- the arcade decide beat. `entry_main.lua` runs CreditWait:Decide(1) -> -- CreditDecideAction (the row plays `choose`, f125..f149: a white overlay blinking on an -- 8-frame triangle, peak 205/256) -> CreditWait:Finish() -> `fade_out` (f16..f35) -> only -- THEN ModeSelectStart. Our engine flips EntryState to SELECT_MODE on the same frame the -- don lands, so the beat has to be played out from here: draw_player_entry() is called in -- EVERY entry state (EntryScreen::draw), and the mode boxes stay invisible until each -- player's cloud animation has finished (~1.2 s), which is longer than the 750 ms this -- takes. The transition is detected by draw_side_select_buttons() no longer being called -- (Entry:update bumps cr_frame once per frame). -- ROUND 12 -- EntryScreen::join_player names the row the cabinet's CreditWait:Decide(playerId) -- would flash (`credit_wait.tlb` plays `choose` on `text_mc_[playerId]`, i.e. the row of the -- player who hit -- not always row 1). Called on the frame the seat enters, while the engine -- is still in SELECT_SIDE, so draw_credit_decide() below picks it up next frame. function Entry:decide_side_select(side) self.cr_pending_decide = (side == 2) and 2 or 1 end function Entry:draw_credit_decide() local now = tex.get_current_ms() if self.cr_seen_frame ~= nil and self.cr_decide_t0 == nil then if self.cr_frame > self.cr_seen_frame then self.cr_seen_frame = nil if self.cr_pending_decide then -- arcade model: the engine told us which row entered self.cr_decide_t0 = now self.cr_decide_row = self.cr_pending_decide self.cr_pending_decide = nil elseif self.cr_side == 0 or self.cr_side == 2 then -- cursor model: side 1 is 「つかわない」 -- cancelled, not decided. self.cr_decide_t0 = now self.cr_decide_row = (self.cr_side == 0) and 1 or 2 end end end if self.cr_decide_t0 == nil then return end local t = (now - self.cr_decide_t0) * 0.06 -- frames since decide local flash_a = CR:get("#8@4", 125 + math.min(t, DECIDE_FLASH_F), "a") or 0 local fade_f = 16 + math.max(0, t - (DECIDE_FLASH_F + 1)) -- fade_out starts after local a = CF:get("player1_text_instance", math.min(fade_f, 35), "a") or 0 if a <= 0.002 then self.cr_decide_t0 = nil return end self:draw_credit(a, nil, ROW_LOOP_F0, self.cr_decide_row, flash_a) YD_ENTRY_CREDIT_MS = now end