Files
YataiDONNijiiro/Scripts/global/allnet_indicator.lua
T
2026-09-19 13:45:48 -04:00

145 lines
8.8 KiB
Lua

-- YataiDON-HSS override of PyTaikoGreen/global/allnet_indicator.lua
-- ROUND 6 (LUA_CAPABILITIES item 43) — boot-loading chrome.
--
-- `AllNetIcon:draw` is the last Lua call on LOADING (loading.cpp: black fill, progress-bar
-- track + fill, KIDOU::WARNING, white fade, allnet_indicator.draw), so it is the skin's only
-- paint hook on the boot screen.
--
-- Arcade reference: lumen attract/notice, `notice_instance_0` at (959.7,542.4) —
-- d0 8x8 black stretched 240x135 -> 1920x1080 backdrop (engine: DrawRectangle BLACK)
-- d1 NOTICE board 846x886 @ (0,-46) -> top-left (536.7, 53.4) (kidou/warning)
-- d2 8x8 #650000 stretched 115.47x5 -> a 923.7x40 track @ (497.9, 977.1)
-- d3 8x8 #ff0000 stretched 0.50x5 -> the fill, left-anchored at x 494.7, growing to 923.7
-- d4/d5 two 62x49.5 black caps at the ends of the track (invisible on black)
-- d6 8x8 white stretched 240x135, alpha 0 -> the fade-out (engine: Fade(WHITE, …))
-- The engine already copies the arcade's exact colours (101,0,0 / RED) and the white fade;
-- what it cannot match from a skin is the GEOMETRY: `progress_bar_*` in LoadingScreen::
-- on_screen_start is derived from the screen metrics (0.43*W x 50*scale at y = 0.85*H =
-- 825.6x75 @ (547.2, 918)) and `progress` has no Lua binding, so the bar cannot be redrawn
-- here. Its top edge (918) lands 11 px inside the last NOTICE line (ink bottom 929 with the
-- arcade board position restored in kidou/texture.json), so the board is simply re-drawn on
-- top from here — in the arcade the two never overlap (board ends 939.4, track starts 977.1),
-- so the stacking is unobservable there and this restores the readable result.
--
-- The ALL.Net icon itself is skipped on LOADING: the arcade boot notice screen carries no
-- overlay at all, and the engine draws this icon AFTER its white fade-out, so it would
-- otherwise hang in front of the full-white flash into the title screen.
AllNetIcon = {}
AllNetIcon.__index = AllNetIcon
function AllNetIcon.new(online)
local self = setmetatable({}, AllNetIcon)
self.online = online
self.indicator = tex.get_texture("global/overlay/allnet_indicator")
return self
end
function AllNetIcon:update(current_ms, online)
self.online = online
end
-- ROUND 9 - 「M曲」 on the gameplay plate (LUA_CAPABILITIES items 5 / 17 / 18).
-- `song_info.nulm` ET 9 `text_song_max` is a 110x40 box centred (1814,122),
-- font 24 / outline 3.0 / centre-aligned, cross-fading with the genre plate on
-- the same timeline as 「N曲目」 (root MC 15 `song_number` cmul 12). The engine
-- draws the 「N曲目」 half itself (SongNum at song_num_game) but had no value
-- for the total; `tex.song_limit()` is the new binding that supplies it.
-- allnet_indicator is the last Lua paint hook on GAME (game.cpp draw_overlay),
-- which is why this lives here and not in background.lua (draw_fore runs before
-- song_info.draw). The engine now also raises global_data.in_transition for
-- these frames while the song-loading transition is still on screen, so the
-- plate text does not float over the rainbow.
local SONG_MAX_CX, SONG_MAX_CY = 1814, 122
-- ROUND 16 (r16-outline): the record's border 3.0 is already in 1080p stage px,
-- and OutlinedText multiplies the thickness it is given by screen_scale (1.5),
-- so the value to pass is border / screen_scale. This used to pass 3 and draw a
-- 4.5 px ring. (`tex.get_screen_scale` is read lazily, at first draw.)
local SONG_MAX_FONT, SONG_MAX_BORDER = 24, 3.0
function AllNetIcon:draw_song_max()
if not tex.song_limit then return end
local limit = tex.song_limit()
if not limit or limit <= 0 then return end
if self._song_max_n ~= limit then
self._song_max = text.create_raw_text((tex.skin_text("song_num_max"):gsub("{0}", tostring(limit))),
SONG_MAX_FONT, { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, SONG_MAX_BORDER / tex.get_screen_scale(), 2.0)
self._song_max_n = limit
end
local t = self._song_max
if not t then return end
-- animation id 3 is the genre <-> song-number cross-fade SongInfo drives;
-- reading the same live object keeps both halves of the plate in step.
if not self._plate_fade then self._plate_fade = tex.get_animation(3, false) end
local fade = self._plate_fade and self._plate_fade.attribute or 1.0
if fade <= 0 then return end
-- ROUND 11 (text sharpness): snap to whole pixels. OutlinedText is a rasterised
-- texture drawn 1:1 with BILINEAR filtering, so an odd-width label centred on an
-- integer lands on a .5 and every texel gets blended 50/50 with its neighbour
-- (+34..69 % edge width, measured — see Graphics/song_select/MAPPING.md ROUND 11).
t:draw({ x = math.floor(SONG_MAX_CX - (t.width - 2.0) / 2 + 0.5),
y = math.floor(SONG_MAX_CY - t.height / 2 + 0.5), fade = fade })
end
function AllNetIcon:draw(x, y)
local screen = tex.current_screen and tex.current_screen() or ""
-- ROUND 71 (r71-dan-skip-popup): GAME_DAN joins GAME here.
--
-- The 段位道場 skip fired with no on-screen cue at all, while the ordinary
-- enso showed the whole card/numeral/dim/banner. Nothing was missing from
-- the pipeline -- DanGameScreen::update_skip_dan() already calls the
-- inherited push_skip_state() (game_dan.cpp:1299), which feeds
-- Background:handle_skip -> self.enso_skip, and DanGameScreen builds a real
-- Background ("DAN", game_dan.cpp:108) whose constructor publishes
-- _G.g_active_enso_skip. The ONLY thing dan mode never did was DRAW it:
-- this hook was gated on `screen == "GAME"`, so GAME_DAN fell through to
-- the bare-indicator tail below and the popup was updated every frame and
-- painted never.
--
-- The cabinet does show it, and shows the SAME asset -- this is not an
-- inference from "the trigger is shared". `datatable/enso_post.bin` (the reference build,
-- tlb decode_datatable.py) is the per-mode placement table; its dojo set is
-- `target 2` (the set carrying donbg_dojo_1p, dani_enso*, and ROUND 69's
-- dani_enso_between), and that set contains
-- part 30 lumen/000_default/enso_normal/enso/information/skip.nulstb
-- x = 0, y = 0, playerNo = 0
-- byte-for-byte the same row as the normal-enso set (`target 0`), pointing
-- at the same enso_normal clip -- there is no enso_dani/.../skip.nulm on
-- the cabinet at all, only this one. In target 2 it is the LAST row in the
-- list, i.e. topmost, and in particular it is placed AFTER
-- `dani_enso_between` (part 38), so the popup draws OVER the between-song
-- fusuma exactly as it does here.
if screen == "GAME" or screen == "GAME_DAN" then
-- The song-number plate belongs to GAME's own song_info cross-fade;
-- GAME_DAN's header is ROUND 70's and is deliberately left alone.
if screen == "GAME" and not (tex.in_transition and tex.in_transition()) then
self:draw_song_max()
end
local frame = self.online and 2 or 0
tex.draw_texture(self.indicator, { frame = frame, x = x, y = y })
-- ROUND 19 (r19-skip2): 演奏スキップ's card/dim/banner, published on the
-- shared globals table by background.lua (self.enso_skip). Drawn from
-- here, the last Lua paint hook on GAME (and, via GameScreen::draw_overlay,
-- on GAME_DAN too -- game_dan.cpp:1178 calls the inherited overlay), so it
-- lands after song_info and the gauge and under the outgoing
-- result_transition -- see the citation at Background.new in
-- Scripts/background/background.lua for why this hook and not draw_fore.
if _G.g_active_enso_skip then _G.g_active_enso_skip:draw() end
return
end
if screen == "LOADING" then
-- ROUND 15 (r15-audit-global): this used to re-draw `loading/kidou/warning` here, to lift
-- the NOTICE board back over the engine's progress bar, whose top edge (918) cut 11 px
-- into the last line of text. The bar now sits where the cabinet puts it
-- (`loading_progress_bar` = 924x40 @ (498,977), from `attract/notice` depth 2), so the two
-- no longer overlap -- board ends 939, track starts 977, exactly as on the cabinet.
-- Removing the re-draw also fixes a defect it introduced: `LoadingScreen::draw` runs this
-- hook AFTER its white fade-out, so the re-drawn board stayed at full opacity while the
-- rest of the screen whitened into TITLE.
-- The ALL.Net icon is still deliberately not drawn: the arcade boot notice screen carries
-- no overlay at all.
return
end
local frame = self.online and 2 or 0
tex.draw_texture(self.indicator, { frame = frame, x = x, y = y })
end