Compare commits

...
Author SHA1 Message Date
Yonokid a0eedc6ae5 Merge branch 'main' into folder-open-leg 2026-09-10 19:32:18 +02:00
Yonokid bebc6fe22e Merge pull request 'Light effects: entry glow patch size, add-blended layers drawn additively' (#21) from GanYiZhong/YataiDONNijiiro:light-effects into main
Reviewed-on: Yonokid/YataiDONNijiiro#21
2026-09-10 19:32:08 +02:00
TaikoZhongandClaude Fable 5.1 2a7a6e7f1f Song select: a furled board is drawn as crisp columns, not a squashed bitmap
Squashing the 960-wide board texture to a few px averaged the outline away and,
because the GPU picks the mip level from the larger axis, blurred every row too;
the cabinet scales a vector shape and stays sharp.  draw_board now builds a
furled board from columns: both rounded corners at 1:1 and the band / panel /
band between them scaled in proportion, each drawn from an 8 px flat slice of
itself and magnified.  Narrower than both corners it becomes a solid bar with
the outline columns on either side and the flat centre between them (squeezed
corners left two hollow strokes with nothing between).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 00:37:30 +08:00
TaikoZhongandClaude Fable 5.1 977bf23a2c Song select: the folder close leg plays the cabinet's return half
Closing a folder (もどる) had no wheel motion at all: the fly table only
covered the open leg (clip f27..150), fly_offset only ran for kind "open", and
the engine's 166 ms fade took the song boxes and the back board out right
after the press -- the cabinet keeps them solid until they fly out (f184..204)
and the board furls (f205..217).

- anim/wheel_decide now spans f27..255 (open leg + `return` leg, straight from
  the cabinet clip); fly_offset plays the return half on the close leg: song
  boxes fly out, wait off screen across the swap (f219) and the genre boxes
  fly back in f234..254.  f255 re-bases the clip, so the leg stops before it.
- The engine's box fade is ignored during the pre-swap half of the close leg
  (box_fade); the clip channels already drive the back board's title fade and
  furl.

Verified with captures: press -> boxes stay -> contents fade / boxes fly out ->
back board furls -> genre board unfurls -> contents return -> boxes fly in.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 18:35:47 +08:00
TaikoZhongandClaude Fable 5.1 1c6243baf2 Song select: the decided genre board stays up while its songs load
Opening a folder on this engine differs from the cabinet in one way that
matters for the animation: the cabinet swaps the content 69 frames into the
decide leg, this engine swaps when its loader is done, which can be a couple
of seconds for a big folder.  The leg clock parked one frame short of the swap
(f113), i.e. with the decided board already furled away and the neighbours
flown out, so the screen sat empty for the whole load -- and before that the
engine re-grows the decided box's yellow frame, which made the board close
and reopen right after the press.

- The open leg now parks one frame short of the furl (f99): the decided board
  stays up, contents faded per the clip, as the loading state.  On the swap the
  clock resumes from the furl, so furl (f100..113) and the new board's unfurl
  (f114..) play back to back; a swap that lands before the park point just lets
  the clock run.
- The neighbours' fly-out (f86..99) plays before the swap as on the cabinet;
  it used to wait for the swap and then jump straight to the off-screen hold.
- The decided board is remembered at OPEN_BEGIN and drawn fully open for the
  whole leg, past the engine's closed re-grow and past the moment the engine
  takes the box off the wheel for the loader (draw_overlays bridges it from the
  still-live box handle until it has furled).
- The new content's song / back board is not drawn before the swap frame.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 07:26:09 +08:00
3 changed files with 377 additions and 253 deletions

No files matched your search

+235 -229
View File
@@ -1,12 +1,14 @@
-- GENERATED by scratchpad/anim_export.py -- DO NOT EDIT BY HAND.
-- Re-export: python anim_export.py enso_normal/song_select/song_select_main_genre.nulm #19 --range 27,150 --fields tx,ty --out wheel_decide.lua
-- Source: enso_normal/song_select/song_select_main_genre.nulm clip #19 frames 27..150 @ 60 fps
-- Rows are {frame, tx, ty}; every field is LINEAR between two rows.
-- GENERATED from the cabinet clip with lumen_anim_dump -- DO NOT EDIT BY HAND.
-- Re-export: lumen_anim_dump.exe enso_normal/song_select/song_select_main_genre.nulm --sprite 19 --all --range 27,255
-- Source: enso_normal/song_select/song_select_main_genre.nulm clip #19 frames 27..255 @ 60 fps
-- Rows are {frame, tx, ty}; every field is LINEAR between two rows. f27..150 is the
-- folder OPEN leg (genre_deceide f45, return f150), f150..255 the CLOSE leg (return
-- f150 .. genre_deceide2 f255); at f255 the clip re-bases for a second decide.
return {
movie = "enso_normal/song_select/song_select_main_genre.nulm",
clip = "#19",
fps = 60,
range = { 27, 150 },
range = { 27, 255 },
fields = { "tx", "ty" },
labels = {
["init"] = 0,
@@ -21,13 +23,36 @@ return {
tracks = {
["kanban_genre_1"] = {
{ 27, 5.55, 28.35 },
{ 28, 11.1, 56.65 },
{ 30, 22.2, 113.35 },
{ 31, 27.8, 141.65 },
{ 33, 38.9, 198.35 },
{ 34, 44.45, 226.65 },
{ 35, 50, 255 },
{ 36, 44.45, 226.65 },
{ 37, 38.9, 198.35 },
{ 39, 27.8, 141.65 },
{ 40, 22.2, 113.35 },
{ 42, 11.1, 56.65 },
{ 43, 5.55, 28.35 },
{ 44, 0, 0 },
{ 150, 0, 0 },
{ 254, 0, 0 },
{ 255, 50, 255 },
},
["kanban_genre_2"] = {
{ 27, -44.45, -226.65 },
{ 28, -38.9, -198.35 },
{ 30, -27.8, -141.65 },
{ 31, -22.2, -113.35 },
{ 33, -11.1, -56.65 },
{ 34, -5.55, -28.35 },
{ 35, 0, 0 },
{ 36, -5.55, -28.35 },
{ 37, -11.1, -56.65 },
{ 39, -22.2, -113.35 },
{ 40, -27.8, -141.65 },
{ 42, -38.9, -198.35 },
{ 43, -44.45, -226.65 },
{ 44, -50, -255 },
{ 86, -50, -255 },
{ 87, -50.7, -257.4 },
@@ -57,11 +82,44 @@ return {
{ 139, -52.85, -264.6 },
{ 140, -50.7, -257.4 },
{ 141, -50, -255 },
{ 150, -50, -255 },
{ 191, -50, -255 },
{ 192, -50.7, -257.4 },
{ 193, -52.85, -264.6 },
{ 194, -56.4, -276.55 },
{ 195, -61.35, -293.35 },
{ 196, -67.75, -314.9 },
{ 197, -75.55, -341.25 },
{ 198, -84.8, -372.45 },
{ 199, -95.45, -408.4 },
{ 200, -107.5, -449.1 },
{ 201, -121, -494.65 },
{ 202, -135.9, -544.95 },
{ 203, -152.25, -600.1 },
{ 204, -170, -660 },
{ 233, -170, -660 },
{ 234, -152.25, -600.1 },
{ 235, -135.9, -545 },
{ 236, -121, -494.65 },
{ 237, -107.5, -449.1 },
{ 238, -95.45, -408.4 },
{ 239, -84.8, -372.45 },
{ 240, -75.55, -341.25 },
{ 241, -67.75, -314.9 },
{ 242, -61.35, -293.35 },
{ 243, -56.4, -276.55 },
{ 244, -52.85, -264.6 },
{ 245, -50.7, -257.4 },
{ 246, -50, -255 },
{ 254, -50, -255 },
{ 255, 0, 0 },
},
["kanban_genre_3"] = {
{ 27, 54.45, 270 },
{ 30, 67.8, 315 },
{ 31, 72.2, 330 },
{ 35, 90, 390 },
{ 39, 72.2, 330 },
{ 40, 67.8, 315 },
{ 44, 50, 255 },
{ 86, 50, 255 },
{ 87, 50.7, 257.4 },
@@ -91,11 +149,44 @@ return {
{ 139, 52.85, 264.6 },
{ 140, 50.7, 257.4 },
{ 141, 50, 255 },
{ 150, 50, 255 },
{ 191, 50, 255 },
{ 192, 50.7, 257.4 },
{ 193, 52.85, 264.6 },
{ 194, 56.4, 276.55 },
{ 195, 61.35, 293.35 },
{ 196, 67.75, 314.9 },
{ 197, 75.55, 341.25 },
{ 198, 84.8, 372.45 },
{ 199, 95.45, 408.4 },
{ 200, 107.5, 449.1 },
{ 201, 121, 494.65 },
{ 202, 135.9, 544.95 },
{ 203, 152.25, 600.1 },
{ 204, 170, 660 },
{ 233, 170, 660 },
{ 234, 152.25, 600.1 },
{ 235, 135.9, 545 },
{ 236, 121, 494.65 },
{ 237, 107.5, 449.1 },
{ 238, 95.45, 408.4 },
{ 239, 84.8, 372.45 },
{ 240, 75.55, 341.25 },
{ 241, 67.75, 314.9 },
{ 242, 61.35, 293.35 },
{ 243, 56.4, 276.55 },
{ 244, 52.85, 264.6 },
{ 245, 50.7, 257.4 },
{ 246, 50, 255 },
{ 254, 50, 255 },
{ 255, 90, 390 },
},
["kanban_genre_4"] = {
{ 27, -85.55, -375 },
{ 30, -72.2, -330 },
{ 31, -67.8, -315 },
{ 35, -50, -255 },
{ 39, -67.8, -315 },
{ 40, -72.2, -330 },
{ 44, -90, -390 },
{ 82, -90, -390 },
{ 83, -90.7, -392.4 },
@@ -125,11 +216,44 @@ return {
{ 143, -92.85, -399.6 },
{ 144, -90.7, -392.4 },
{ 145, -90, -390 },
{ 150, -90, -390 },
{ 187, -90, -390 },
{ 188, -90.7, -392.4 },
{ 189, -92.85, -399.6 },
{ 190, -96.4, -411.55 },
{ 191, -101.35, -428.35 },
{ 192, -107.75, -449.9 },
{ 193, -115.55, -476.25 },
{ 194, -124.8, -507.45 },
{ 195, -135.45, -543.4 },
{ 196, -147.5, -584.1 },
{ 197, -161, -629.65 },
{ 198, -175.9, -679.95 },
{ 199, -192.25, -735.1 },
{ 200, -210, -795 },
{ 237, -210, -795 },
{ 238, -192.25, -735.1 },
{ 239, -175.9, -680 },
{ 240, -161, -629.65 },
{ 241, -147.5, -584.1 },
{ 242, -135.45, -543.4 },
{ 243, -124.8, -507.45 },
{ 244, -115.55, -476.25 },
{ 245, -107.75, -449.9 },
{ 246, -101.35, -428.35 },
{ 247, -96.4, -411.55 },
{ 248, -92.85, -399.6 },
{ 249, -90.7, -392.4 },
{ 250, -90, -390 },
{ 254, -90, -390 },
{ 255, -50, -255 },
},
["kanban_genre_5"] = {
{ 27, 94.45, 405 },
{ 30, 107.8, 450 },
{ 31, 112.2, 465 },
{ 35, 130, 525 },
{ 39, 112.2, 465 },
{ 40, 107.8, 450 },
{ 44, 90, 390 },
{ 82, 90, 390 },
{ 83, 90.7, 392.4 },
@@ -159,11 +283,44 @@ return {
{ 143, 92.85, 399.6 },
{ 144, 90.7, 392.4 },
{ 145, 90, 390 },
{ 150, 90, 390 },
{ 187, 90, 390 },
{ 188, 90.7, 392.4 },
{ 189, 92.85, 399.6 },
{ 190, 96.4, 411.55 },
{ 191, 101.35, 428.35 },
{ 192, 107.75, 449.9 },
{ 193, 115.55, 476.25 },
{ 194, 124.8, 507.45 },
{ 195, 135.45, 543.4 },
{ 196, 147.5, 584.1 },
{ 197, 161, 629.65 },
{ 198, 175.9, 679.95 },
{ 199, 192.25, 735.1 },
{ 200, 210, 795 },
{ 237, 210, 795 },
{ 238, 192.25, 735.1 },
{ 239, 175.9, 680 },
{ 240, 161, 629.65 },
{ 241, 147.5, 584.1 },
{ 242, 135.45, 543.4 },
{ 243, 124.8, 507.45 },
{ 244, 115.55, 476.25 },
{ 245, 107.75, 449.9 },
{ 246, 101.35, 428.35 },
{ 247, 96.4, 411.55 },
{ 248, 92.85, 399.6 },
{ 249, 90.7, 392.4 },
{ 250, 90, 390 },
{ 254, 90, 390 },
{ 255, 130, 525 },
},
["kanban_genre_6"] = {
{ 27, -125.55, -510 },
{ 30, -112.2, -465 },
{ 31, -107.8, -450 },
{ 35, -90, -390 },
{ 39, -107.8, -450 },
{ 40, -112.2, -465 },
{ 44, -130, -525 },
{ 78, -130, -525 },
{ 79, -130.7, -527.4 },
@@ -193,11 +350,43 @@ return {
{ 147, -132.85, -534.6 },
{ 148, -130.7, -527.4 },
{ 149, -130, -525 },
{ 150, -130, -525 },
{ 183, -130, -525 },
{ 184, -130.7, -527.4 },
{ 185, -132.85, -534.6 },
{ 186, -136.4, -546.55 },
{ 187, -141.35, -563.35 },
{ 188, -147.75, -584.9 },
{ 189, -155.55, -611.25 },
{ 190, -164.8, -642.45 },
{ 191, -175.45, -678.4 },
{ 192, -187.5, -719.1 },
{ 193, -201, -764.65 },
{ 194, -215.9, -814.95 },
{ 195, -232.25, -870.1 },
{ 196, -250, -930 },
{ 241, -250, -930 },
{ 242, -232.25, -870.1 },
{ 243, -215.9, -815 },
{ 244, -201, -764.65 },
{ 245, -187.5, -719.1 },
{ 246, -175.45, -678.4 },
{ 247, -164.8, -642.45 },
{ 248, -155.55, -611.25 },
{ 249, -147.75, -584.9 },
{ 250, -141.35, -563.35 },
{ 251, -136.4, -546.55 },
{ 252, -132.85, -534.6 },
{ 253, -130.7, -527.4 },
{ 254, -130, -525 },
{ 255, -90, -390 },
},
["kanban_genre_7"] = {
{ 27, 134.45, 540 },
{ 30, 147.8, 585 },
{ 31, 152.2, 600 },
{ 35, 170, 660 },
{ 39, 152.2, 600 },
{ 40, 147.8, 585 },
{ 44, 130, 525 },
{ 78, 130, 525 },
{ 79, 130.7, 527.4 },
@@ -227,229 +416,46 @@ return {
{ 147, 132.85, 534.6 },
{ 148, 130.7, 527.4 },
{ 149, 130, 525 },
{ 150, 130, 525 },
{ 183, 130, 525 },
{ 184, 130.7, 527.4 },
{ 185, 132.85, 534.6 },
{ 186, 136.4, 546.55 },
{ 187, 141.35, 563.35 },
{ 188, 147.75, 584.9 },
{ 189, 155.55, 611.25 },
{ 190, 164.8, 642.45 },
{ 191, 175.45, 678.4 },
{ 192, 187.5, 719.1 },
{ 193, 201, 764.65 },
{ 194, 215.9, 814.95 },
{ 195, 232.25, 870.1 },
{ 196, 250, 930 },
{ 241, 250, 930 },
{ 242, 232.25, 870.1 },
{ 243, 215.9, 815 },
{ 244, 201, 764.65 },
{ 245, 187.5, 719.1 },
{ 246, 175.45, 678.4 },
{ 247, 164.8, 642.45 },
{ 248, 155.55, 611.25 },
{ 249, 147.75, 584.9 },
{ 250, 141.35, 563.35 },
{ 251, 136.4, 546.55 },
{ 252, 132.85, 534.6 },
{ 253, 130.7, 527.4 },
{ 254, 130, 525 },
{ 255, 170, 660 },
},
["kanban_genre_8"] = {
{ 27, -165.55, -645 },
{ 30, -152.2, -600 },
{ 31, -147.8, -585 },
{ 35, -130, -525 },
{ 39, -147.8, -585 },
{ 40, -152.2, -600 },
{ 44, -170, -660 },
{ 150, -170, -660 },
},
["kanban_song_1"] = {
{ 27, 5.55, 28.35 },
{ 35, 50, 255 },
{ 44, 0, 0 },
{ 150, 0, 0 },
},
["kanban_song_2"] = {
{ 27, -44.45, -226.65 },
{ 35, 0, 0 },
{ 44, -50, -255 },
{ 86, -50, -255 },
{ 87, -50.7, -257.4 },
{ 88, -52.85, -264.6 },
{ 89, -56.4, -276.55 },
{ 90, -61.35, -293.35 },
{ 91, -67.75, -314.9 },
{ 92, -75.55, -341.25 },
{ 93, -84.8, -372.45 },
{ 94, -95.45, -408.4 },
{ 95, -107.5, -449.1 },
{ 96, -121, -494.65 },
{ 97, -135.9, -544.95 },
{ 98, -152.25, -600.1 },
{ 99, -170, -660 },
{ 128, -170, -660 },
{ 129, -152.25, -600.1 },
{ 130, -135.9, -545 },
{ 131, -121, -494.65 },
{ 132, -107.5, -449.1 },
{ 133, -95.45, -408.4 },
{ 134, -84.8, -372.45 },
{ 135, -75.55, -341.25 },
{ 136, -67.75, -314.9 },
{ 137, -61.35, -293.35 },
{ 138, -56.4, -276.55 },
{ 139, -52.85, -264.6 },
{ 140, -50.7, -257.4 },
{ 141, -50, -255 },
{ 150, -50, -255 },
},
["kanban_song_3"] = {
{ 27, 54.45, 270 },
{ 35, 90, 390 },
{ 44, 50, 255 },
{ 86, 50, 255 },
{ 87, 50.7, 257.4 },
{ 88, 52.85, 264.6 },
{ 89, 56.4, 276.55 },
{ 90, 61.35, 293.35 },
{ 91, 67.75, 314.9 },
{ 92, 75.55, 341.25 },
{ 93, 84.8, 372.45 },
{ 94, 95.45, 408.4 },
{ 95, 107.5, 449.1 },
{ 96, 121, 494.65 },
{ 97, 135.9, 544.95 },
{ 98, 152.25, 600.1 },
{ 99, 170, 660 },
{ 128, 170, 660 },
{ 129, 152.25, 600.1 },
{ 130, 135.9, 545 },
{ 131, 121, 494.65 },
{ 132, 107.5, 449.1 },
{ 133, 95.45, 408.4 },
{ 134, 84.8, 372.45 },
{ 135, 75.55, 341.25 },
{ 136, 67.75, 314.9 },
{ 137, 61.35, 293.35 },
{ 138, 56.4, 276.55 },
{ 139, 52.85, 264.6 },
{ 140, 50.7, 257.4 },
{ 141, 50, 255 },
{ 150, 50, 255 },
},
["kanban_song_4"] = {
{ 27, -85.55, -375 },
{ 35, -50, -255 },
{ 44, -90, -390 },
{ 82, -90, -390 },
{ 83, -90.7, -392.4 },
{ 84, -92.85, -399.6 },
{ 85, -96.4, -411.55 },
{ 86, -101.35, -428.35 },
{ 87, -107.75, -449.9 },
{ 88, -115.55, -476.25 },
{ 89, -124.8, -507.45 },
{ 90, -135.45, -543.4 },
{ 91, -147.5, -584.1 },
{ 92, -161, -629.65 },
{ 93, -175.9, -679.95 },
{ 94, -192.25, -735.1 },
{ 95, -210, -795 },
{ 132, -210, -795 },
{ 133, -192.25, -735.1 },
{ 134, -175.9, -680 },
{ 135, -161, -629.65 },
{ 136, -147.5, -584.1 },
{ 137, -135.45, -543.4 },
{ 138, -124.8, -507.45 },
{ 139, -115.55, -476.25 },
{ 140, -107.75, -449.9 },
{ 141, -101.35, -428.35 },
{ 142, -96.4, -411.55 },
{ 143, -92.85, -399.6 },
{ 144, -90.7, -392.4 },
{ 145, -90, -390 },
{ 150, -90, -390 },
},
["kanban_song_5"] = {
{ 27, 94.45, 405 },
{ 35, 130, 525 },
{ 44, 90, 390 },
{ 82, 90, 390 },
{ 83, 90.7, 392.4 },
{ 84, 92.85, 399.6 },
{ 85, 96.4, 411.55 },
{ 86, 101.35, 428.35 },
{ 87, 107.75, 449.9 },
{ 88, 115.55, 476.25 },
{ 89, 124.8, 507.45 },
{ 90, 135.45, 543.4 },
{ 91, 147.5, 584.1 },
{ 92, 161, 629.65 },
{ 93, 175.9, 679.95 },
{ 94, 192.25, 735.1 },
{ 95, 210, 795 },
{ 132, 210, 795 },
{ 133, 192.25, 735.1 },
{ 134, 175.9, 680 },
{ 135, 161, 629.65 },
{ 136, 147.5, 584.1 },
{ 137, 135.45, 543.4 },
{ 138, 124.8, 507.45 },
{ 139, 115.55, 476.25 },
{ 140, 107.75, 449.9 },
{ 141, 101.35, 428.35 },
{ 142, 96.4, 411.55 },
{ 143, 92.85, 399.6 },
{ 144, 90.7, 392.4 },
{ 145, 90, 390 },
{ 150, 90, 390 },
},
["kanban_song_6"] = {
{ 27, -125.55, -510 },
{ 35, -90, -390 },
{ 44, -130, -525 },
{ 78, -130, -525 },
{ 79, -130.7, -527.4 },
{ 80, -132.85, -534.6 },
{ 81, -136.4, -546.55 },
{ 82, -141.35, -563.35 },
{ 83, -147.75, -584.9 },
{ 84, -155.55, -611.25 },
{ 85, -164.8, -642.45 },
{ 86, -175.45, -678.4 },
{ 87, -187.5, -719.1 },
{ 88, -201, -764.65 },
{ 89, -215.9, -814.95 },
{ 90, -232.25, -870.1 },
{ 91, -250, -930 },
{ 136, -250, -930 },
{ 137, -232.25, -870.1 },
{ 138, -215.9, -815 },
{ 139, -201, -764.65 },
{ 140, -187.5, -719.1 },
{ 141, -175.45, -678.4 },
{ 142, -164.8, -642.45 },
{ 143, -155.55, -611.25 },
{ 144, -147.75, -584.9 },
{ 145, -141.35, -563.35 },
{ 146, -136.4, -546.55 },
{ 147, -132.85, -534.6 },
{ 148, -130.7, -527.4 },
{ 149, -130, -525 },
{ 150, -130, -525 },
},
["kanban_song_7"] = {
{ 27, 134.45, 540 },
{ 35, 170, 660 },
{ 44, 130, 525 },
{ 78, 130, 525 },
{ 79, 130.7, 527.4 },
{ 80, 132.85, 534.6 },
{ 81, 136.4, 546.55 },
{ 82, 141.35, 563.35 },
{ 83, 147.75, 584.9 },
{ 84, 155.55, 611.25 },
{ 85, 164.8, 642.45 },
{ 86, 175.45, 678.4 },
{ 87, 187.5, 719.1 },
{ 88, 201, 764.65 },
{ 89, 215.9, 814.95 },
{ 90, 232.25, 870.1 },
{ 91, 250, 930 },
{ 136, 250, 930 },
{ 137, 232.25, 870.1 },
{ 138, 215.9, 815 },
{ 139, 201, 764.65 },
{ 140, 187.5, 719.1 },
{ 141, 175.45, 678.4 },
{ 142, 164.8, 642.45 },
{ 143, 155.55, 611.25 },
{ 144, 147.75, 584.9 },
{ 145, 141.35, 563.35 },
{ 146, 136.4, 546.55 },
{ 147, 132.85, 534.6 },
{ 148, 130.7, 527.4 },
{ 149, 130, 525 },
{ 150, 130, 525 },
},
["kanban_song_8"] = {
{ 27, -165.55, -645 },
{ 35, -130, -525 },
{ 44, -170, -660 },
{ 150, -170, -660 },
{ 254, -170, -660 },
{ 255, -130, -525 },
},
},
}
+140 -22
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
@@ -710,13 +712,17 @@ end
-- width -- exactly how the existing `y2 = h - 352` calls already drive the height. So a
-- horizontal scale is `x2 = BOARD_W * (sx - 1)` plus a re-centred x, with no engine
-- change. sx = nil/1 leaves every pre-r61 call byte-identical.
-- A furled board (sx < 1) is not a squashed copy of the 960-wide texture: squashing
-- averages the outline away and makes the GPU pick a small mip level (the LOD follows
-- the larger axis), which blurs every row. The cabinet scales a vector shape, so its
-- edges stay sharp at any width. Five columns get the same result from the bitmap:
-- the two rounded corners at 1:1 (40 px), and the coloured band / inner panel / band
-- between them scaled in proportion, each drawn from an 8 px flat slice of itself and
-- MAGNIFIED to its width. Column layout of every bar_genre frame and the back board:
-- corner 0..40 | band 40..83 | panel 83..877 | band 877..920 | corner 920..960.
local function draw_board(bar_id, frame, bx, by, cen_h, fade, crop_center, sx)
local w = BOARD_W
local x2 = nil
if sx and sx ~= 1.0 then
w = BOARD_W * sx
x2 = w - BOARD_W
end
if sx and sx ~= 1.0 then w = math.max(2, math.floor(BOARD_W * sx + 0.5)) end
local x = math.floor(bx - w / 2 + 0.5)
local top = math.floor(by - cen_h / 2 + 0.5) - CAP_H
local src_y, src_h = CAP_H, CEN_SRC_H
@@ -725,12 +731,53 @@ local function draw_board(bar_id, frame, bx, by, cen_h, fade, crop_center, sx)
src_y = CAP_H + math.floor((CEN_SRC_H - src_h) / 2)
cen_h = src_h
end
tex.draw_texture(bar_id, { frame = frame, x = x, y = top, y2 = CAP_H - 352, x2 = x2, fade = fade,
src = { x = 0, y = 0, width = BOARD_W, height = CAP_H } })
tex.draw_texture(bar_id, { frame = frame, x = x, y = top + CAP_H, y2 = cen_h - 352, x2 = x2, fade = fade,
src = { x = 0, y = src_y, width = BOARD_W, height = src_h } })
tex.draw_texture(bar_id, { frame = frame, x = x, y = top + CAP_H + cen_h, y2 = CAP_H - 352, x2 = x2, fade = fade,
src = { x = 0, y = CAP_H + CEN_SRC_H, width = BOARD_W, height = CAP_H } })
-- the three horizontal bands (top cap / centre / bottom cap) as {y, src_y, src_h, dst_h}
local bands = { { top, 0, CAP_H, CAP_H }, { top + CAP_H, src_y, src_h, cen_h },
{ top + CAP_H + cen_h, CAP_H + CEN_SRC_H, CAP_H, CAP_H } }
if w == BOARD_W then
for _, b in ipairs(bands) do
tex.draw_texture(bar_id, { frame = frame, x = x, y = b[1], y2 = b[4] - 352, fade = fade,
src = { x = 0, y = b[2], width = BOARD_W, height = b[3] } })
end
return
end
local CORNER, BAND, PANEL = 40, 43, 794 -- source widths; 40+43+794+43+40 = 960
local cols
if w >= 2 * CORNER then
local corner = CORNER
local inner = w - 2 * corner
local band = math.floor(inner * BAND / (2 * BAND + PANEL) + 0.5)
local panel = inner - 2 * band
-- columns: {src_x, src_w, dst_x, dst_w}
cols = {
{ 0, CORNER, x, corner },
{ CORNER + BAND / 2 - 4, 8, x + corner, band },
{ BOARD_W / 2 - 4, 8, x + corner + band, panel },
{ BOARD_W - CORNER - BAND / 2 - 4, 8, x + corner + band + panel, band },
{ BOARD_W - CORNER, CORNER, x + w - corner, corner },
}
else
-- narrower than both corners (the last frames of a furl / first of an unfurl): the
-- cabinet's vector shape is a solid bar with its outline all round, so draw the
-- two outline columns (texture x 13..20 / 940..947) at a few px each and fill the
-- rest from the flat centre slice -- squeezing the rounded corners instead left
-- two hollow strokes with nothing between them.
local ol = math.max(2, math.min(8, math.floor(w / 6)))
local mid = math.max(0, w - 2 * ol)
cols = {
{ 13, 8, x, ol },
{ BOARD_W / 2 - 4, 8, x + ol, mid },
{ 940, 8, x + ol + mid, ol },
}
end
for _, b in ipairs(bands) do
for _, c in ipairs(cols) do
if c[4] > 0 then
tex.draw_texture(bar_id, { frame = frame, x = c[3], y = b[1], x2 = c[4] - BOARD_W, y2 = b[4] - 352,
fade = fade, src = { x = c[1], y = b[2], width = c[2], height = b[3] } })
end
end
end
end
-- Yellow cursor glow around the board (arcade cursor_top/center/bottom): the glow's caps
@@ -979,6 +1026,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 +1041,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 +1098,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
@@ -1054,6 +1114,15 @@ local function leg_f()
return f
end
-- The engine's own box fade, except during the pre-swap half of the CLOSE leg: there the
-- engine fades the song boxes and the back board out in 166 ms, while the cabinet keeps
-- them solid until they fly out (f184..204) / the board furls (f205..217) -- those come
-- from the clip channels, so the engine fade is ignored until the swap.
local function box_fade(box)
if R61.kind == "close" and R61.t0 and not R61.swapped then return 1.0 end
return box.fade.attribute
end
-- Start / advance the leg. `begin` puts the clock on the label frame; `swap` re-anchors
-- it on the cabinet's content-swap frame so the post-swap half is phase-exact no matter
-- how long the loader took.
@@ -1061,8 +1130,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,8 +1168,17 @@ 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 f >= FLY_END_F then return 0.0, 0.0 end
if not f then return 0.0, 0.0 end
if R61.kind == "open" then
if f >= FLY_END_F then return 0.0, 0.0 end
elseif R61.kind == "close" then
-- the CLOSE leg is the clip's `return` half: the song boxes fly out f184..204,
-- wait off screen across the swap (f219) and the genre boxes fly back in
-- f234..254; f255 (`genre_deceide2`) re-bases the clip, so stop just before it
if f >= (WHEEL_FLY:label("genre_deceide2") or 255) - 1 then return 0.0, 0.0 end
else
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
local d = box:box_y() - FLY_CENTER_Y
@@ -1109,6 +1195,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,
@@ -1348,7 +1453,7 @@ end
function SongSelect:draw_song_board(box, pb, ia, ic)
local bx, by = box:box_x(), box:box_y()
local fdx, fdy = fly_offset(box); bx, by = bx + fdx, by + fdy -- r56 wheel fly-in
local fade = math.min(1.0, box.fade.attribute)
local fade = math.min(1.0, box_fade(box))
-- ROUND 61: the folder-ENTER unfurl. On the frames the cabinet is playing
-- genre_deceide f113..f145 the incoming song board is NOT growing vertically from
@@ -1375,6 +1480,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
@@ -2077,7 +2185,7 @@ function SongSelect:draw_folder_board(box, pb, ch_alpha, ch_off, ta, glow_a)
local bx, by = box:box_x(), box:box_y()
local fdx, fdy = fly_offset(box); bx, by = bx + fdx, by + fdy -- r56 wheel fly-in
local cen_h = CEN_CLOSED_H + (CEN_OPEN_H - CEN_CLOSED_H) * pb
local fade = box.fade.attribute
local fade = box_fade(box)
local frame, has_pattern = folder_frame(box)
-- ROUND 85 ---------------------------------------------------------------
@@ -2094,7 +2202,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 +2331,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
@@ -2273,7 +2390,7 @@ function SongSelect:draw_back_board(box, p)
local bx, by = box:box_x(), box:box_y()
local fdx, fdy = fly_offset(box); bx, by = bx + fdx, by + fdy -- r56 wheel fly-in
local cen_h = CEN_CLOSED_H + (CEN_OPEN_H - CEN_CLOSED_H) * p
local fade = math.min(1.0, box.fade.attribute)
local fade = math.min(1.0, box_fade(box))
-- ROUND 85: on the cabinet the panel that unfurls across the swap is the
-- newly-focused one (`GetSongKanbanMc(kSelectNumber + openOffset)`). In THIS
@@ -2286,6 +2403,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 +2762,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)
@@ -2665,7 +2783,7 @@ function SongSelect:draw_box(box)
p = e and (folder_close_timeline(e)) or 0.0
end
local cen_h = CEN_CLOSED_H + (CEN_OPEN_H - CEN_CLOSED_H) * p
local fade = math.min(1.0, box.fade.attribute)
local fade = math.min(1.0, box_fade(box))
if p > 0 then self:draw_glow(bx, by, cen_h, fade * p * glow_pulse()) end
draw_board((p > 0) and self._id_bar_folder or self._id_bar_genre, 10, bx, by, cen_h, fade, p <= 0 or p >= 1) -- ROUND 5: closed = full pale panel
if p > 0 and p < 1 then draw_board(self._id_bar_genre, 10, bx, by, cen_h, fade * (1.0 - p)) end
+2 -2
View File
@@ -3171,7 +3171,7 @@ e08f82230e9e8f8c00deed9a7d0d0eaba6933021b9960b782a8b77eca3200b06 *./Scripts/anim
eb2bb15e87cc83d66b320e0e4cbcbd2d5385881f36eca27fe73740439055ef6c *./Scripts/anim/sort_cursor.lua
5789c13c7958010f2878f9a0b119a50af4f362e754dc06ca3683ce742d507d25 *./Scripts/anim/title_idle.lua
24e7afe3e93935774c14aebce3e635970ec045952224ea5246633ff05b37e3af *./Scripts/anim/title_idle_map.lua
a340f195886e0e372da2cca847c1a243ed56d76239597c01f6ccdf11d1779759 *./Scripts/anim/wheel_decide.lua
2a160f3c8902d329effb39fb342087b6f7dca56b15c13d1b605b7cf3ca275b1c *./Scripts/anim/wheel_decide.lua
4e61d41a6f50228b0d320290a99c7f6658843936448c61aff89c5a1e86891121 *./Scripts/background/background.lua
1d35116ef8edb2c9acf9ccc26024e1e788cf3cb010b87a930f1f76108d3c6b69 *./Scripts/background/bg_collabs/a3.lua
784052aa0ba1881415d1468174453cbee33b2cc58c6283b0a53758759a750668 *./Scripts/background/bg_collabs/animal.lua
@@ -3277,7 +3277,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
698d1ba46c4be558b59624e339a5e1971d12bff5119daed2bc22bdeb5b305286 *./Scripts/song_select/song_select.lua
89047ab5b642696922ca2c6e098ca288580a9c0bb3e197a08f17b821a31fc519 *./.skin-repo
40c378cdcaea2e2c9ec3da4c7fa72911d13a849a5b51e9645300f9571a7e12c8 *./Sounds/dan_result/achieve_tamashii.ogg
606f2d3558badc06e54b2c59a36f0580f4954774918d69a712ad6de45518cba0 *./Sounds/dan_result/advance_intro.ogg