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
@@ -0,0 +1,108 @@
|
||||
import { NUM_POKEMON } from "../rom/profile";
|
||||
import { NICKNAME_PATTERN, PARTY_LENGTH, type PartyMon } from "./pokemon";
|
||||
|
||||
/** NUM_HOF_TEAMS: the teams sHallOfFame keeps; HOF_MASTER_COUNT: where
|
||||
* wHallOfFameCount stops (constants/misc_constants.asm). */
|
||||
export const NUM_HOF_TEAMS = 30;
|
||||
export const HOF_MASTER_COUNT = 200;
|
||||
|
||||
/** HOF_MON_LENGTH: only the fields GetHallOfFameParty copies. */
|
||||
export interface HallOfFameMon {
|
||||
species: number;
|
||||
otId: number;
|
||||
dvs: number;
|
||||
level: number;
|
||||
nickname: string;
|
||||
}
|
||||
/** One sHallOfFame entry (HOF_LENGTH): the win it records and the team
|
||||
* that won, without its Eggs. */
|
||||
export interface HallOfFameTeam {
|
||||
/** wHallOfFameCount when the team entered, capped at HOF_MASTER_COUNT. */
|
||||
win: number;
|
||||
mons: HallOfFameMon[];
|
||||
}
|
||||
export interface HallOfFameRecords {
|
||||
/** wHallOfFameCount: the League wins, up to HOF_MASTER_COUNT. */
|
||||
hallOfFameCount: number;
|
||||
/** sHallOfFame, newest first. Separate from STATUSFLAGS_HALL_OF_FAME_F. */
|
||||
hallOfFameTeams: HallOfFameTeam[];
|
||||
}
|
||||
|
||||
/** GetHallOfFameParty: skip Eggs, copy the six recorded fields, and keep
|
||||
* party order. An all-Egg party produces an empty team. */
|
||||
export function getHallOfFameParty(
|
||||
party: readonly PartyMon[],
|
||||
win: number,
|
||||
): HallOfFameTeam {
|
||||
return {
|
||||
win,
|
||||
mons: party
|
||||
.filter((mon) => !mon.egg)
|
||||
.map(({ species, otId, dvs, level, nickname }) => ({
|
||||
species,
|
||||
otId,
|
||||
dvs,
|
||||
level,
|
||||
nickname,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
/** HallOfFame's capped count increment, then AddHallOfFameEntry: the
|
||||
* newest team goes first and the oldest of a full sHallOfFame drops off.
|
||||
* The League's ceremony is not ported, so nothing calls this yet; it
|
||||
* leaves STATUSFLAGS_HALL_OF_FAME_F (`hallOfFame`) to its caller. */
|
||||
export function addHallOfFameEntry(
|
||||
records: HallOfFameRecords,
|
||||
party: readonly PartyMon[],
|
||||
) {
|
||||
records.hallOfFameCount = Math.min(
|
||||
HOF_MASTER_COUNT,
|
||||
records.hallOfFameCount + 1,
|
||||
);
|
||||
records.hallOfFameTeams.unshift(
|
||||
getHallOfFameParty(party, records.hallOfFameCount),
|
||||
);
|
||||
records.hallOfFameTeams.length = Math.min(
|
||||
NUM_HOF_TEAMS,
|
||||
records.hallOfFameTeams.length,
|
||||
);
|
||||
}
|
||||
|
||||
/** Structural records validation; no stats, party ownership or current
|
||||
* species are required of a historical entry. */
|
||||
export function validHallOfFame(
|
||||
count: unknown,
|
||||
value: unknown,
|
||||
): value is HallOfFameTeam[] {
|
||||
const integer = (n: unknown, min: number, max: number): n is number =>
|
||||
Number.isInteger(n) && Number(n) >= min && Number(n) <= max;
|
||||
if (
|
||||
!integer(count, 0, HOF_MASTER_COUNT) ||
|
||||
!Array.isArray(value) ||
|
||||
value.length > NUM_HOF_TEAMS
|
||||
)
|
||||
return false;
|
||||
if ((count === 0) !== (value.length === 0) || value.length > count)
|
||||
return false;
|
||||
return value.every(
|
||||
(team, index) =>
|
||||
team !== null &&
|
||||
typeof team === "object" &&
|
||||
integer(team.win, 1, count) &&
|
||||
(index === 0 ? team.win === count : team.win <= value[index - 1].win) &&
|
||||
Array.isArray(team.mons) &&
|
||||
team.mons.length <= PARTY_LENGTH &&
|
||||
team.mons.every(
|
||||
(mon: HallOfFameMon) =>
|
||||
mon !== null &&
|
||||
typeof mon === "object" &&
|
||||
integer(mon.species, 1, NUM_POKEMON) &&
|
||||
integer(mon.otId, 0, 65535) &&
|
||||
integer(mon.dvs, 0, 65535) &&
|
||||
integer(mon.level, 1, 100) &&
|
||||
typeof mon.nickname === "string" &&
|
||||
NICKNAME_PATTERN.test(mon.nickname),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user