Port the Pokédex list, entries and tab (#35)
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:
1 parent
03aa913a94
commit
cdee576818
20 files changed
+1624
-29
No files matched your search
+63
-7
@@ -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() {
|
||||
|
||||
Reference in new issue
Block a user