The Spirit fish gate
The Spirit is the rarest catch in the fishing minigame, and players have never caught it as often as the published tables say they should: the accepted model (Normal Lure at Buma, a “Good!” bait, 1 in 32) predicts one inside a long session, while hundreds of catches without one are routine. This page reads the species-selection code out of the fishing overlay and shows why - the rare column is not on the dice at all.
At a glance
- Where
- Fishing overlay, PROT entry 0972 (load base
0x801CE818) - Species table
- Per venue, 3 lure rows × 5 band columns; parser
legaia_asset::fishing_species - Saved state
- Lifetime cast counter in the save block - the gate's hidden precondition
- Confidence
- Confirmed - MIPS disassembly, checked against a retail USA disc
- Used by
- Playable fishing demo · curated fishing tables
The spawn tables
When a fish strikes, the hooked-fish handler picks the species with species = spawn_table[lure*8 + band]. The equipped lure picks the row; the current cast band (0–4) picks the column. The species agree cell-for-cell with the community tables - the gap is in how band 4 is reached.
| Buma / lure | band 3 (~75.0%) | band 2 (~15.2%) | band 1 (~4.9%) | band 0 (~4.9%) | band 4 (gated) |
|---|---|---|---|---|---|
| Light | High Charger | High Charger | Jack | Jack | Spikefish† |
| Normal | High Charger | Jack | High Charger | High Charger | Spirit |
| Heavy | Charger | Fly Pie | Lippian | Devourer | Spikefish† |
| Vidna / lure | band 3 | band 2 | band 1 | band 0 | band 4 (gated) |
|---|---|---|---|---|---|
| Light | Jack | Jack | Fly Pie | Jack | Spikefish† |
| Normal | High Charger | Fly Pie | Spikefish | Fly Pie | Spikefish† |
| Heavy | Fly Pie | Fly Pie | Charger | Octoban | Baraba |
† Dead cells. Each venue's band-4 gate hardwires the lure it fires on (Normal at Buma, Heavy at Vidna), so band 4 is only ever read on the row carrying the rare fish. The other Spikefish cells are unreachable in retail play - only a developer shortcut (debug flag + R1 at the strike) forces band 4 unconditionally.
How the band is chosen
Band assignment has two phases. While the lure is in the water, the band is re-derived every frame: a cadence match pins it for a ~64-frame hold window, otherwise the frame's random roll replaces it. At the instant a fish strikes, the venue's gate may upgrade band 0 to band 4. Everything after the strike is deterministic.
The band roll
While the lure sits deep enough (line record over 500 units) and no fish is hooked, the band re-rolls on every frame no cadence holds it: rand() & 0xfff against three fixed cutoffs. The published 184/48/16/8-out-of-256 estimate has the right shape; the real cutoffs sit slightly lower at the rare end. No outcome maps to band 4 - there is no fifth cutoff.
The reel-cadence recogniser
Before each frame's band roll, the game consults a reel-cadence recogniser: a 16-slot ring of {button, held-frames} reel history, walked backwards against four templates, each hold matched with ±10 frames of tolerance. A match does three things:
- fires the “Good!” splash;
- stores the matched template's id as the band;
- arms a ~64-frame countdown during which the band holds instead of re-rolling and the bite roll runs at roughly twenty times its idle rate.
A strike can only land on a frame where a reel button is held, so the final press of the cadence doubles as the bite window.
Performing the band-0 cadence
Setup: cast deep (the cadence check only runs once the line record exceeds 500), then press either reel button briefly and release so the first rest starts from a measurable point. Then:
- Hands off for about two-thirds of a second (0.52–0.82 s accepted).
- Hold ✕ for about 0.4 s (0.27–0.57 s), then release.
- Hands off again for about two-thirds of a second.
- Press and hold □. The splash fires about a tenth of a second into the hold: band 0 is set. Keep holding - the boosted bite lands only while a reel button is down. If nothing bites, release and repeat from step 1.
The hold window is the load-bearing part. A rolled band 0 exists only on the frames the dice produce it; a cadence-set band is pinned for the full window, and the boosted strike usually lands inside it. The four templates:
The band-4 gate at the strike
When a strike lands (reel held, per-frame strike roll passed, nothing hooked yet), one branch immediately before the species lookup decides whether an active band 0 upgrades to band 4. Every condition must hold at once:
| Condition | Buma (Spirit) | Vidna (Baraba) | Visible to the player? |
|---|---|---|---|
| Lifetime casts (saved counter) | > 50 | no threshold | No - lives in the save block, never displayed |
| Cast counter parity | even | even | Only as the lure's drift direction on wall contact |
| Lure | Normal | Heavy | Yes |
| Rod | third rod | third rod | Yes, but no table records it |
| Band active | 0 | 0 | Only via a template-0 “Good!” |
| Final roll | 1 in 16 | 1 in 4 | No |
The cast counter increments once per cast when the lure lands, persists across sessions and is saved with the game - band 4 at Buma is unreachable inside the first 51 lifetime casts. With either other rod equipped the gate short-circuits and band 4 cannot occur.
The gate as code
if (venue == Buma) { // DAT_801d90d0 == 0
if (0x32 < casts // > 50 lifetime casts (_DAT_80084460)
&& (casts & 1) == 0 // cast counter EVEN at this instant
&& lure == 1 // Normal Lure (_DAT_80084450)
&& rod == 2 // third rod (_DAT_80084454)
&& band == 0) // rare band active (DAT_801d90e8)
if ((rand() & 0xf) == 0) // ... then 1 in 16
band = 4; // -> Spirit
} else { // Vidna
if ((casts & 1) == 0 && lure == 2 && rod == 2 && band == 0)
if ((rand() & 3) == 0) // 1 in 4, no cast-count threshold
band = 4; // -> Baraba
}
Rendered from the strike branch of FUN_801d26cc; the species lookup follows directly. The cadence hold countdown is armed to 0x40 and also feeds the strike credit (credit = countdown + 2), which is where the ~20× bite boost comes from.
Effective probabilities
Per-catch Spirit probability at Buma, assuming a deep cast and a landed strike:
| Setup | Per catch | Derivation |
|---|---|---|
| Third rod, Normal Lure, 50+ lifetime casts, template-0 cadence held at the strike | ≈ 1/32 | 1/16 gate roll × ½ counter parity; the cadence pins band 0 and boosts the bite ~20× for its hold window |
| Third rod, Normal Lure, 50+ lifetime casts, no cadence | ≈ 1/660 | 199/4096 band-0 roll × ½ parity × 1/16 gate roll |
| Either other rod, or under 51 lifetime casts | 0 | The gate fails before the random roll |
Under a flat 1/32, 250 catches without a Spirit has probability ~0.04%; under the gated model without cadence input the same drought has probability ~68% - long empty sessions are the expected outcome. Baraba at Vidna has no cast-count threshold and a 1-in-4 roll, matching its far higher observed rate.
Passing the gate selects the species; landing it is a separate problem. The Spirit carries the species table's largest pull factor, so a gated strike can still be lost in the reel.
Player reports, mapped to mechanisms
| Reported behaviour | Mechanism |
|---|---|
| Square presses associated with Spirit catches | Template 0 - the only cadence that sets band 0 - is the only template ending in a Square tap |
| Pond position affects results | Cells flagged 0x4000 in the floor grid raise the strike rate, so the gate is evaluated more often (the species table is unaffected) |
| Cast distance matters | Below 200 line units no strike occurs; below 500 the band never re-rolls and the cadence check never runs |
| “Good!” improves the odds | Any match boosts the bite rate ~20× for ~1 s, but only template 0 sets band 0; the other three set bands 1–3 with the same splash |
| 1/32 with a “Good!” on Normal Lure | The effective rate when rod, cast-counter and cadence conditions all hold; those conditions are not visible |
| Long droughts despite the right lure | Expected under the gated model - and certain with either other rod or under 51 lifetime casts |
How we know
Everything above is read from the MIPS disassembly of the fishing overlay (PROT entry 0972) and checked against a retail USA disc. No Sony-owned bytes appear here - only addresses, offsets and decoded parameters. The full subsystem reference is minigame-fishing.md.
| Function / data | Address | What it proves |
|---|---|---|
| Hooked-fish handler (strike branch + band-4 gate + species lookup) | FUN_801d26cc | The gate conditions, the 1/16 and 1/4 rolls, spawn_table[lure*8 + band] |
| Reel-cadence recogniser | FUN_801d3db4 | Four templates, ±10-frame tolerance, template id stored as band, hold countdown 0x40 |
| Reel-button decode | FUN_801d7450 | Cross = reel A (pad bit 0x40), Square = reel B (0x80) |
| Species table | 0x801D81A4 | Per-species pull factor (Spirit largest) |
| Venue spawn tables | 0x801D8334 / 0x801D8434 | The Buma / Vidna lure × band grids above |
| Cadence templates | 0x801D87D4 | The four button/hold sequences |
| Cast band / venue / cast counter / lure / rod | DAT_801d90e8 / DAT_801d90d0 / _DAT_80084460 / _DAT_80084450 / _DAT_80084454 | The five inputs the gate reads; the cast counter sits in the save block |
| Band-roll cutoffs | 0xc00 / 0xe70 / 0xf38 | 75.0 / 15.2 / 4.9 / 4.9 %, no fifth cutoff |