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 <noreply@anthropic.com>
This commit is contained in:
Cyphgirl
2026-08-08 08:55:30 -04:00
parent 1f66572d05
commit f44fdf5d6f
9 changed files with 161 additions and 97 deletions

View File

@@ -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"

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

View File

@@ -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
}
]
}
]
}

View File

@@ -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'),