Files
YataiDONNijiiro/Scripts/global/indicator.lua
T
TaikoZhongandClaude Fable 5.1 44e0a5e3b2 Entry: control-guide mode per phase, mode board title centred on its band
- The top-left control guide follows the cabinet's ChangeMode: `decide` alone on
  the credit screen, the `all` loop (rim to choose + face to decide) on mode
  select when the list has more than one board, hidden during the drum select.
  entry.lua / entry/box.lua publish the phase, global/indicator.lua reads it.
- The open mode board's title sits in the middle of the dark band at the top of
  the plate; the text object's box is taller than its ink, so the nominal y is
  set for the ink (-118 -> -97).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 00:40:52 +08:00

104 lines
5.5 KiB
Lua

-- YataiDON-HSS override of PyTaikoGreen/global/indicator.lua
-- Arcade common/control_guide: white top-left panel with a drum; 'main/taiko_small/all' is a 650-frame
-- loop at the lumen's 60 fps (10.83 s): frames 0..209 right stick + up arrow (hits @60,145),
-- 210..419 left stick + down arrow (hits @270,355), 420..649 both sticks + 「決定」 pill (face flash
-- 521..569). Round 4: re-baked every 2nd frame (325 cells = 30 fps, 352x276 cells, y offset 12 in
-- texture.json, origin = screen (0,0) so skin_config *_indicator positions should be {0,0}) into
-- global/indicator/background; the previous bake was every 5th frame (12 fps) which read as sluggish.
-- Wall-clock loop length is the arcade's (elapsed ms * 60 / FRAME_STEP). The other parent textures
-- (text, drum_face/kat/don, blue_arrow) are not drawn. All engine call sites use State.SELECT;
-- the other states fall back to the same loop.
Indicator = {}
Indicator.__index = Indicator
Indicator.State = {
SKIP = 0,
SIDE = 1,
SELECT = 2,
WAIT = 3,
}
local FRAME_STEP = 2 -- arcade frames per baked frame (bake_guide.py STEP)
local ARCADE_FPS = 60
function Indicator.new(state)
local self = setmetatable({}, Indicator)
self.state = state
self.background = tex.load_texture("global/indicator/background")
self.frame_count = tex.get_texture_info("indicator", "background").frame_count
self.t0 = tex.get_current_ms()
return self
end
function Indicator:update(current_ms) end
-- The baked loop is two guides back to back: cells 0..SPLIT-1 (arcade frames 0..419) = rim hit
-- + arrow (song select: "pick with the rim"), cells SPLIT..DECIDE_END-1 (arcade frames 420..649,
-- 230 frames = 3.83 s, the same length as the arcade's taiko_small 'decide' loop) = both sticks +
-- 決定 pill (entry: "decide with the face"). The engine passes the same State everywhere,
-- so which guide a screen wants is carried by its skin_config position: the
-- song-select keys are set to y=1 (see skin_config), entry/others to y=0.
local SPLIT, DECIDE_END = math.floor(420 / FRAME_STEP), math.floor(650 / FRAME_STEP) -- cells 210..324 = both sticks + 決定
__hss_costume_panel = __hss_costume_panel or {}
__hss_entry_guide = __hss_entry_guide or nil -- { ms, phase = "side" | "mode", count } from the entry scripts
-- ROUND 11 drew the 段位道場 shutter doors from HERE, purely for layering: the
-- indicator was the last skin-owned draw on SONG_SELECT and therefore the only slot
-- that landed over the whole HUD (LUA_CAPABILITIES C-dan-3). ROUND 14 added the real
-- slot -- `SongSelect:draw_top(dan_progress)`, called from SongSelectScreen::draw()
-- immediately before dan_transition->draw() -- so the doors now live in
-- song_select.lua where they belong and this file is back to being the indicator.
--
-- The fallback is kept for one reason only: on an engine WITHOUT draw_top, nothing
-- would ever call the rig. `dan_doors.draw()` returns false unless a transition is
-- actually running, and song_select.lua marks the frame it already drew, so on the
-- current engine this costs one table lookup and draws nothing twice.
local _dd_ok, dan_doors = pcall(require, "song_select/dan_doors")
function Indicator:draw(x, y, fade)
fade = fade or 1.0
if _dd_ok and not dan_doors.drawn_this_frame() and dan_doors.draw() then return end
-- arcade costume select (entry/costume.nulm) hides the top-left control guide: its own
-- title box (100..898 x 142..268) sits where the guide panel is; costume_menu.lua keeps
-- __hss_costume_panel[side] fresh while a costume menu is open (skin_config gives both
-- indicator_entry_* the same (0,0), so the side cannot be told apart here -> hide for any side)
local now = tex.get_current_ms()
for _, t in pairs(__hss_costume_panel) do
if now - t < 100 then return end
end
-- entry phases (published by entry.lua / entry/box.lua while they draw): TaikoSelect hides
-- the guide, ModeSelect with several boards shows the `all` loop instead of `decide`
local g = __hss_entry_guide
local show_all = false
if g and now - g.ms < 100 then
if g.phase == "side" then return end
show_all = (g.phase == "mode") and (g.count or 1) > 1
end
local elapsed = tex.get_current_ms() - self.t0
local frame
if (y or 0) >= 1 or show_all then
frame = math.floor(elapsed / 1000 * ARCADE_FPS / FRAME_STEP) % SPLIT
if (y or 0) >= 1 then y = y - 1 end
else
local n = DECIDE_END - SPLIT
frame = SPLIT + math.floor(elapsed / 1000 * ARCADE_FPS / FRAME_STEP) % n
end
tex.draw_texture(self.background, { frame = frame, x = x, y = y, fade = fade })
end
-- ROUND 17 — the top-most slot on DAN_SELECT.
--
-- `DanSelectScreen::draw()` calls this as its very last statement, after the coin
-- overlay, the GLOBAL::DAN_SELECT plate and the allnet chip (Indicator::draw_top,
-- src/objects/global/indicator.{h,cpp}). It is DAN_SELECT's equivalent of
-- `SongSelect:draw_top`, and it exists for exactly one thing: the 段位道場 shutter's
-- SECOND half. The cabinet's doors OPEN on the dan-select screen
-- (`loading_dani_intro` f187..200) — up to round 16 our transition ended with a
-- hard cut on SONG_SELECT and the reveal was never played at all.
--
-- `dan_doors.draw_open()` returns false unless a transition actually handed over,
-- so on every other visit to DAN_SELECT this is one table lookup and no draw.
function Indicator:draw_top()
if _dd_ok then dan_doors.draw_open() end
end