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.
3.6 KiB
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:
- Extraction.
SurfingPikachuSpriteis not inSpriteSheetPointerTable— loaded by its ownld de,likeRedBikeSprite. The extractor never sees it, and the symbol is not in the Yellow manifest. - Engine rule.
field.playerSprites.surfis 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-checkworld & maps v2suite stays green. - Mod-API (
parity_surfing_pikachu_sprite.lua):syncSurfingPikachuPlayer:poseacross four party shapes (12/12). The existingparity_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.