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:
Sébastien QUEROLandClaude Opus 5.5 committed 2026-10-03 00:49:35 +02:00
1 parent 4cb4676c7d
commit 397dcef44c
20 files changed
+681 -47

No files matched your search

+38 -14
View File
@@ -12,7 +12,8 @@ import { generatePartyMon } from "../src/game/party/pokemon";
* the Storm Badge, and New Bark Town and Cherrygrove City visited.
* "headbutt" faces Route 29's first reachable Headbutt tree from below
* with a Pokémon that knows Headbutt; Random always returning 0 drops a
* sleeping Hoothoot. */
* sleeping Hoothoot. "fishing" faces the sea on New Bark Town's shore
* with the Old Rod, which then hooks a Magikarp. */
export function foundationFixture(
assets: CrystalAssets,
room:
@@ -23,7 +24,8 @@ export function foundationFixture(
| "pokegear"
| "mom"
| "fly"
| "headbutt",
| "headbutt"
| "fishing",
) {
const world = new GameWorld(
assets,
@@ -45,7 +47,8 @@ export function foundationFixture(
}),
);
world.state.bag.items = [{ item: 18, quantity: 5 }]; // POTION
if (room === "candy") world.state.bag.items.push({ item: 0x20, quantity: 1 });
if (room === "candy")
world.state.bag.items.push({ item: 0x20, quantity: 1 });
}
if (room === "pokegear" || room === "mom") {
world.state.party = [
@@ -80,10 +83,26 @@ export function foundationFixture(
mon.pp = [15, 0, 0, 0];
world.state.party = [mon];
world.state.flags.add(OW.ENGINE_STORMBADGE);
for (const spawn of [14, 15]) // SPAWN_NEW_BARK, SPAWN_CHERRYGROVE
for (const spawn of [14, 15])
// SPAWN_NEW_BARK, SPAWN_CHERRYGROVE
world.state.flags.add(assets.spawnEngineFlag(spawn)!);
for (let event = 0; event < 8; event++) world.state.events.delete(event);
}
if (room === "fishing") {
world.state.party = [
generatePartyMon(assets.pokemon, {
species: 155,
level: 8,
item: 0,
otId: world.playerId,
ot: "CHRIS",
dvs: 0x9abc,
caughtData: 0,
}),
];
world.state.bag.keyItems.push(0x3a); // OLD_ROD
for (let event = 0; event < 8; event++) world.state.events.delete(event);
}
if (room === "headbutt") {
const mon = generatePartyMon(assets.pokemon, {
species: 158, // TOTODILE
@@ -111,21 +130,26 @@ export function foundationFixture(
const [map, x, y] =
room === "headbutt"
? headbuttSpot(assets)
: room === "center" || room === "candy"
? ["26:5", 9, 2]
: room === "poster"
? ["24:7", 6, 1]
: room === "mom"
? ["24:6", 7, 3]
: room && room !== "pokegear" && room !== "fly"
? ["24:7", 2, 2]
: ["24:4", 9, 6];
: room === "fishing"
? ["24:4", 17, 7]
: room === "center" || room === "candy"
? ["26:5", 9, 2]
: room === "poster"
? ["24:7", 6, 1]
: room === "mom"
? ["24:6", 7, 3]
: room &&
room !== "pokegear" &&
room !== "fly" &&
room !== "fishing"
? ["24:7", 2, 2]
: ["24:4", 9, 6];
world.restore({
...save,
map,
x,
y,
direction: room === "mom" ? "down" : "up",
direction: room === "mom" ? "down" : room === "fishing" ? "right" : "up",
objects: [],
});
return world;