Port the Pokédex list, entries and tab (#35)
Checks / web (push) Failing after 21s
Private ROM checks / private-rom (push) Failing after 14m27s

The start menu's POKéDEX runs Pokedex in New mode: the list up to the
last seen Pokémon, its cursor and page moves, and DisplayDexEntry with
the category, number, footprint, and the height, weight and pages once
caught. The Pokédex tab shows the same records from the loaded game.
Order, entries and footprints are compared with the pinned PRET source.

AREA, CRY, PRNT, the option and search screens, Old and A to Z modes
and Unown mode remain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
samyandClaude Opus 5.5 committed 2026-10-03 20:19:24 +02:00
1 parent 03aa913a94
commit cdee576818
20 files changed
+1624 -29

No files matched your search

+63 -7
View File
@@ -5,6 +5,8 @@ import {
} from "./game/rendering/trainer-card";
import "./ui/styles.css";
import { renderShell } from "./ui/shell";
import { renderPokedexScreen, renderPokedexTab } from "./ui/pokedex";
import { ENGINE_FLAGS } from "./game/rom/profile";
import { bindTabs } from "./ui/tabs";
import { NativeRuntime } from "./game/runtime";
import { LocalMapView } from "./game/rendering/minimap";
@@ -61,6 +63,7 @@ function showWorld(world: GameWorld) {
showMail(world);
showPokegear(world);
showTrainerCard(world);
showPokedex(world);
showOptions(world);
showFlyMap(world);
get("town-map-view").hidden = !world.townMap;
@@ -79,6 +82,7 @@ function showWorld(world: GameWorld) {
// The Pokégear's map and radio cards have no textbox.
(dialogue.choice?.kind === "pokegear" && !dialogue.pages[dialogue.index]) ||
dialogue.choice?.kind === "trainercard" ||
dialogue.choice?.kind === "pokedex" ||
dialogue.choice?.kind === "options" ||
dialogue.choice?.kind === "flymap" ||
Boolean(mart) ||
@@ -138,11 +142,12 @@ function showChoice(choice: Choice | undefined) {
else if (
choice.kind === "pokegear" ||
choice.kind === "trainercard" ||
choice.kind === "pokedex" ||
choice.kind === "options" ||
choice.kind === "flymap"
) {
// The Pokégear, the trainer card, the options and the Fly map read
// the controls directly.
// The Pokégear, the trainer card, the Pokédex, the options and the
// Fly map read the controls directly.
container.replaceChildren();
container.hidden = true;
} else if (choice.kind === "yesno")
@@ -1078,6 +1083,50 @@ function showPokegear(world: GameWorld) {
} else body.replaceChildren();
}
let pokedexKey = "";
/** Pokedex: the main list or an entry, from the world's current view. */
function showPokedex(world: GameWorld) {
const choice = world.dialogue?.choice;
const view = choice?.kind === "pokedex" ? choice.view : undefined;
const panel = get("pokedex-screen");
panel.hidden = !view;
if (!view) {
pokedexKey = "";
return;
}
const key = JSON.stringify(view);
if (key === pokedexKey) return;
pokedexKey = key;
renderPokedexScreen(panel, view, world.assets);
}
let pokedexTabKey = "";
let pokedexTabSelection: number | undefined;
/** The Pokédex tab, from the loaded game's committed or draft state. */
function showPokedexTab() {
if (tabs.active() !== "pokedex") return;
const world = ready() ? runtime.world : undefined;
const state = world?.liveState;
const progress = state && {
owned: state.flags.has(ENGINE_FLAGS.pokedex),
seen: state.pokedex.seen,
caught: state.pokedex.caught,
};
const key = JSON.stringify([
Boolean(world),
progress && [progress.owned, [...progress.seen], [...progress.caught]],
pokedexTabSelection,
]);
if (key === pokedexTabKey) return;
pokedexTabKey = key;
renderPokedexTab(get("panel-pokedex"), world?.assets, progress, pokedexTabSelection, (species) => {
pokedexTabSelection = species;
showPokedexTab();
// On narrow screens the entry sits below the list.
get("panel-pokedex").querySelector(".pokedex-tab-entry")?.scrollIntoView({ block: "nearest" });
});
}
let optionsKey = "";
/** _Option's screen: each option with its setting, and the ▶ cursor. */
function showOptions(world: GameWorld) {
@@ -1454,11 +1503,17 @@ const controls = bindControls(
() => {},
);
const ready = () => ["paused", "playing"].includes(session.state);
const tabs = bindTabs(root, () => {
pause();
controls.release();
update();
});
const tabs = bindTabs(
root,
() => {
pause();
controls.release();
update();
},
(id) => {
if (id === "pokedex") showPokedexTab();
},
);
function showError(error: unknown) {
status.textContent =
@@ -1498,6 +1553,7 @@ function update() {
get("rom-label").classList.toggle("disabled", busy);
get<HTMLButtonElement>("dialogue-next").disabled =
busy || session.state !== "playing";
showPokedexTab();
}
async function save() {