Port the fishing rods and wild Magikarp
The Old, Good and Super Rods run FishFunction facing water: the map's fish group and Fish pick no fish, no bite, or a Pokémon from FishGroups and the time of day's TimeFishGroups. The player casts and jiggles with the fishing frames drawn from LoadFishingGFX's tiles, shows "!" on a bite, and the hooked Pokémon attacks as BATTLETYPE_FISH. Facing pieces now use signed offsets, which the rod above and left of the player needs. Wild Magikarp no longer stop a battle: LoadEnemyMon redraws their DVs through CalcMagikarpLength and its filters, as the original does. The length routine matches the original in the reference emulator. Part of #27 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4cb4676c7d
commit
397dcef44c
20 files changed
+681
-47
No files matched your search
+29
-3
@@ -32,7 +32,7 @@ These paths refer to the pinned [PRET source](https://github.com/pret/pokecrysta
|
||||
| Movement interpreter | `macros/scripts/movement.asm`, `engine/overworld/movement.asm`, `engine/overworld/map_objects.asm` | Turns, steps, slides, jumps (two tiles with the original arc), sleeps, facing locks, visibility and emotes. `follow` takes one tile toward the leader's previous square. All movement opcodes decode, including teleport, fishing, skyfall, shake and flicker poses; Controlled reference scenes check spin, teleport, skyfall, fishing and flicker direction, visibility and lift. |
|
||||
| Specials | `data/events/special_pointers.asm`, `engine/rtc/timeset.asm`, `engine/overworld/decorations.asm` | Selected by routine address from the ROM table: `SetDayOfWeek`, initial DST flags, `RestartMapMusic` (no audio yet), room decoration toggles, `PokemonCenterPC` and `PlayersHousePC` (Bill's, the player's and Oak's PCs), the Town Map, `HealParty`, `HealMachineAnim` (presentation only), `CheckPokerus` and the `StubbedTrainerRankings_Healings` stub. |
|
||||
| `game/scripts/pc.ts` | `engine/events/pokecenter_pc.asm`, `engine/pokemon/bills_pc_top.asm`, `engine/pokemon/bills_pc.asm`, `engine/events/prof_oaks_pc.asm`, `engine/events/std_collision.asm` | The Pokémon Center and house PCs: Bill's PC (deposit, withdraw, release, change and name boxes, MOVE PKMN W/O MAIL, stats), item storage, the empty mail box and Oak's rating. Menu strings and texts come from the ROM; lists are native. Printing is not ported. |
|
||||
| `game/scripts/start-menu.ts` | `engine/menus/start_menu.asm`, `engine/pokemon/mon_menu.asm`, `mon_submenu.asm`, `party_menu.asm`, `switchpartymons.asm`, `engine/items/pack.asm`, `engine/items/item_effects.asm` | The start menu, the party menu with the Pokémon submenu (STATS, SWITCH, MOVE, ITEM) and the pack (USE, GIVE, TOSS) with the field item effects listed below, including Rare Candy, stones and vitamins. Menu strings, prompts and texts come from the ROM; screens are native. Field moves from the menu (checked by the world), Softboiled and Milk Drink, SEL and the Select button (`SelectMenu`). MAIL and the rods give a notice. |
|
||||
| `game/scripts/start-menu.ts` | `engine/menus/start_menu.asm`, `engine/pokemon/mon_menu.asm`, `mon_submenu.asm`, `party_menu.asm`, `switchpartymons.asm`, `engine/items/pack.asm`, `engine/items/item_effects.asm` | The start menu, the party menu with the Pokémon submenu (STATS, SWITCH, MOVE, ITEM) and the pack (USE, GIVE, TOSS) with the field item effects listed below, including Rare Candy, stones and vitamins. Menu strings, prompts and texts come from the ROM; screens are native. Field moves from the menu (checked by the world), Softboiled and Milk Drink, SEL and the Select button (`SelectMenu`). MAIL gives a notice. |
|
||||
| `game/scripts/pokegear.ts` | `engine/pokegear/pokegear.asm`, `engine/phone/phone.asm`, `engine/phone/scripts/mom.asm`, `elm.asm`, `engine/rtc/print_hours_mins.asm` | `PokeGear` with each card's joypad handling: the clock (`Pokegear_UpdateClock`, `PrintHoursMins`), the map card's landmark cursor (`TownMap_InitCursorAndPlayerIconPositions`, `TownMap_GetKantoLandmarkLimits`), the phone list (`PokegearPhone_UpdateDisplayList`, `GetCallerClassAndName`, `PokegearPhoneContactSubmenu`, `CheckCanDeletePhoneNumber`) and calls (`MakePhoneCallFromPokegear`, `CheckPhoneContactTimeOfDay`, `GetMapPhoneService`, `HangUp`). Callee scripts run in the event interpreter on the start menu's draft. Screens are native; the radio's stations are not ported. |
|
||||
| `game/scripts/trainer-card.ts` | `engine/menus/trainer_card.asm`, `engine/gfx/player_gfx.asm` (`GetCardPic`), `engine/gfx/cgb_layouts.asm` (`_CGB_TrainerCard`), `home/game_time.asm` | `TrainerCard`'s two reachable pages with their joypad rules, strings from `.Name_Money`, `.Dex_PlayTime` and `.Badges`, the caught count, and the badges from `TrainerCard_JohtoBadgesOAM` with their eight-frame steps. `rendering/trainer-card.ts` draws the card picture, leader faces and badges from the ROM with the card's palettes and attribute map. `world/game-time.ts` is `GameTimer` (capped at 999:59:59). Text is native; the blinking colon's and badges' phase start at the page load. |
|
||||
| `game/scripts/options.ts` | `engine/menus/options_menu.asm`, `data/default_options.asm`, `engine/battle/core.asm` (`CheckWhetherToAskSwitch`), `engine/menus/start_menu.asm` | `_Option` with `OptionsControl` and each option's routine on the four option bytes, `DefaultOptions`, and the two settings consumed so far: `BATTLE_SHIFT` and `MENU_ACCOUNT`. Strings come from the ROM; the screen is native. |
|
||||
@@ -325,7 +325,8 @@ event flag), `ItemFinder` (the world's `CheckForHiddenItems` picks the
|
||||
queued script), `_CardKey`, `_BasementKey` (map and facing tile in
|
||||
`wPlayerMapX/Y` coordinates) and `_Squirtbottle`, whose
|
||||
`.CheckCanUseSquirtbottle` asks the world's `GetFacingObject` and leaves the
|
||||
object in `hLastTalked`. Items are used from the
|
||||
object in `hLastTalked`, and the rods (`UseRod`, below). Items are used
|
||||
from the
|
||||
Items pocket slot they were chosen from (`wCurItemQuantity`).
|
||||
`ItemActionTextWaitButton` prints `PrintPartyMenuActionText` with the HP
|
||||
change. `ChangeHappiness` outside battle does not touch a battle Pokémon.
|
||||
@@ -356,6 +357,24 @@ keeps the step's count. `TryWildEncounter`'s `CheckRepelEffect` follows
|
||||
`ChooseWildEncounter`. `text_ram` of `wPlayerName`, `wRivalName` and
|
||||
`wMomsName` reads the text context's names.
|
||||
|
||||
`FishFunction` runs in the world (`.TryFish`'s surf and `WATER_TILE` checks,
|
||||
`GetFishingGroup` from the map header's `MAP_FISHGROUP`) and queues
|
||||
`Script_GotABite`, `Script_NotEvenANibble` or `Script_NotEvenANibble2`;
|
||||
`scripts/fish.ts` is `Fish` over `FishGroups` and `TimeFishGroups`
|
||||
(`GetFishGroupIndex`'s swarm groups need `wFishingSwarmFlag`, which only
|
||||
trainer calls set). The interpreter gained `loademote` (an emote loaded to
|
||||
the bubble's tiles is what `show_emote` shows next), `loadmem hBGMapMode`
|
||||
(ignored), `Fishing_CheckFacingUp`, `PutTheRodAway` (after the pending
|
||||
text) and an accepted `LoadFishingGFX`. `fish_cast_rod` and `fish_got_bite`
|
||||
set the actor's `OBJECT_ACTION_FISHING` until `PutTheRodAway`; the renderer
|
||||
then draws `FACING_FISH_*` from the player's tiles with `FishingGFX` or
|
||||
`KrisFishingGFX` over tiles 2-3, 6-7 and 10-11 and the rod at $fc-$fd,
|
||||
all in VRAM bank 1 like the player's sprite (`.InitSprite` sets
|
||||
`OAM_BANK1` below tile $80). Facing offsets are now read as signed bytes.
|
||||
The battle's `BATTLETYPE_FISH` prints `HookedPokemonAttackedText`.
|
||||
`LoadEnemyMon`'s `.Magikarp` filters and `CalcMagikarpLength` (with its
|
||||
`.BCLessThanDE` high-byte comparison) replace the Magikarp refusal.
|
||||
|
||||
Tests: `tests/field-items.test.ts` (local ROM) uses each Repel, walks with
|
||||
one through a test-only grass table (weaker Pokémon kept away, a fainted
|
||||
lead, an equal level let through, the last step's message and its replay
|
||||
@@ -363,7 +382,14 @@ after a reload), and covers the Coin Case, the Blue Card, Sacred Ash with
|
||||
and without a fainted Pokémon, both boxes, the save migration, the
|
||||
Itemfinder at each edge of the screen around Route 30's hidden Potion,
|
||||
the keys (a start-menu run with the unopened maps' positions) and the
|
||||
Squirtbottle (the interpreter facing a test Sudowoodo on Route 36).
|
||||
Squirtbottle (the interpreter facing a test Sudowoodo on Route 36),
|
||||
`Fish` against the Shore tables, a bite, no bite and no fish in New Bark
|
||||
Town with the poses and the bubble, the surf and water refusals, and the
|
||||
Magikarp DV filters. `tests/reference-parity.spec.ts` compares
|
||||
`magikarpLength` with `CalcMagikarpLength` in the reference emulator over
|
||||
1,509 DV and ID pairs. A Chromium/WebKit test hooks a Magikarp with the
|
||||
Old Rod; the four fishing directions were checked in close-up
|
||||
screenshots, not against the original.
|
||||
|
||||
## Evolution
|
||||
|
||||
|
||||
+3
-1
@@ -169,7 +169,7 @@ The numbered sections below keep their full scope. Each one opens with a checkli
|
||||
- PACK: the Items, Balls, Key and TM pockets (left and right change pockets; there are no TMs or HMs yet), and each item's submenu chosen by its permissions and field menu (`USE`, `GIVE`, `TOSS`, `SEL`, `QUIT`). TOSS asks how many and confirms. USE follows `UseItem`: Oak's warning without a field use, "You don't have a POKéMON!" for party items without one, and `_DoItemEffect` by the item's `ItemEffects` address: Potions and the other `HealingHPAmounts` items, status healers, Full Restore, Revive and Max Revive, the bitter Energypowder, Energy Root, Heal Powder and Revival Herb, Ethers, Elixers, the MysteryBerry and PP Up. The Bicycle closes the menu and runs `Script_GetOnBike` or `Script_GetOffBike` outdoors; elsewhere Oak objects, because `wFieldMoveSucceeded` shares `wItemEffectSucceeded`'s byte.
|
||||
- PP Up keeps a quirk: `wUsePPUp` shares `wTempPP`'s byte, so `ComputeMaxPP` adds one step (a fifth of the base PP, at most 7) to the current PP as well as the maximum. Sketch and moves with three PP Ups are "maxed out".
|
||||
- The menu runs on a script draft, like the PC. Changes commit when it closes; a save made while it is open keeps the state from before it. The start menu cursor, the party menu cursor and the last pocket stay in memory between openings and are cleared after a battle, as `CleanUpBattleRAM` does. The party cursor reaches the next battle's `ChangeHappiness`.
|
||||
- Not ported: MAIL, switching to another party member's moves with left and right, item reordering with Select and the fishing rods (each gives a notice and changes nothing; the Escape Rope runs since the Fly section below, Repels and the other items of the last section since then). Rare Candy, evolution stones and vitamins run since the evolution section below; field moves, SEL and Select since the section after it.
|
||||
- Not ported: MAIL, switching to another party member's moves with left and right, and item reordering with Select (each gives a notice and changes nothing; the Escape Rope runs since the Fly section below, Repels and the other items of the last section since then). Rare Candy, evolution stones and vitamins run since the evolution section below; field moves, SEL and Select since the section after it.
|
||||
|
||||
## Implemented: evolution
|
||||
|
||||
@@ -248,6 +248,8 @@ The numbered sections below keep their full scope. Each one opens with a checkli
|
||||
- The Normal Box and the Gorgeous Box hold the silver and the gold trophy doll (`SetSpecificDecorationFlag`), sent home for the bedroom PC.
|
||||
- The Itemfinder answers "Yes! ITEMFINDER indicates there's an item nearby." when a hidden item not found yet lies on the original's screen around the player (`CheckForHiddenItems`: four squares left and up, five right, four down), and "Nope!" otherwise. Route 30's hidden Potion is the only one on an open map.
|
||||
- The Card Key and the Basement Key run their door scripts only facing the Radio Tower 3F slot or the Goldenrod Underground door (Oak objects elsewhere). The Squirtbottle sprinkles water, and on Route 36 starts the Sudowoodo battle when facing it (`WateredWeirdTreeScript`). None of these maps is open yet.
|
||||
- The Old, Good and Super Rods fish facing water, never while surfing (Oak objects otherwise; the facing tile may hold an object, as in the original). The map header's fish group decides: none gives "Not even a nibble!" at once; otherwise `Fish` bites below 50% + 1 and picks the rod's `FishGroups` entry, with `TimeFishGroups` for the morning and day or the night. The player casts with the fishing frames (`LoadFishingGFX`'s body and rod tiles), jiggles four times on a bite, shows "!", and after "Oh! A bite!" puts the rod away before a `BATTLETYPE_FISH` battle: "The hooked MAGIKARP attacked!". Qwilfish and Remoraid swarms come from trainer calls, which are not ported. New Bark Town, Route 30 and Cherrygrove City have fish.
|
||||
- Wild Magikarp now battle: `LoadEnemyMon` draws their DVs again as the original does, through `CalcMagikarpLength` (compared with the original routine) and its filters, whose millimetre limits only work as a floor of four feet that about 39% of draws skip (39 percent + 1), nowhere in map group 9 or on maps numbered 6 (the Lake of Rage check). Unown are still refused.
|
||||
- Save format 3 gained `repel`, `coins` and `blueCardBalance`, migrated by absence to 0.
|
||||
|
||||
## Native battles: current state
|
||||
|
||||
Reference in new issue
Block a user