diff --git a/Scripts/anim/wheel_decide.lua b/Scripts/anim/wheel_decide.lua index 1d1dca4..b69ad89 100644 --- a/Scripts/anim/wheel_decide.lua +++ b/Scripts/anim/wheel_decide.lua @@ -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 }, }, }, } diff --git a/Scripts/song_select/song_select.lua b/Scripts/song_select/song_select.lua index d280ee5..7d16400 100644 --- a/Scripts/song_select/song_select.lua +++ b/Scripts/song_select/song_select.lua @@ -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 diff --git a/checksums.sha256 b/checksums.sha256 index 990d82e..5da8c5b 100644 --- a/checksums.sha256 +++ b/checksums.sha256 @@ -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