The Gen 3 extractor emitted eggCycles/eggGroups but never egg moves, so the
gen3_dexnav hidden-mon roll was inert on FireRed: a hidden mon kept its
level-up moves and could never gain an egg move.
Decode the ROM's own gEggMoves table (pokefirered/src/data/pokemon/
egg_moves.h) into pokemon/egg_moves.lua and expose it the same way as
learnsets/tmhm:
- Versions: EGG_MOVES = 0x25EF0C plus the 20000 species offset, the 0xFFFF
run terminator and a defensive per-species cap. The table is one flat u16
stream of `{ species + 20000, move..., 0xFFFF }` runs with no final
terminator, so the first word that is neither a header nor a plausible move
id ends the scan.
- PokemonExtract: extract_egg_moves + write_egg_moves_lua, written to the
cache by run(), required by ready() so a stale cache re-extracts, and
returned as pack.eggMoves. FORMAT_VERSION 3 -> 4.
- Pokemon.eggMoves(species): runtime accessor with the same species coercion
as Pokemon.learnset; nil for a species with no egg move.
- Schemas: eggMoves on monTables/monRecord/writeMon and the Gen 3 species
field list, so a mod reads record.eggMoves as move ids and writes names back.
- Versions.CACHE_VERSION 98 -> 99 to force re-extraction.
The table is sparse: species without egg moves are absent rather than an
empty list, all the way from the ROM to the mod record.
Validated against a supported FireRed USA 1.0 dump: 165 species, 973 moves,
<=8 per species, Bulbasaur {113,130,219,204,80,345,320,174}, Mankey
{157,193,96,68,179,251,279,265} (no Toxic), Mew nil.
Tests: new tests/engine/game3_egg_moves.lua (31 checks ROM-free, 39 with a
ROM), gate_gen3_mod_api 734/734, engine tier 587/587, modkit tier 37/37,
lint --gate clean.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>