mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-17 11:11:10 +02:00
1fe35335a5
Yellow's IsSurfingPikachuInParty swaps the player's overworld sheet to a Pikachu-on-a-surfboard when the party mon that knows SURF is a Pikachu. The recomp was missing both halves of this: the sheet was never extracted, and the engine had no seam for the swap. Extraction: SurfingPikachuSprite (gfx/sprites/surfing_pikachu.2bpp) loads outside SpriteSheetPointerTable via LoadSurfingPlayerSpriteGraphics2, the same bypass RedBikeSprite uses. Added the symbol to the Yellow manifest and a parallel extract in RomExtractor / build_rom_data / extract/sprites, minting SPRITE_SURFING_PIKACHU. PaletteFX colors it (player OBP palette, same as the bike). Engine: new field.playerSprites.surfPikachu (default SPRITE_SURFING_PIKACHU, guarded so before extraction the ride keeps the Seel). Player.new caches surfPikachuSprite; pose() picks it when surfing and the SURF-mon is a Pikachu. New OverworldState:syncSurfingPikachu derives the flag from partyKnows at every surf-state toggle (mount, dismount, fly, teleport, blackout, forced-surf tile, boot-restore). Runtime-only, re-derived at load so a party change between save and load is honored. Lane B: RFC at docs/rfcs/0001-surfing-pikachu-sprite.md. Backward-compatible — existing mods see no change (surf still defaults to SPRITE_SEEL; surfPikachu only resolves on a Yellow import after regeneration). Parity tests in tests/parity_surfing_pikachu_sprite.lua (12/12) and tests/mod_world_tests.lua (19229/19229 with the new boot-seed checks). tests/parity_cinnabar_east_surf.lua (24/24) unchanged. Regeneration required: re-run make_yellow_manifest.py against a pret/pokeyellow checkout, then re-import the Yellow ROM.
96 lines
3.6 KiB
Markdown
96 lines
3.6 KiB
Markdown
# RFC 0001 — Port Yellow's `IsSurfingPikachuInParty` surf sprite
|
||
|
||
## Status
|
||
|
||
Proposed. Engine: `Player.lua`, `FieldDefaults.lua`,
|
||
`OverworldController.lua`, `RomExtractor.lua`, `PaletteFX.lua`. Tools:
|
||
`build_rom_data.py`, `extract/sprites.py`, `make_rom_manifest.py`,
|
||
`make_yellow_manifest.py`. Tests: `parity_surfing_pikachu_sprite.lua`,
|
||
`mod_world_tests.lua`.
|
||
|
||
**Regeneration required.** The manifest and sprite sheet update by
|
||
re-running `make_yellow_manifest.py` against a `pret/pokeyellow`
|
||
checkout, then re-importing the Yellow ROM.
|
||
|
||
## Motivation
|
||
|
||
Yellow's `IsSurfingPikachuInParty` + `LoadSurfingPlayerSpriteGraphics2`
|
||
(`home/map_objects.asm`, `home/overworld.asm`) swap the player's
|
||
overworld sheet to `SurfingPikachuSprite` (`gfx/sprites/
|
||
surfing_pikachu.2bpp`, a 16×96 walk sheet — not the minigame sheets)
|
||
when the party mon that knows SURF is a Pikachu. The recomp misses this
|
||
in two places:
|
||
|
||
1. **Extraction.** `SurfingPikachuSprite` is not in
|
||
`SpriteSheetPointerTable` — loaded by its own `ld de,` like
|
||
`RedBikeSprite`. The extractor never sees it, and the symbol is not
|
||
in the Yellow manifest.
|
||
2. **Engine rule.** `field.playerSprites.surf` is one static
|
||
(`SPRITE_SEEL`), cached at boot. No seam for "swap when the SURF-mon
|
||
is a Pikachu."
|
||
|
||
## The decision it extends
|
||
|
||
No prior D-number. Extends the surf-field-move port in
|
||
`docs/behavior-porting-notes.md` (the `IsSurfingAllowed` exact port)
|
||
with the player-sprite swap vanilla runs alongside it.
|
||
|
||
## The exact API delta
|
||
|
||
Backward-compatible, additive-only.
|
||
|
||
### `field.playerSprites.surfPikachu`
|
||
|
||
New optional key alongside `walk`/`surf`/`bike`/`fly`, defaults to
|
||
`SPRITE_SURFING_PIKACHU`. Guarded in `Player.new` so before extraction
|
||
lands the ride keeps the Seel — no plain on-water Pikachu.
|
||
|
||
### `Player.surfPikachuSprite`
|
||
|
||
`Player.new` builds a second `SpriteRenderer` when the field resolves.
|
||
`pose()` picks it when `surfing and surfingPikachu`.
|
||
|
||
### `Player.surfingPikachu` (runtime)
|
||
|
||
Runtime-only boolean (not persisted); re-derived so a party change
|
||
between save and load is honored.
|
||
|
||
### `OverworldState:syncSurfingPikachu()`
|
||
|
||
Sets `player.surfingPikachu` from `partyKnows("SURF")`. Called at every
|
||
surf-state toggle: trySurf, dismount, flyTo, beginTeleportOut,
|
||
warpToHealPoint, forced-surf tile, setMap boot-restore.
|
||
|
||
### Importer — `SPRITE_SURFING_PIKACHU`
|
||
|
||
`make_yellow_manifest.py` adds `SurfingPikachuSprite` to
|
||
`YELLOW_EXTRA_SYMBOLS`. `make_rom_manifest.py`'s `sprite_metadata()`
|
||
gains a `surfPikachu` entry (guarded, so Red/Blue unchanged).
|
||
`RomExtractor.extractSprites` + `build_rom_data.py` + `extract/sprites.py`
|
||
each gain a parallel extract mirroring `RedBikeSprite`.
|
||
|
||
### `PaletteFX.spriteObp`
|
||
|
||
`SurfingPikachuSprite` joins `RedBikeSprite` in the no-bracket-index
|
||
special case, wearing the player's OBP palette so it colors in GBC mode.
|
||
|
||
## Migration note for existing mods
|
||
|
||
**Nothing.** `surf` still defaults to `SPRITE_SEEL`; `surfPikachu`
|
||
only resolves on a Yellow import after regeneration. No manifest or
|
||
`mod.save` shape changes. An eligibility hook that swaps a rental
|
||
SURF-mon still drives the sprite pick via `partyKnows`.
|
||
|
||
## Parity tests
|
||
|
||
- **No-mod** (`mod_world_tests.lua`): `surf == "SPRITE_SEEL"`,
|
||
`surfPikachu == "SPRITE_SURFING_PIKACHU"` seeded at boot. The 19229-check
|
||
`world & maps v2` suite stays green.
|
||
- **Mod-API** (`parity_surfing_pikachu_sprite.lua`): `syncSurfingPikachu`
|
||
+ `Player:pose` across four party shapes (12/12). The existing
|
||
`parity_cinnabar_east_surf.lua` (24/24) stays green.
|
||
|
||
## Deprecation etiquette
|
||
|
||
Nothing deprecated. Additive: a new `field.playerSprites` key, a new
|
||
runtime flag, a new engine method, a new sprite id. |