From f44fdf5d6f9cbdb9bbf4f77e8a72e0fc8c310bb0 Mon Sep 17 00:00:00 2001 From: Cyphgirl Date: Sat, 8 Aug 2026 08:55:30 -0400 Subject: [PATCH] Extract the capture cutscene sheet from baserom gCaptureScreenTilesGfx goes over the tile-704 overlay slot from three call sites. Six segments: the float-up fx at t0..101 from gPokemonFloatOamFramesets, the ball absorb fx at t127..222 from gMonCatchBallAbsorbPokemonFxSpriteSet, and between them the two sub-slots at t102..105 and t123..126 that gCaptureBallTilesGfx streams the ball itself into, a gap and a tail. This one does not end in a blank tile. The copy is 0x1C00 but the label runs 0x1C20, and that last tile holds real pixels, so it stays in the sheet instead of becoming .space the way the others did. Worth checking per blob rather than assuming, since five sheets in a row had a blank there. Four of the six segments needed palette overrides. The float-up fx votes on full coverage and is bank 14, but everything from t123 on is the ball and its absorb fx in bank 1, and a banner sheet sharing the slot outvoted that with 88 tiles of bank 14. gMonCatchBallAbsorbPokemonFxSpriteSet names bank 1 throughout, and the ball slots take gBallPalettes, which the board loads into bank 1. Rebuilt sheet matches the ROM blob before and after recolouring, check passes, make compare passes. Co-Authored-By: Claude Opus 5 --- data/rom_1.s | 10 +- .../stage/main/capture_screen_absorb_fx.png | Bin 0 -> 946 bytes .../capture_screen_capture_ball_slot_0.png | Bin 0 -> 220 bytes .../capture_screen_capture_ball_slot_1.png | Bin 0 -> 211 bytes .../stage/main/capture_screen_float_mon.png | Bin 0 -> 1197 bytes .../main/capture_screen_unreferenced_gap.png | Bin 0 -> 330 bytes .../stage/main/capture_screen_unused_tail.png | Bin 0 -> 154 bytes graphics/stage/main/main_stage_gfx.json | 233 ++++++++++-------- tools/scripts/objpalette.py | 15 ++ 9 files changed, 161 insertions(+), 97 deletions(-) create mode 100644 graphics/stage/main/capture_screen_absorb_fx.png create mode 100644 graphics/stage/main/capture_screen_capture_ball_slot_0.png create mode 100644 graphics/stage/main/capture_screen_capture_ball_slot_1.png create mode 100644 graphics/stage/main/capture_screen_float_mon.png create mode 100644 graphics/stage/main/capture_screen_unreferenced_gap.png create mode 100644 graphics/stage/main/capture_screen_unused_tail.png diff --git a/data/rom_1.s b/data/rom_1.s index 34e7c656..540698c5 100644 --- a/data/rom_1.s +++ b/data/rom_1.s @@ -787,8 +787,16 @@ gRayquazaBonusClear_Gfx:: @ 0x081408B4 .incbin "graphics/stage/rayquaza/rayquaza_bonus_clear.4bpp" .space 0x20 +@ The capture cutscene, streamed over the tile-704 overlay slot from three +@ places (main_board_center_capture_hole.c, main_board_to_be_split.c and +@ save_and_restore_game.c). t0..101 is the float-up fx drawn by +@ gPokemonFloatOamFramesets, t127..222 the ball absorb fx from +@ gMonCatchBallAbsorbPokemonFxSpriteSet. t102..105 and t123..126 are sub-slots +@ the ball graphic streams into, from gCaptureBallTilesGfx. +@ Unlike the other sheets here the copy is 0x20 short of the label, and that +@ last tile is not blank, so it stays in the sheet rather than becoming .space. gCaptureScreenTilesGfx:: @ 0x081428D4 - .incbin "baserom.gba", 0x1428D4, 0x1C20 + .incbin "graphics/stage/main/capture_screen.4bpp" .include "data/graphics/mon_hatch_sprites_pals.inc" diff --git a/graphics/stage/main/capture_screen_absorb_fx.png b/graphics/stage/main/capture_screen_absorb_fx.png new file mode 100644 index 0000000000000000000000000000000000000000..f087e31bd0ff796c0591ca6b6895878a04be9ec3 GIT binary patch literal 946 zcmV;j15NyiP)_OM%7SA)Ua2cVZW?m^!8vqgQ$X7}r;6<3nP(E)cuW&H^z;5AlE(xDP@H|)8>0&oF!DAT0_kbMIM zhqbFZUz!Q*C&2Adw8gUAC|zh>DWG}J;h#MH6#o-sDo1b@$snctB!ye6L4bNUHxHPL zlXlW!tprzdty*u3{qlS43p2;!>MeIXhhRe_PJnd~EEBMoQ=o|1An+dOC%|4Vps(O| z3EqId0{s7A2|s-b){LzwsLPe194ER3{VO!3i z>Sw_^NWm15Xbm(jqqvT;Ch=}oP_6s;ldH8IW*yWBBu<>(SUM&c$+-dL29WB{0p5TX z4_yy=?A3GvXd4c~Ue)x(qe{N_Ckb9OL?Z}g5YWsyp7Txgshen^IcN%0G)U;1pabtK zt@ff0vlEO7%ErN{LmSjVok0C49{_Y6-9Ynxu+~KH7y~UdAbP63lLKf5n)j^jN{FBd zXroB-IYup<0xO#K@c?nOyP$akDe$&JL_8g4u{|bP0HhTJjrxeEg9p+$KgU7pR`f^F zY}_a zIXP%JkUs~hQ13m<+gc=03R#g88oe!LKPaX{b)0|QVM2M0&Tag$R(z3HAVjv*DdLc0}( zju`MTw|W_~y>*|%t`c1Dcud#hMeSdQuHthWyWV;+O?dW)DS1`aI^BvHkp~~F413yn zDr`cAT9JUJ$L6U=UWRK7T0 S;?8rRl?hQ13m<+gc=03R#g88oe!LKPaX{b)0|QVM2M0&Tag$R(y>Xr{jv*DdLQikx zYB1noxiCA%``|C-lk6@$@A!7D`oG^|%R1AI3Kh}!Vi{VZ^cA!P3w_E~y9V%9^sNq; zo8qGt8+DIyqt{JQ3+W%5??_9f%;oVoEWhLU$435Rj2RyoYF;bM%{s>M4QLaCr>mdK II;Vst0MmL`G5`Po literal 0 HcmV?d00001 diff --git a/graphics/stage/main/capture_screen_float_mon.png b/graphics/stage/main/capture_screen_float_mon.png new file mode 100644 index 0000000000000000000000000000000000000000..384a80d9992f47f9cfd7ad16a330e3800834a188 GIT binary patch literal 1197 zcmV;e1XBBnP))qd04&}E zfak|Sf0p+B12EReiesE~1<-{7ShSMLSQwV-Wn3Aymu~4aCHTqdq8@Asx!i;aHuNa? zskz}kK!!TYCChrgxPw-b5d$Xkjzb^?lM<`sERK9IC84}w;5vf>#p6;cnE?}g&t9Ue z2Kk;}3M4>N2qeooL!+d58`pJFG#C6NSSgw88~xb^Sui^olE5!ldyOPk6P%=q|1F9m zu+v7tM0RQqs0Et50O;T(^FJ4?sR0|MvdOT@g}&k&AS&0EniVlcev|FCIcihuipotj zA&@$N9}!5n0|ytUZJGZcxPfN&C{LB;56ghDcH6#ZK&;o6Bt%vi7A^g8nXegGw@t%` zHw}57ViYN0w(n6X6V)58mxHQdL;)8MqHZFQ3kqciG>%InJ)@dizvZP+8jjB3C_z8B zt!-RrK0yX6dqjo?}IVpx3!q&FS z)+^XB1Q_8JZiHG0uptU1!7;DQ(NYRd`=G^ia$BA$44?(%nqvoH-h?(y`T&gM?#5*Y zb7N)Q&Vin~G6|v+<_GhNiY?aotrC!U3zI5T)+?rmK>go#gTtwgFwv*jGBga%#qkKh zPop|CP@TkteB;S*v5A+MIdvV*qO$y9DbdYH_P-{eRi|)S!1_>^9#WGGNrJM+Ys88b zHX1E-x-3Lp1MoLqJ#PWb&f{JsZ|~nVTXl6afolhBj2LRFNh-=ukZPEm*QW2+O zS#fBEb(2nUZ3+?5wkgzmUOm(io?36fQ=1JBJm!)Lu05SZxIC~ZGo_kTrPvAxuNFKw zW+JZa63;R`1!p2oqbeeqPB{bdHI_0&7C8f(x2I2&uAG4`L;ezl>&e8VC!nsD_1wY$ zJhr;o#Z-LxesK-Jd%!OB@|sC(wWTE*OLOEn0T~Onw6fx2d3e3bKqEj19xbobEx$T|vUo4? zT$9-A3n9-umlGgO1Hcf&n92lba&wWJ7f%1yES<(;@N6$GOf;5qnUwiN4tfObPa1Z3 zS=*uu8}rRzFiNnzxr`UK=dP8BIzm#xWz7d+C-e986iy_ z8E_i@dqZ>zampE5&=9Z6CHjY`CbnvA7pte$F@#{H&pBjEtt8Yx2<54uWpj~sB^F$~ zF3jyHX5?Y7*9l=+EFFoh0Yk^gT4lY{Wvevch*0$tc8Du6%X2$so1C|j*pd|s(wo<0 ch#nB&3phe&ON?4|P5=M^07*qoM6N<$f(HGQh5!Hn literal 0 HcmV?d00001 diff --git a/graphics/stage/main/capture_screen_unused_tail.png b/graphics/stage/main/capture_screen_unused_tail.png new file mode 100644 index 0000000000000000000000000000000000000000..30e1fbe1fe0a4899de48f23f973998b09df12129 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~c!VDytB9fK>DT4r?5Z4gv( z8+Lqf2srWM!iOIVUi^r7@#DvYA1?%691!@yzyMUm!NJjS+~gEcud1huV@SoV&+MG?9Vl2#BPjhl|dX5zsnz1ny=CkyjgTe~DWM4fY?nAA literal 0 HcmV?d00001 diff --git a/graphics/stage/main/main_stage_gfx.json b/graphics/stage/main/main_stage_gfx.json index b788c12a..2bab6e83 100644 --- a/graphics/stage/main/main_stage_gfx.json +++ b/graphics/stage/main/main_stage_gfx.json @@ -9,26 +9,26 @@ "files": [ { "gfx_filename": "board_action", - "segments":[ + "segments": [ { - "segfile": "board_action_text_large", - "width": 8 + "segfile": "board_action_text_large", + "width": 8 }, { - "segfile": "board_action_text_medium", - "width": 8 + "segfile": "board_action_text_medium", + "width": 8 }, { - "segfile": "board_action_text_small", - "width": 6 + "segfile": "board_action_text_small", + "width": 6 }, { - "segfile": "board_action_bolts", - "width": 2 + "segfile": "board_action_bolts", + "width": 2 }, { - "segfile": "board_action_sparkle", - "width": 2 + "segfile": "board_action_sparkle", + "width": 2 } ], "palette": "board_action_obj.gbapal", @@ -36,50 +36,50 @@ }, { "gfx_filename": "catch_tile_reveal", - "segments":[ + "segments": [ { - "segfile": "catch_tile_reveal_shards_0", - "width": 4 + "segfile": "catch_tile_reveal_shards_0", + "width": 4 }, { - "segfile": "catch_tile_reveal_shards_1", - "width": 2 + "segfile": "catch_tile_reveal_shards_1", + "width": 2 }, { - "segfile": "catch_tile_reveal_specks_0", - "width": 1 + "segfile": "catch_tile_reveal_specks_0", + "width": 1 }, { - "segfile": "catch_tile_reveal_shards_2", - "width": 2 + "segfile": "catch_tile_reveal_shards_2", + "width": 2 }, { - "segfile": "catch_tile_reveal_specks_1", - "width": 1 + "segfile": "catch_tile_reveal_specks_1", + "width": 1 }, { - "segfile": "catch_tile_reveal_shards_3", - "width": 2 + "segfile": "catch_tile_reveal_shards_3", + "width": 2 }, { - "segfile": "catch_tile_reveal_wave_0", - "width": 4 + "segfile": "catch_tile_reveal_wave_0", + "width": 4 }, { - "segfile": "catch_tile_reveal_debris", - "width": 5 + "segfile": "catch_tile_reveal_debris", + "width": 5 }, { - "segfile": "catch_tile_reveal_wave_1", - "width": 4 + "segfile": "catch_tile_reveal_wave_1", + "width": 4 }, { - "segfile": "catch_tile_reveal_wave_1_cap", - "width": 1 + "segfile": "catch_tile_reveal_wave_1_cap", + "width": 1 }, { - "segfile": "catch_tile_reveal_dome", - "width": 4 + "segfile": "catch_tile_reveal_dome", + "width": 4 } ], "palette": "catch_tile_reveal.gbapal", @@ -87,74 +87,74 @@ }, { "gfx_filename": "gunk_084F61EC", - "mwidth":8, - "align":1, + "mwidth": 8, + "align": 1, "palette": "bonus_stage_obj.gbapal", "palbank": 5 }, { "gfx_filename": "gunk_0844AA0C", - "mwidth":6, + "mwidth": 6, "mheight": 6, - "oam":true, + "oam": true, "palette": "../main/bonus_stage_obj.gbapal", "palbank": 4 }, { "gfx_filename": "pika_spinner", - "mwidth":3, - "mheight":3, - "width":12, - "oam":true, + "mwidth": 3, + "mheight": 3, + "width": 12, + "oam": true, "palette": "../ruby/ruby_board_palset_0.gbapal", "palbank": 3 }, { "gfx_filename": "jirachi_banner", - "mwidth":30, - "mheight":9, - "oam":true + "mwidth": 30, + "mheight": 9, + "oam": true }, { "gfx_filename": "travel", - "segments":[ + "segments": [ { "segfile": "travel_banner", - "mwidth":30, - "mheight":8, - "oam":true + "mwidth": 30, + "mheight": 8, + "oam": true }, { "segfile": "travel_bottom_border", - "width":5 + "width": 5 }, { "segfile": "travel_pole", - "width":4 + "width": 4 }, { "segfile": "travel_arrows", - "mwidth":3, - "mheight":4, - "oam":true + "mwidth": 3, + "mheight": 4, + "oam": true }, { "segfile": "travel_pole_base", - "width":2 + "width": 2 } ] }, { "gfx_filename": "evo_banner", - "mheight":9, - "mwidth":30, - "oam":true + "mheight": 9, + "mwidth": 30, + "oam": true }, { "gfx_filename": "game_over_text", "mheight": 2, "mwidth": 2, - "width":16, + "width": 16, "palette": "bonus_clear_text_lit.gbapal", "palbank": 0 }, @@ -165,14 +165,14 @@ }, { "gfx_filename": "latios", - "mheight":8, - "mwidth":8, + "mheight": 8, + "mwidth": 8, "palette": "bonus_stage_lit.gbapal", "palbank": 0 }, { "gfx_filename": "latios_arm", - "width":2, + "width": 2, "palette": "bonus_stage_lit.gbapal", "palbank": 0 }, @@ -180,20 +180,20 @@ "gfx_filename": "ball_save", "segments": [ { - "segfile":"ball_save_banner", - "mwidth":16, - "mheight":8, - "oam":true + "segfile": "ball_save_banner", + "mwidth": 16, + "mheight": 8, + "oam": true }, { - "segfile":"ball_save_latias", - "width":8, - "height":8 + "segfile": "ball_save_latias", + "width": 8, + "height": 8 }, { - "segfile":"ball_save_latias_arm", - "width":2, - "height":3 + "segfile": "ball_save_latias_arm", + "width": 2, + "height": 3 } ], "palette": "bonus_stage_lit.gbapal", @@ -203,31 +203,31 @@ "gfx_filename": "end_of_ball", "segments": [ { - "segfile":"end_of_ball_left", - "mwidth":8, - "mheight":8 + "segfile": "end_of_ball_left", + "mwidth": 8, + "mheight": 8 }, { - "segfile":"end_of_ball_top_corner", - "mwidth":2, - "mheight":2 + "segfile": "end_of_ball_top_corner", + "mwidth": 2, + "mheight": 2 }, { - "segfile":"end_of_ball_banner", - "mwidth":22, - "mheight":2, - "oam":true + "segfile": "end_of_ball_banner", + "mwidth": 22, + "mheight": 2, + "oam": true }, { - "segfile":"end_of_ball_right", - "mwidth":8, - "mheight":8 + "segfile": "end_of_ball_right", + "mwidth": 8, + "mheight": 8 }, { - "segfile":"end_of_ball_space", - "mwidth":24, - "mheight":2, - "oam":true + "segfile": "end_of_ball_space", + "mwidth": 24, + "mheight": 2, + "oam": true } ], "palette": "bonus_clear_text_lit.gbapal", @@ -235,27 +235,27 @@ }, { "gfx_filename": "bonus_trap", - "mwidth":6, - "mheight":4, - "oam":true, + "mwidth": 6, + "mheight": 4, + "oam": true, "palette": "../ruby/ruby_board_palset_0.gbapal", "palbank": 1 }, { "gfx_filename": "pokeball_regular", - "mwidth":2 + "mwidth": 2 }, { "gfx_filename": "pokeball_great", - "mwidth":2 + "mwidth": 2 }, { "gfx_filename": "pokeball_ultra", - "mwidth":2 + "mwidth": 2 }, { "gfx_filename": "pokeball_master", - "mwidth":2 + "mwidth": 2 }, { "gfx_filename": "ball_open_to_catch", @@ -345,6 +345,47 @@ "gfx_filename": "catch_tile_burst_stage3", "palette": "catch_tile_burst_stage3.gbapal", "palbank": 0 + }, + { + "gfx_filename": "capture_screen", + "segments": [ + { + "segfile": "capture_screen_float_mon", + "width": 6, + "palette": "bonus_stage_obj.gbapal", + "palbank": 5 + }, + { + "segfile": "capture_screen_capture_ball_slot_0", + "width": 4, + "palette": "../ruby/ruby_board_palset_0.gbapal", + "palbank": 1 + }, + { + "segfile": "capture_screen_unreferenced_gap", + "width": 17, + "palette": "../ruby/ruby_board_palset_0.gbapal", + "palbank": 1 + }, + { + "segfile": "capture_screen_capture_ball_slot_1", + "width": 4, + "palette": "../ruby/ruby_board_palset_0.gbapal", + "palbank": 1 + }, + { + "segfile": "capture_screen_absorb_fx", + "width": 4, + "palette": "../ruby/ruby_board_palset_0.gbapal", + "palbank": 1 + }, + { + "segfile": "capture_screen_unused_tail", + "width": 2, + "palette": "../ruby/ruby_board_palset_0.gbapal", + "palbank": 1 + } + ] } ] } diff --git a/tools/scripts/objpalette.py b/tools/scripts/objpalette.py index 42cb7273..a24443b2 100644 --- a/tools/scripts/objpalette.py +++ b/tools/scripts/objpalette.py @@ -211,6 +211,7 @@ SLOTS = { ('graphics/stage/ruby', 'travel_paint'): ('ruby', 704, 192, 'main_board_launcher_and_cutscenes.c'), ('graphics/stage/sapphire', 'travel_paint'): ('sapphire', 704, 192, 'main_board_launcher_and_cutscenes.c'), ('graphics/stage/main', 'ball_save'): ('ruby', 704, 288, 'all_board_mode_change_and_debug_menu.c'), + ('graphics/stage/main', 'capture_screen'): ('ruby', 704, 225, 'main_board_center_capture_hole.c'), ('graphics/stage/main', 'end_of_ball'): ('ruby', 704, 320, 'all_board_mode_change_and_debug_menu.c'), ('graphics/stage/main', 'game_over_text'): ('ruby', 704, 32, 'all_board_mode_change_and_debug_menu.c'), ('graphics/stage/main', 'area_roulette_selected_fx'): ('ruby', 704, 20, 'main_board_intro_mode.c'), @@ -327,6 +328,20 @@ OVERRIDES = { # do not draw this art. Every gGroudon* entry landing in 704..959 names bank # 12 and nothing else, so that is the sheet's palette throughout; these are # the segments where a foreign set outvoted it. + # The capture cutscene shares the 704 slot with the banner sheets, which + # outvote it below the float-up fx. Everything from t123 on is the ball and + # its absorb fx: gMonCatchBallAbsorbPokemonFxSpriteSet names bank 1 + # throughout, and gCaptureBallTilesGfx streams the ball itself into t102..105 + # and t123..126, drawn with gBallPalettes in bank 1. + ('ruby', 'capture_screen', 'capture_screen_capture_ball_slot_0'): + (1, 'gCaptureBallTilesGfx slot, drawn with gBallPalettes'), + ('ruby', 'capture_screen', 'capture_screen_unreferenced_gap'): + (1, 'unreferenced, sits between the two ball slots'), + ('ruby', 'capture_screen', 'capture_screen_absorb_fx'): + (1, 'gMonCatchBallAbsorbPokemonFxSpriteSet; a banner sheet outvoted it'), + ('ruby', 'capture_screen', 'capture_screen_unused_tail'): + (1, 'past the end of the copy, matches the absorb fx'), + ('groudon', 'board_fx', 'board_fx_projectile_spawn'): (12, 'foreign set in the 704 slot outvoted bank 12'), ('groudon', 'board_fx', 'board_fx_projectile_impact'): (12, 'foreign set in the 704 slot outvoted bank 12'), ('groudon', 'board_fx', 'board_fx_projectile_debris'): (12, 'foreign set in the 704 slot outvoted bank 12'),