Song select: the decided genre board stays up while its songs load #22

Merged
Yonokid merged 4 commits from GanYiZhong/YataiDONNijiiro:folder-open-leg into main 2026-09-10 19:32:36 +02:00
2 changed files with 62 additions and 7 deletions
Showing only changes of commit 1c6243baf2 - Show all commits

No files matched your search

+61 -6
View File
@@ -361,6 +361,7 @@ function SongSelect:draw_top(dan_progress)
end
function SongSelect:draw_overlays(state)
self:draw_decided_bridge() -- decided genre board while its songs load (defined below)
if _dd_ok then dan_doors.arm(state == STATE_DAN_SELECTED) end
-- number_of_songs plate: arcade song_of_number_instance at stage (1754,270), 280x72 centred.
-- The engine draws its own song_num_bg (made transparent in this skin) and the "N曲目" text
@@ -678,6 +679,7 @@ end
-- Scrolling genre backdrop (enso_normal/song_select/song_select_bg, 2880x1080 per genre)
--------------------------------------------------------------------------------
function SongSelect:draw_background(nav)
self._frame_no = (self._frame_no or 0) + 1
self:refresh_folder_context(nav)
local info = tex.get_texture_info("box", "background")
local width = info.width
@@ -979,6 +981,7 @@ local R61 = {
-- clip landmarks (overwritten from the generated table)
open_f0 = 45, open_swap = 114, open_end = 145,
close_f0 = 150, close_swap = 219, close_end = 250,
open_furl = 100, -- first frame the decided genre board furls shut (genre_board_sx < 1)
-- event bookkeeping
seq = nil, -- last Navigator.wheel_event_seq we saw
have_events = false, -- engine actually exposes the r85 channel
@@ -993,6 +996,12 @@ do
"close_f0", "close_swap", "close_end" }) do
if t[k] then R61[k] = t[k] end
end
local rows = t.tracks and t.tracks.genre_board_sx
if rows then
for i = 1, #rows do
if rows[i][2] < 0.999 then R61.open_furl = rows[i][1]; break end
end
end
end
end
-- Linear sampler over the generated {frame, v1, v2...} rows. Fail-soft: an absent table
@@ -1044,8 +1053,14 @@ local function leg_f()
if R61.disabled or not R61.clip or not R61.t0 then return nil end
local f = R61.f0 + (tex.get_current_ms() - R61.t0) * 0.06
if not R61.swapped then
-- hold one frame short of the swap until the engine says it happened
local hold = (R61.kind == "close") and (R61.close_swap - 1) or (R61.open_swap - 1)
-- hold until the engine says the swap happened. The close leg holds one frame
-- short of its swap; the OPEN leg holds one frame short of the FURL (f99): the
-- cabinet loads a folder inside its 69-frame decide, this engine can take a
-- couple of seconds, and parking on f113 (board already furled away, boxes
-- flown out) left the screen empty for all of that time. Parked on f99 the
-- decided board stays up as the loading state and the furl -> unfurl pair
-- plays back to back once the swap lands (see leg_event).
local hold = (R61.kind == "close") and (R61.close_swap - 1) or (R61.open_furl - 1)
if f > hold then f = hold end
return f
end
@@ -1061,8 +1076,16 @@ local function leg_event(id)
local now = tex.get_current_ms()
if id == 3 then -- OPEN_BEGIN
R61.t0, R61.f0, R61.kind, R61.swapped = now, R61.open_f0, "open", false
R61.dec_id, R61.dec_box = R61.last_open_id, R61.last_open_box -- the decided board
elseif id == 4 then -- OPEN_SWAP
R61.t0, R61.f0, R61.kind, R61.swapped = now, R61.open_swap, "open", true
-- the clock was parked on open_furl - 1 while the loader ran: resume from the
-- furl so furl (f100..113) and unfurl (f114..) play back to back. A swap that
-- lands before the park point (tiny folder) just lets the clock keep running.
local f = (R61.kind == "open" and R61.t0) and (R61.f0 + (now - R61.t0) * 0.06) or nil
if not f or f >= R61.open_furl - 1 then
R61.t0, R61.f0 = now, R61.open_furl
end
R61.kind, R61.swapped = "open", true
R61.snap_once, R61.snap_ms = true, now -- OpenFolderState ends GotoAndPlay("on")
elseif id == 5 then -- CLOSE_BEGIN
R61.t0, R61.f0, R61.kind, R61.swapped = now, R61.close_f0, "close", false
@@ -1091,7 +1114,7 @@ local _fly_dbg = read_env("YATAIDON_R56_DEBUG") ~= nil -- log sampled offsets (
local function fly_offset(box)
if R56_DISABLED then return 0.0, 0.0 end
local f = leg_f()
if not f or not R61.swapped or R61.kind ~= "open" then return 0.0, 0.0 end
if not f or R61.kind ~= "open" then return 0.0, 0.0 end
if f >= FLY_END_F then return 0.0, 0.0 end
local st = box:draw_state()
if st == "open" or st == "diff_select" then return 0.0, 0.0 end -- the decided board stays
@@ -1109,6 +1132,25 @@ local function fly_offset(box)
return x - rx, y - ry
end
-- The decided genre board while the loader owns it (see draw_folder_open): drawn here,
-- after the wheel, whenever draw_box did not get to it this frame, until it has furled.
function SongSelect:draw_decided_bridge()
if not R61.dec_box then return end
local lf = (R61.kind == "open") and leg_f() or nil
if lf and lf < R61.open_swap - 1 then
if self._dec_frame ~= self._frame_no then
pcall(self.draw_folder_open, self, R61.dec_box)
end
else
R61.dec_id, R61.dec_box = nil, nil
end
end
-- true while `box` is the genre board the player just decided on (open leg running)
local function is_decided(box)
return R61.kind == "open" and R61.t0 ~= nil and R61.dec_id ~= nil and box_id(box) == R61.dec_id
end
-- ROUND 51: how a FRESH open animation starts is not one-size-fits-all. From the real
-- the reference build song_select_song_main.lua state machine (scratchpad dec/, verified this round):
-- * cursor move Scroll -> Main -> ProcKanbanWaitCountToSelectOn (61-tick hold,
@@ -1375,6 +1417,9 @@ function SongSelect:draw_song_board(box, pb, ia, ic)
tostring(box:draw_state()), tostring(box.text_name)))
end)
end
if gof and R61.kind == "open" and gof < R61.open_swap - 1 and box:draw_state() == "open" then
return -- the new content's board does not exist until the swap frame
end
if gof and box:draw_state() == "open" then
local sx, ba = go_get("song_board_sx", gof, 1), go_get("song_board_sx", gof, 2)
if sx and ba then
@@ -2094,7 +2139,7 @@ function SongSelect:draw_folder_board(box, pb, ch_alpha, ch_off, ta, glow_a)
-- pointing at.
local ltitle = 1.0
if not R61.disabled then
local lf = (box:draw_state() == "open") and leg_f() or nil
local lf = (box:draw_state() == "open" or is_decided(box)) and leg_f() or nil
if lf then
local sx, ba = go_get("genre_board_sx", lf, 1), go_get("genre_board_sx", lf, 2)
if sx and ba then
@@ -2223,6 +2268,15 @@ function SongSelect:draw_folder_closed(box)
end
function SongSelect:draw_folder_open(box)
-- remember the decided board: the engine removes the folder box from the wheel
-- while its songs load, and draw_overlays keeps drawing it from here until it
-- has furled away (the C++ box outlives the wheel slot, so the handle stays valid)
R61.last_open_id, R61.last_open_box = box_id(box), box
if is_decided(box) then
self._dec_frame = self._frame_no
self:draw_folder_board(box, 1.0, 1.0, 440.0, 1.0, 1.0)
return
end
local key = "f\0" .. box_id(box) -- r63: per-BOX, not per-title (see box_id)
local t = wheel_open_t(key)
if t == nil then -- cabinet 508 ms pre-growth hold: fully closed
@@ -2286,6 +2340,7 @@ function SongSelect:draw_back_board(box, p)
local lta = 1.0
if not R61.disabled then
local lf = (box:draw_state() == "open") and leg_f() or nil
if lf and R61.kind == "open" and lf < R61.open_swap - 1 then return end -- not yet
if lf then
local sx, ba = go_get("song_board_sx", lf, 1), go_get("song_board_sx", lf, 2)
if sx and ba then
@@ -2644,7 +2699,7 @@ function SongSelect:draw_box(box)
elseif state == "open" then self:draw_song_open(box)
else self:draw_song_closed(box) end
elseif kind == "folder" then
if state == "open" then self:draw_folder_open(box)
if state == "open" or is_decided(box) then self:draw_folder_open(box)
else self:draw_folder_closed(box) end
elseif kind == "back" then
if state == "open" then self:draw_back_open(box)
+1 -1
View File
@@ -3280,7 +3280,7 @@ bae62b0f451139b880d57d4b214156a8deaadedb2aacc1f7421d4e21189a810d *./Scripts/resu
fe5bc0a6cff271012d0de9ec7fc5cc7a94b3f1268ea1aa4a18e72c38b1a0e6c3 *./Scripts/result/result_fade_in.lua
9447dea62976348429b38b22104c68708b21cfbbf61f5d37a5a8d082d69f7a1c *./Scripts/result/result_player.lua
1033652c20bd62a07f645c94961227dfe73fb49df9bc581c460739c96c109c08 *./Scripts/song_select/dan_doors.lua
d3af610009783a9cf6e044dfcee396ea7f0ee90cd059fc44feb98e6935a5afff *./Scripts/song_select/song_select.lua
4675b3ec75e92633aee3008b23c59538595c28a9c1f6cefb5dc219d75a1104df *./Scripts/song_select/song_select.lua
89047ab5b642696922ca2c6e098ca288580a9c0bb3e197a08f17b821a31fc519 *./.skin-repo
40c378cdcaea2e2c9ec3da4c7fa72911d13a849a5b51e9645300f9571a7e12c8 *./Sounds/dan_result/achieve_tamashii.ogg
606f2d3558badc06e54b2c59a36f0580f4954774918d69a712ad6de45518cba0 *./Sounds/dan_result/advance_intro.ogg