Files
Crystal/src/game/scripts/fish.ts
T
Sébastien QUEROLandClaude Opus 5.5 397dcef44c 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>
2026-10-03 00:49:35 +02:00

46 lines
1.6 KiB
TypeScript

import type { RomReader } from "../rom/reader";
import { OVERWORLD } from "../rom/profile";
/** The fishing rods' encounters (engine/events/fish.asm and
* data/wild/fish.asm). */
export interface FishMon {
species: number;
level: number;
}
/** FISHGROUP_DATA_LENGTH: the bite chance, then a table per rod. */
const FISHGROUP_DATA_LENGTH = 7;
/** NITE_F: TimeFishGroups' second species from the night on. */
const NITE_F = 2;
/** Fish: rod 0 (Old), 1 (Good) or 2 (Super) in FishGroups entry `group`
* (FISHGROUP_*, never FISHGROUP_NONE). A bite when Random falls below the
* group's chance, then the first entry whose chance a second Random does
* not exceed; species 0 picks the time of day's TimeFishGroups entry.
* Undefined when nothing bites. GetFishGroupIndex's swarm groups need
* DAILYFLAGS1_FISH_SWARM_F and wFishingSwarmFlag, which only trainer calls
* set; they are not ported, so the map's own group is used. */
export function fish(
r: RomReader,
group: number,
rod: number,
timeOfDay: number,
random: () => number,
): FishMon | undefined {
const entry = OVERWORLD.FishGroups + (group - 1) * FISHGROUP_DATA_LENGTH;
if (random() >= r.byte(entry)) return undefined;
let p = r.near(entry + 1 + rod * 2, r.bank(entry));
const roll = random();
while (roll > r.byte(p)) p += 3;
let species = r.byte(p + 1),
level = r.byte(p + 2);
if (!species) {
// .TimeEncounter: the level byte indexes TimeFishGroups.
const time =
OVERWORLD.TimeFishGroups + level * 4 + (timeOfDay >= NITE_F ? 2 : 0);
species = r.byte(time);
level = r.byte(time + 1);
}
return { species, level };
}