Breed at the Day-Care, hatch Eggs, draw MAIL stationery and browse the Hall of Fame (Closes #29)
- Day-Care and breeding: deposits, withdrawal pricing and growth, compatibility, egg species, DVs and moves, DayCareStep, egg collection and the Odd Egg, compared with the cartridge's routines. - CountStep: walking happiness, DoEggStep, DayCareStep and DoBikeStep in the original's order; HatchEggs with the ROM's hatch animation, compared frame by frame with the original. - MAIL: all ten stationery types and the Portrait MAIL picture, compared with the cartridge's tilemaps, graphics and palettes. - Printing: Bill's PC boxes, Pokedex PRNT, MAIL and the Photo Studio take the original's absent-printer path. - Hall of Fame records (saved apart from the League flag, ready for the League to call) and the Hall of Fame PC, compared with the cartridge's _HallOfFamePC on 255 pages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7d03f5c5ca
commit
e49bc6de9a
49 files changed
+6028
-88
No files matched your search
+16
-1
@@ -5,6 +5,7 @@ import {
|
||||
MAP_GROUP_COUNT,
|
||||
NATIVE_MAPS,
|
||||
NUM_ENGINE_FLAGS,
|
||||
NUM_POKEMON,
|
||||
NUM_SPRITEMOVEDATA,
|
||||
OVERWORLD,
|
||||
PHONE,
|
||||
@@ -24,6 +25,10 @@ import type {
|
||||
FacingTile,
|
||||
} from "../world/types";
|
||||
|
||||
/** Sprite ids above the one-byte range ask for a Pokémon's overworld icon by
|
||||
* species (MON_SPRITE_ID + species). */
|
||||
export const MON_SPRITE_ID = 0x100;
|
||||
|
||||
/** The only layer that knows where Crystal stores its data. Everything is
|
||||
* decoded from the supplied ROM, on demand, and cached only in memory. */
|
||||
export class CrystalAssets {
|
||||
@@ -566,11 +571,21 @@ export class CrystalAssets {
|
||||
}
|
||||
/** GetSprite: overworld sprites, and Pokémon drawn from their party
|
||||
* menu icons (GetMonSprite). Variable sprites are resolved by the world
|
||||
* from wVariableSprites first; day-care Pokémon are not ported. */
|
||||
* from wVariableSprites first. A Day-Care Pokémon (SPRITE_DAY_CARE_MON_1
|
||||
* and 2, which GetMonSprite resolves to wBreedMon1/2's species) is
|
||||
* asked for as MON_SPRITE_ID + its species, as LoadOverworldMonIcon
|
||||
* draws it. */
|
||||
sprite(id: number): Sprite | undefined {
|
||||
const cached = this.sprites.get(id);
|
||||
if (cached) return cached;
|
||||
const r = this.reader;
|
||||
if (id > MON_SPRITE_ID) {
|
||||
const species = id - MON_SPRITE_ID;
|
||||
if (species > NUM_POKEMON) return undefined;
|
||||
const sprite = { graphics: this.monIcon(species), palette: 0, walking: true };
|
||||
this.sprites.set(id, sprite);
|
||||
return sprite;
|
||||
}
|
||||
if (id >= OW.SPRITE_POKEMON && id < OW.SPRITE_POKEMON + OW.NUM_POKEMON_SPRITES) {
|
||||
// LoadOverworldMonIcon: eight tiles, two frames in the down and up
|
||||
// standing slots, with palette 0.
|
||||
|
||||
@@ -43,6 +43,8 @@ export function fontTiles(reader: RomReader, frame: number) {
|
||||
* (constants/charmap.asm). */
|
||||
const CODES: Record<string, number> = {
|
||||
" ": 0x7f,
|
||||
"“": 0x72,
|
||||
"”": 0x73,
|
||||
"(": 0x9a,
|
||||
")": 0x9b,
|
||||
":": 0x9c,
|
||||
|
||||
+26
-2
@@ -359,6 +359,30 @@ export class PokemonData {
|
||||
return evolutions;
|
||||
}
|
||||
|
||||
/** GetPreEvolution: the first species (in dex order) with an evolution
|
||||
* into this one, or the species itself. */
|
||||
preEvolution(species: number): number {
|
||||
this.checkSpecies(species);
|
||||
for (let from = 1; from <= NUM_POKEMON; from++)
|
||||
if (this.evolutions(from).some((evolution) => evolution.species === species))
|
||||
return from;
|
||||
return species;
|
||||
}
|
||||
|
||||
/** EggMovePointers' list for a species (data/pokemon/egg_moves.asm), up
|
||||
* to its -1 terminator; the shared NoEggMoves list is empty. */
|
||||
eggMoves(species: number): number[] {
|
||||
this.checkSpecies(species);
|
||||
const r = this.reader,
|
||||
table = JOHTO.EggMovePointers + (species - 1) * 2;
|
||||
const moves: number[] = [];
|
||||
for (let p = r.near(table, r.bank(table)); r.byte(p) !== 0xff; p++) {
|
||||
if (moves.length > 16) throw new Error("Invalid egg moves.");
|
||||
moves.push(r.byte(p));
|
||||
}
|
||||
return moves;
|
||||
}
|
||||
|
||||
/** Level-up moves (data/pokemon/evos_attacks.asm). Like FillMoves, the
|
||||
* evolution list is skipped up to its terminating zero byte. */
|
||||
learnset(species: number): { level: number; move: number }[] {
|
||||
@@ -439,8 +463,8 @@ export class PokemonData {
|
||||
padded.set(tiles.slice(column * 80, (column + 1) * 80), ((column + 1) * 7 + 2) * 16);
|
||||
return padded;
|
||||
}
|
||||
eggPalette(): Palette {
|
||||
return this.middleColors(SYMBOLS.pokemonPalettes + 0xfd * 8);
|
||||
eggPalette(shiny = false): Palette {
|
||||
return this.middleColors(SYMBOLS.pokemonPalettes + 0xfd * 8 + (shiny ? 4 : 0));
|
||||
}
|
||||
/** Front picture tiles, padded into the 7x7 box as PadFrontpic does:
|
||||
* column-major, bottom-aligned, with a blank left column for 5 and 6. */
|
||||
|
||||
@@ -202,6 +202,8 @@ export const EVENTS = {
|
||||
bugCatchingContestant8A: 1821,
|
||||
bugCatchingContestant9A: 1822,
|
||||
bugCatchingContestant10A: 1823,
|
||||
/** HatchEggs sets this when a Togepi hatches. */
|
||||
togepiHatched: 84,
|
||||
} as const;
|
||||
|
||||
/** Engine flag indices named directly by translated routines. */
|
||||
@@ -209,10 +211,14 @@ export const ENGINE_FLAGS = {
|
||||
pokegear: 4,
|
||||
pokedex: 11,
|
||||
allFruitTrees: 84,
|
||||
bikeShopCall: 20,
|
||||
/** STATUSFLAGS2_BUG_CONTEST_TIMER_F is the same WRAM bit. */
|
||||
bugContestTimer: 17,
|
||||
rocketsInRadioTower: 19,
|
||||
rocketsInMahogany: 23,
|
||||
dayCareManHasEgg: 5,
|
||||
dayCareManHasMon: 6,
|
||||
dayCareLadyHasMon: 7,
|
||||
expnCard: 3,
|
||||
rocketSignal: 14,
|
||||
fishSwarm: 82,
|
||||
@@ -1211,9 +1217,23 @@ export const AUDIO = {
|
||||
PokemonCries: 0xf2787,
|
||||
} as const;
|
||||
|
||||
/** Egg hatching (engine/pokemon/breeding.asm and the sprite animations it
|
||||
* uses), keyed by PRET labels for `npm run check:reference`. */
|
||||
export const EGGS = {
|
||||
Text_BreedHuh: 0x1c0db0,
|
||||
_BreedClearboxText: 0x1c0db8,
|
||||
_BreedEggHatchText: 0x1c0dba,
|
||||
_BreedAskNicknameText: 0x1c0dd8,
|
||||
EggHatchGFX: 0x17393,
|
||||
"Hatch_InitShellFragments.SpriteData": 0x173ef,
|
||||
BattleObjectPals: 0x979c,
|
||||
} as const;
|
||||
|
||||
/** Johto's scripts, routines and tables from Route 32 on, keyed by their
|
||||
* PRET labels for `npm run check:reference`. */
|
||||
export const JOHTO = {
|
||||
"_HallOfFamePC.TimeFamer": 0x8670c,
|
||||
FontBattleExtra: 0xf8600,
|
||||
CheckMagikarpLength: 0xfbb32,
|
||||
MagikarpHouseSign: 0xfbcd2,
|
||||
FindPartyMonThatSpecies: 0xc276,
|
||||
@@ -1270,6 +1290,30 @@ export const JOHTO = {
|
||||
"PokeSeer": 0x4f0bc,
|
||||
"PhotoStudio": 0x16dc7,
|
||||
"PlaySlowCry": 0xfb841,
|
||||
DayCareMan: 0x166d6,
|
||||
DayCareLady: 0x1672a,
|
||||
DayCareManOutside: 0x16936,
|
||||
DayCareMon1: 0x17421,
|
||||
DayCareMon2: 0x17440,
|
||||
GiveOddEgg: 0x117656,
|
||||
"PrintDayCareText.TextTable": 0x168aa,
|
||||
"DayCareManOutside.NotYetText": 0x16944,
|
||||
"DayCareManOutside.FoundAnEggText": 0x16993,
|
||||
"DayCareManOutside.ReceivedEggText": 0x16998,
|
||||
"DayCareManOutside.TakeGoodCareOfEggText": 0x1699d,
|
||||
"DayCareManOutside.IllKeepItThanksText": 0x169a2,
|
||||
"DayCareManOutside.NoRoomForEggText": 0x169a7,
|
||||
LeftWithDayCareLadyText: 0x17462,
|
||||
LeftWithDayCareManText: 0x17467,
|
||||
"DayCareMonCompatibilityText.BreedBrimmingWithEnergyText": 0x1749c,
|
||||
"DayCareMonCompatibilityText.BreedNoInterestText": 0x174a1,
|
||||
"DayCareMonCompatibilityText.BreedAppearsToCareForText": 0x174a6,
|
||||
"DayCareMonCompatibilityText.BreedFriendlyText": 0x174ab,
|
||||
"DayCareMonCompatibilityText.BreedShowsInterestText": 0x174b0,
|
||||
EggMovePointers: 0x23b11,
|
||||
OddEggProbabilities: 0x1fb552,
|
||||
OddEggs: 0x1fb56e,
|
||||
"_GiveOddEgg.Odd": 0x1fb546,
|
||||
"SpecialShuckleOT": 0x7370,
|
||||
"SpecialShuckleNickname": 0x7376,
|
||||
"SeerSeeAllText": 0x4f28c,
|
||||
@@ -1518,6 +1562,8 @@ export const WRAM = {
|
||||
wMagikarpRecordHoldersName: 0xdfea,
|
||||
wcd49: 0xcd49,
|
||||
wNrOfBeatenBattleTowerTrainers: 0xcf64,
|
||||
wBreedMon1Nickname: 0xdef6,
|
||||
wBreedMon2Nickname: 0xdf2f,
|
||||
} as const;
|
||||
|
||||
export const MAP_GROUP_COUNT = 26;
|
||||
@@ -1743,3 +1789,45 @@ export const NATIVE_MAPS: Record<string, string> = {
|
||||
"3:16": "National Park (Bug-Catching Contest)",
|
||||
};
|
||||
export const INITIAL_POSITION = { map: "24:7", x: 3, y: 3 } as const;
|
||||
|
||||
/** ReadAnyMail stationery graphics and palettes. */
|
||||
export const MAIL = {
|
||||
"MorphMailDividerGFX": 0xb9926,
|
||||
"BlueSkyMailGrassGFX": 0xb992e,
|
||||
"PortraitMailSmallPokeballGFX": 0xb9936,
|
||||
"MorphMailBorderGFX": 0xb993e,
|
||||
"MusicMailSmallNoteGFX": 0xb9946,
|
||||
"SurfMailWaveGFX": 0xb994e,
|
||||
"PortraitMailUnderlineGFX": 0xb995e,
|
||||
"LovelyMailUnderlineGFX": 0xb9966,
|
||||
"LovelyMailSmallHeartGFX": 0xb996e,
|
||||
"SurfLiteBlueMailSmallShapesGFX": 0xb9976,
|
||||
"EonMailBorder1GFX": 0xb997e,
|
||||
"EonMailBorder2GFX": 0xb998e,
|
||||
"MailNatuGFX": 0xb9996,
|
||||
"MailDratiniGFX": 0xb99c6,
|
||||
"MailPoliwagGFX": 0xb99f6,
|
||||
"MailLaprasGFX": 0xb9a26,
|
||||
"MailEeveeGFX": 0xb9a56,
|
||||
"MailDittoGFX": 0xb9a86,
|
||||
"MailMewGFX": 0xb9ab6,
|
||||
"MailDragoniteAndSentretGFX": 0xb9b46,
|
||||
"PortraitMailLargePokeballGFX": 0xb9bfe,
|
||||
"MailOddishGFX": 0xb9c1e,
|
||||
"SurfLiteBlueMailLargeShapesGFX": 0xb9c3e,
|
||||
"LovelyMailLargeHeartGFX": 0xb9c5e,
|
||||
"MorphMailBorderCornerGFX": 0xb9c7e,
|
||||
"MailLargeCircleGFX": 0xb9c9e,
|
||||
"FlowerMailFlowerGFX": 0xb9cbe,
|
||||
"MusicMailLargeNoteGFX": 0xb9cfe,
|
||||
"MailCloudGFX": 0xb9d16,
|
||||
"SurfMailBorderGFX": 0xb9d46,
|
||||
"FlowerMailBorderGFX": 0xb9d86,
|
||||
"LiteBlueMailBorderGFX": 0xb9dc6,
|
||||
"MusicMailBorderGFX": 0xb9e06,
|
||||
"LovelyMailBorderGFX": 0xb9e26,
|
||||
"PortraitMailBorderGFX": 0xb9e4e,
|
||||
"MailGFXPointers": 0xb92f8,
|
||||
"LoadMailPalettes.MailPals": 0x8d05,
|
||||
"StandardEnglishFont": 0x1de5e6,
|
||||
} as const;
|
||||
Reference in new issue
Block a user