Implement native opening scenes, battle foundation and overworld movement
Checks / web (push) Canceled after 0s
Checks / web (push) Canceled after 0s
This commit is contained in:
1 parent
8b80d05ca2
commit
c08d250cf6
39 files changed
+10727
-1524
No files matched your search
+26
-19
@@ -7,7 +7,7 @@ flowchart LR
|
||||
ROM[User ROM] --> Gate[Exact revision validation]
|
||||
Gate --> Assets[ROM reader and asset decoders]
|
||||
Assets --> World[Native world rules]
|
||||
Assets --> Scripts[Native event and text interpreters]
|
||||
Assets --> Scripts[Resumable event, movement and text interpreters]
|
||||
Scripts --> World
|
||||
Input[Touch and keyboard] --> Runtime[Native runtime]
|
||||
Runtime --> World
|
||||
@@ -17,28 +17,35 @@ flowchart LR
|
||||
Reference[Separate reference emulator] -. local comparisons only .-> World
|
||||
```
|
||||
|
||||
| Module | Responsibility |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| `src/rom/validate.ts` | Exact cartridge identity, no networking |
|
||||
| `src/game/rom` | Banked reads, LZ, maps/tilesets/sprites/palettes and pinned addresses |
|
||||
| `src/game/world` | Position, movement, collision, warps, visibility, time selection and native save validation |
|
||||
| `src/game/scripts` | The game's event/text formats, no GB instructions |
|
||||
| `src/game/rendering` | Planar pixels, metatiles, camera and sprites |
|
||||
| `src/game/runtime.ts` | Frame scheduling, input, interpolation and presentation updates |
|
||||
| `src/input` | Abstract buttons, multiple sources and browser bindings |
|
||||
| `src/app` | Runtime-independent load/play/pause/backup lifecycle |
|
||||
| `src/storage` | Versioned envelope, IndexedDB transactions and ordered writes |
|
||||
| `src/ui`, `src/main.ts` | UI composition and DOM dialogue, no ROM offsets |
|
||||
| `src/platform` | Browser locks and future native platform adapters |
|
||||
| `src/reference`, `src/emulator` | Original-game reference, excluded from the native build |
|
||||
| `reference/public` | Licensed emulator files for the reference build only |
|
||||
| Module | Responsibility |
|
||||
| ------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `src/rom/validate.ts` | Exact cartridge identity, no networking |
|
||||
| `src/game/rom` | Banked reads, LZ, maps/tilesets/sprites/palettes and pinned addresses |
|
||||
| `src/game/world` | Overworld ticks, movement, collision, warps, connections, scenes, callbacks and save validation |
|
||||
| `src/game/scripts` | The game's event, movement and text formats and translated specials, no GB instructions |
|
||||
| `src/game/rendering` | Planar pixels, metatiles, connection strips, adaptive camera, sprites, emotes and minimap |
|
||||
| `src/game/party` | Party Pokémon generation, stat formulas, bag pockets and their validation |
|
||||
| `src/game/runtime.ts` | 30 Hz tick scheduling from real time, input routing and presentation updates |
|
||||
| `src/input` | Abstract buttons, multiple sources and browser bindings |
|
||||
| `src/app` | Runtime-independent load/play/pause/backup lifecycle |
|
||||
| `src/storage` | Versioned envelope, IndexedDB transactions and ordered writes |
|
||||
| `src/ui`, `src/main.ts` | Accessible game tabs, UI composition and DOM dialogue, no ROM offsets |
|
||||
| `src/platform` | Browser locks and future native platform adapters |
|
||||
| `src/reference`, `src/emulator` | Original-game reference, excluded from the native build |
|
||||
| `reference/public` | Licensed emulator files for the reference build only |
|
||||
|
||||
`GameRuntime` is a lifecycle interface, not an emulator contract. Native state is validated JSON: map, position, facing, name/avatar, in-game tile count, flags and sprite variables. It contains no graphics, music, dialogue, GB memory or ROM bytes. The backup envelope retains the historical `coreId` field; native backups use it for their runtime/schema ID.
|
||||
`GameRuntime` is a lifecycle interface, not an emulator contract. Native state is validated JSON, schema version 3. It holds the map, position, facing, name/avatar, player ID and in-game tile count; event and engine flags and sprite variables; scene values, phone contacts, the weekday offset and DST flag; positions of objects that scripts moved; and the party, bag, Pokédex sets and money. Early version-3 backups without a money field migrate to the starting balance. It contains no graphics, music, dialogue, GB memory or ROM bytes. Versions 1 and 2 migrate with new-game defaults. Party Pokémon are validated by recomputing their stats from the ROM. The backup envelope retains the historical `coreId` field; native backups use it for their runtime/schema ID.
|
||||
|
||||
Saves made during an unfinished walk or jump retain its source tile and completed step count, so loading cannot skip a landing event or map transition. Directional mats wait for exit input; doors, stairs and caves force an animated downward step after arrival.
|
||||
|
||||
Native and reference sessions use different IndexedDB databases and Web Locks. Imports reject incompatible schemas and invalid positions before changing the world. A failed import restores the prior state. Original cartridge saves and emulator snapshots cannot be used as native saves.
|
||||
|
||||
Scripts evaluate against a private draft. Unknown commands abort it. Dialogue commits only after the last page is acknowledged. A mid-dialogue save contains the last committed state, allowing the interaction to be replayed without partial rewards/flags. Automatic story scenes and callbacks are explicitly disabled in the exploration milestone.
|
||||
`GameWorld` advances in overworld ticks of two video frames, as the original loop does. The runtime converts elapsed time to ticks. Tile events follow `CheckTileEvent`: a completed step checks connections, then warps, then coordinate events for the current scene. Idle ticks run the current scene script. Map entry runs the NEWMAP, TILES and OBJECTS callbacks on a copy first, so an unsupported callback refuses the step instead of entering a half-initialized map. Objects spawn from event flags at map load, and later flag changes leave them in place until `appear`/`disappear` or the next load.
|
||||
|
||||
Scripts are generators that evaluate against a private draft and yield presentation effects: pages, yes/no or weekday choices, movement, emotes and pauses. The world presents each effect and resumes the script with the answer, or after the animation's ticks. Unknown commands, movement commands and specials abort. Aborting discards the draft and restores the positions the scene changed. The draft commits only when the script ends. A save made during a scene contains the committed state, and coordinate events rewind to the tile before the triggering step, so the scene replays without partial rewards or flags. Specials are translated natively and selected by the routine that the ROM's special table points to.
|
||||
|
||||
Asset caches and the ROM reader remain in memory for lazy extraction. Neither ROMs nor extracted assets enter IndexedDB, the build or a backend. Vite blocks serving the root ROM and private reference checkout during development.
|
||||
|
||||
Introduce future modules with working features: `game/battle`, `game/party`, `game/inventory`, `game/audio`, then `features/link` and `features/walking`. Rules must not import UI/browser modules. Transports and step providers must not write directly into world state.
|
||||
The native viewport follows its available CSS dimensions and draws additional world tiles at a bounded pixel resolution. Beyond a map's edge it draws the connected map with the current tileset, as the original connection strips do, and the border block elsewhere. Resizing also redraws paused sessions. The local minimap caches terrain from the loaded map and updates its marker from the same world position used by the player; the Map tab shares that view. It is a current-area map, not a full region atlas. Leaving Game pauses the session and releases held input; returning requires explicit play. The reference player retains its own fixed-screen styling.
|
||||
|
||||
`game/battle` now holds the native battle core and ROM-backed battle tables. Its unit and damage/type reference tests do not yet establish the full overworld-to-battle browser flow. Introduce future modules with working features: `game/audio`, then `features/link` and `features/walking`. Party and bag models live in `game/party`; scripts change them only on their draft state. Rules must not import UI/browser modules. Transports and step providers must not write directly into world state.
|
||||
+25
-13
@@ -2,7 +2,7 @@
|
||||
|
||||
## Reproducible reference
|
||||
|
||||
The private `.reference/pokecrystal` checkout is pinned to `7a7881d0d62e0ddbd82dcf10e7116807487ac651`. With RGBDS 1.0.3, its `crystal11` build is byte-identical to the supplied English US/Europe revision 1.1 ROM. `npm run check:reference` verifies the files, commit and every address in `src/game/rom/profile.ts` against generated symbols.
|
||||
The private `.reference/pokecrystal` checkout is pinned to `7a7881d0d62e0ddbd82dcf10e7116807487ac651`. With RGBDS 1.0.3, its `crystal11` build is byte-identical to the supplied English US/Europe revision 1.1 ROM. `npm run check:reference` verifies the files and commit. It checks every ROM and RAM address in `src/game/rom/profile.ts` against generated symbols, event constants against `constants/event_flags.asm`, and map-group bounds against `data/maps/maps.asm`.
|
||||
|
||||
To recreate the private reference:
|
||||
|
||||
@@ -21,23 +21,31 @@ The reference checkout, rebuilt ROM, extracted graphics, saves and gameplay scre
|
||||
|
||||
These paths refer to the pinned [PRET source](https://github.com/pret/pokecrystal/tree/7a7881d0d62e0ddbd82dcf10e7116807487ac651).
|
||||
|
||||
| Native module | PRET reference | Evidence and limits |
|
||||
| -------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `game/rom/lz.ts` | `home/decompress.asm` | All LZ command types have unit vectors; six tilesets match original ASM execution byte-for-byte. |
|
||||
| `game/rom/assets.ts` maps/events | `data/maps/maps.asm`, `data/maps/attributes.asm`, `macros/scripts/maps.asm` | Six-map dimensions, events, destinations, navigation and return warps checked with the actual ROM. Connections are decoded but traversal is disabled. |
|
||||
| Tiles/palettes | `home/map.asm`, `engine/gfx/color.asm`, `engine/tilesets/mapgroup_roofs.asm` | Graphics match rebuilt reference bytes. Day/night palettes and roofs supported; terrain animation/dynamic tiles and other special palettes pending. |
|
||||
| Sprites/rendering | `data/sprites/sprites.asm`, `data/sprites/facings.asm` | Chris/Kris and standard NPC graphics/facings decoded. Dynamic Pokémon icons and room decorations pending. |
|
||||
| `game/world/world.ts` | `engine/overworld/player_movement.asm`, `data/collision/collision_permissions.asm` | Walking, walls, visible objects and ordinary local warps. Not complete frame-by-frame parity; forced movement, ledges and surfing are refused. |
|
||||
| Event interpreter | `macros/scripts/events.asm`, `engine/overworld/scripting.asm`, `engine/events/std_scripts.asm` | Bounded calls/jumps/conditions, flags, initial sprite variables and basic text interactions. Unknown commands abort; no assembly fallback. |
|
||||
| Text interpreter | `macros/scripts/text.asm`, `constants/charmap.asm` | Literal/far text, line/paragraph controls and player substitution. Dynamic RAM/ASM text is unsupported. |
|
||||
| Native module | PRET reference | Evidence and limits |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `game/rom/lz.ts` | `home/decompress.asm` | All LZ command types have unit vectors; six tilesets match original ASM execution byte-for-byte. |
|
||||
| `game/rom/assets.ts` maps/events | `data/maps/maps.asm`, `data/maps/attributes.asm`, `data/maps/scenes.asm`, `data/maps/landmarks.asm`, `macros/scripts/maps.asm` | Any map header in the ROM's 26 groups decodes; only the six ported maps can be entered. Location names, scene-variable owners and connection offsets come from the ROM. |
|
||||
| Tiles/palettes | `home/map.asm`, `engine/gfx/color.asm`, `engine/tilesets/mapgroup_roofs.asm` | Graphics match rebuilt reference bytes. Connected maps draw beyond the edges with the current tileset, like the original strips. Terrain animation and other special palettes pending. |
|
||||
| Sprites/rendering | `data/sprites/sprites.asm`, `data/sprites/facings.asm`, `data/sprites/emotes.asm` | Chris/Kris, standard NPCs, emote bubbles and jump shadows decoded. Walking frames follow `SetFacingStepAction`. Dynamic Pokémon icons and room decorations pending. |
|
||||
| `game/world/world.ts` | `engine/overworld/events.asm`, `player_movement.asm`, `warp_connection.asm`, `data/collision/collision_permissions.asm` | 30 Hz overworld ticks, 8-tick walks, 16-tick ledge jumps, directional mats, animated door/stair exits, connection coordinates, events, scenes and callbacks. Surfing and NPC roaming remain absent; turn timing still needs comparison. |
|
||||
| Event interpreter | `macros/scripts/events.asm`, `engine/overworld/scripting.asm`, `engine/events/std_scripts.asm` | Resumable; yields text, choices, movement, emotes and pauses. Scenes, phone contacts, string buffers and object commands. Unknown commands and specials abort without committing. |
|
||||
| Movement interpreter | `macros/scripts/movement.asm`, `engine/overworld/movement.asm`, `engine/overworld/map_objects.asm` | Turns, steps, slides, jumps (two tiles with the original arc), sleeps, facing locks, visibility and emotes. `follow` moves the follower into the leader's previous square. |
|
||||
| Specials | `data/events/special_pointers.asm`, `engine/rtc/timeset.asm`, `engine/overworld/decorations.asm` | Selected by routine address from the ROM table: `SetDayOfWeek`, initial DST flags, `RestartMapMusic` (no audio yet) and the empty-room decoration toggles. |
|
||||
| `game/rom/pokemon.ts` | `data/pokemon/base_stats`, `evos_attacks.asm`, `data/moves/moves.asm`, `data/items/attributes.asm`, `engine/gfx/load_pics.asm` | Species, move and item names, base data, learnsets, move PP, item pockets, growth-rate exp and front pictures (`FixPicBank`, `PadFrontpic`). Starter pictures match rebuilt bytes. |
|
||||
| `game/party` | `engine/pokemon/move_mon.asm`, `engine/pokemon/caught_data.asm`, `engine/items/items.asm` | `GeneratePartyMonStats` for script gifts: DVs, `FillMoves`, PP, exp, `CalcMonStatC`, happiness and caught data. `PutItemInPocket`, key items and `TossItem`. PC boxes, TMs and HMs are refused. |
|
||||
| Text interpreter | `macros/scripts/text.asm`, `constants/charmap.asm`, `home/text.asm` | Literal/far text, RAM names and string buffers from native state, numbers of dots, and sound or pause cues (consumed). `text_asm` and other RAM reads are refused. |
|
||||
|
||||
Supported event opcodes are explicit in the interpreter switch. Audio commands and delays consume their operands, but sound sequencing and presentation timing are pending; those opcodes do not imply complete audiovisual behavior.
|
||||
Supported event opcodes are explicit in the interpreter switch. Audio commands consume their operands, but sound sequencing is pending; those opcodes do not imply complete audiovisual behavior. `pause` holds the current text or waits the original number of overworld ticks.
|
||||
|
||||
Scripts run on a private draft. The world presents each yielded effect, then resumes the script with the player's answer or when the animation ends. The draft is committed only when the script ends. A save made during a scene returns the committed state, and coordinate events rewind to the source of the triggering walk or two-tile jump. Saves during movement also retain the source tile until arrival events run, including across map connections. A failed scene restores the positions it had changed. As in `LoadMapObjects`, map objects spawn when the map loads. Later flag changes do not remove objects already shown; only `appear` and `disappear` do.
|
||||
|
||||
The opening scenes currently run end to end from the ROM: Mom's Pokégear, weekday and DST scene, the teacher at the west edge, the rival at the lab window, Elm's introduction with its yes/no loop, the lab's exit guard, the starter choice with `pokepic`, `givepoke` and the nickname prompt, Elm's directions and the aide's Potion through the ROM's own `GiveItemScript`. `callasm` accepts only explicitly empty routines or native translations; battle whiteout hooks are present but await full flow validation. The naming screen is a native text field limited to the characters the original offers.
|
||||
|
||||
## Actual emulator comparison
|
||||
|
||||
`tests/reference-parity.spec.ts` loads the user's ROM into the reference emulator and places a small original test trampoline in emulated WRAM. It calls the ROM's `FarDecompress` routine at `$0b40`, then sets a return sentinel. Every output byte is compared with the native decoder for six supported map tilesets. This executes the original routine rather than comparing two copies of our code.
|
||||
|
||||
That establishes decompression parity for those inputs. It does not prove complete gameplay, rendering, battles, audio, timing or physical-device parity. Extend controlled comparisons as each subsystem is translated.
|
||||
The same suite compares 400 damage cases and 400 type-effectiveness cases per browser against the original battle routines. Battle unit tests cover win, escape, loss, experience, level-up and move-learning flows. This establishes parity only for the compared routines and inputs. It does not prove complete gameplay, rendering, battles, audio, timing or physical-device parity. Extend controlled comparisons as each subsystem is translated.
|
||||
|
||||
## Validation
|
||||
|
||||
@@ -55,6 +63,10 @@ User-ROM tests skip when the file is absent, including public CI. Synthetic test
|
||||
|
||||
Native production is `dist/`; the optional reference output is `dist-reference/`. Release checks reject emulator dependencies, binary game files and embedded binary assets in the native output. Source review is still required when adding assets or data.
|
||||
|
||||
## Save schema
|
||||
|
||||
Native saves are version 3. Version 2 added scene values by owning map, phone contacts, the weekday offset and DST flag, and positions of objects that scripts moved on the current map. Version 3 adds the player ID, party, bag, Pokédex seen/caught sets and money. Early version-3 backups without money receive the original starting balance; explicitly invalid balances are rejected. Restores recompute each Pokémon's stats from its DVs and reject any mismatch, and check every item against its ROM pocket. Older saves migrate with new-game defaults; a missing player ID is drawn as a new game draws it. Objects are restored from the save on continue, and only the TILES callback runs, as in `MapSetupScript_Continue`.
|
||||
|
||||
## Next slice
|
||||
|
||||
Expand automatic scenes/callbacks and native party/inventory models to implement the opening through starter selection. Add the first battle loop with Route 29 and the Mystery Egg quest. Keep this story milestone separate from exploration saves until initialization and migration are defined.
|
||||
Validate the existing battle core and UI together, including win, escape, whiteout and save/reload through the browser. Encounter tables and ledge movement are present, but Route 29 stays disabled until its scripts, catching tutorial, fruit tree and item interactions are supported and tested. Then continue to Cherrygrove. Add party, bag and Pokégear menus over the native models. Heal-machine and other specials stay refused until translated.
|
||||
+74
-12
@@ -17,17 +17,47 @@ The emulator-backed prototype is now at `/reference.html`. The default applicati
|
||||
- A bounded interpreter for a subset of the game's own event bytecode, plus text decoding. This does not execute GB instructions.
|
||||
- Original initial event flags, readable signs, bedroom radio, bookshelves and supported conversations. Unknown interactions abort without committing partial changes.
|
||||
- Native DOM dialogue, name/avatar choice, touch/keyboard controls and pause/resume.
|
||||
- A minimal Crystal-style shell with Game, Savegames, Map, Pokédex, Link and Friends tabs across the top. The game uses the available native canvas, and leaving Game releases input and pauses play.
|
||||
- Existing save, backup export and backup import actions in Savegames. Map shares a live local minimap with the game and shows the current supported area, player position and coordinates. Pokédex, Link and Friends are clearly marked as planned rather than populated with placeholder data.
|
||||
- Native JSON state inside the backup envelope, separate IndexedDB storage and a separate tab lock. No emulator snapshot or cartridge save migration is implied.
|
||||
- Synthetic tests, local-ROM tests, browser checks, and comparisons against the original decompression routine running in the reference emulator.
|
||||
- Native production output excludes the emulator and original game assets.
|
||||
|
||||
This is **exploration**, not a complete new game or story-compatible save. Opening scenes, automatic map callbacks/coordinate events, story progression, NPC movement, decorations, animated terrain, full collision behavior, connected routes, party/inventory, battles and audio remain unported. Online Link and real-world steps come later.
|
||||
## Implemented: opening scenes
|
||||
|
||||
- Resumable event interpreter: text, yes/no and weekday choices, scripted movement, `follow`, emotes, pauses, scene variables, phone contacts, string buffers and translated specials. Unknown commands still abort without committing.
|
||||
- Movement data decoder for turns, steps, slides, jumps, sleeps, facing locks, visibility and emotes, animated at the original 30 Hz overworld rate. Player walking now takes the original 8 ticks per tile, not half that.
|
||||
- Coordinate events, scene scripts with `sdefer`, and NEWMAP/TILES/OBJECTS map callbacks, including the bedroom's own initialization callback. Objects spawn at map load as in the original.
|
||||
- Mom's Pokégear, weekday and DST scene; the teacher at the town's west edge; the rival at the lab window; and Elm's introduction with the lab's exit guard, all from the ROM's scripts.
|
||||
- Map headers for all 26 groups, ROM location names and connected maps drawn beyond the edges. Entering an unported connection is refused with its location name.
|
||||
- Version 2 native saves with scenes, phone, game-clock settings and moved objects; version 1 saves migrate.
|
||||
|
||||
## Implemented: starter and first items
|
||||
|
||||
- ROM decoders for species names, base data, learnsets, moves, items, pockets, growth rates and front pictures.
|
||||
- Native party generation for script gifts, following `GeneratePartyMonStats`: random DVs, level-up moves, PP, exp, stats, happiness and caught data. The Pokédex records the species as seen and caught.
|
||||
- Bag pockets with the original capacities and stacking rules. `verbosegiveitem` runs the ROM's own `GiveItemScript`.
|
||||
- Elm's Poké Balls, with a picture box, the nickname prompt with a native naming field, Elm's directions and phone number, and the aide's Potion.
|
||||
- Version 3 saves with the player ID, party, bag and Pokédex; restores recompute stats and check item pockets.
|
||||
|
||||
## Implemented: ledges and warp movement
|
||||
|
||||
- Walkable ledge tops, directional two-tile jumps over 16 ticks, and jump shadows.
|
||||
- Exit mats wait for input in their exit direction. Arriving on a mat preserves the actual position; doors, stairs and caves animate the downward exit step.
|
||||
- Mid-step saves replay from the source tile, including jumps and map connections, so reload cannot bypass landing scenes or warps.
|
||||
- Synthetic movement tests run without a ROM. Local-ROM tests exercise five Route 29 ledge types without enabling that route in production; browser checks cover stairs, opening scenes and an exit-mat save/reload.
|
||||
|
||||
## In progress: native battles
|
||||
|
||||
The battle core, ROM tables, encounter hooks, battle UI and whiteout hooks are present. Unit tests cover wins, escape, loss, experience and move learning; reference tests compare damage and type effectiveness. Full browser battle flows, capture, Route 29 scripts and the opening quest remain unverified or unfinished.
|
||||
|
||||
This is still not a complete new game. Playable battles, party/bag/Pokégear menus, story progression beyond the lab, NPC roaming, decorations, animated terrain, surfing, entering routes and audio remain unfinished. Save slots, a Johto/Kanto atlas, Pokédex records, online Link, friends and real-world steps come later.
|
||||
|
||||
## 1. Complete the overworld foundation
|
||||
|
||||
Extend extraction to every map. Read the ROM's map index and location names rather than shipping a copied world database. Implement connected borders, seamless transitions, dynamic warps, elevators, ledges, ice, currents, forced movement, surfing, cycling, cut trees and boulders.
|
||||
Map headers, location names, connection offsets, connected-border drawing, coordinate events, scene scripts, map callbacks and scripted movement are in place (see above). Next: enable connected transitions as their maps are ported; add dynamic warps, elevators, ice, currents, remaining forced movement, surfing, cycling, cut trees and boulders. Player turn timing still needs a reference comparison.
|
||||
|
||||
Port callbacks, decorations, tile changes, scheduled NPC visibility, NPC movement, trainer sight lines and scripted movement. Complete terrain animation, layering and special palettes. Record deviations from the original until a comparison test closes them.
|
||||
Port decorations, tile changes (`changeblock`), NPC roaming movement types, trainer sight lines and the remaining movement commands. Complete terrain animation, layering and special palettes. Record deviations from the original until a comparison test closes them.
|
||||
|
||||
Acceptance: representative outdoor/interior/cave/connected-map traces produce matching positions, collisions, transitions and event changes in native and reference engines. Do not enable an area merely because its image can be decoded.
|
||||
|
||||
@@ -37,9 +67,9 @@ Introduce native player, party, Pokémon, inventory, money and quest models. Rea
|
||||
|
||||
Expand script calls, choices, scene state, inventory commands and native special handlers. Translate routines reached through assembly calls into explicit native services; never fall back to emulator execution in the shipping game.
|
||||
|
||||
Implement the introduction, naming/clock setup, meeting Mom, Elm's starter selection, Route 29, Cherrygrove and the Mystery Egg round trip. Keep exploration saves separate until migration is meaningful.
|
||||
Meeting Mom, Elm's introduction, the starter and the aide's Potion run now. Next: validate and complete battle integration, Route 29 with wild encounters and the catching tutorial, Cherrygrove and the Mystery Egg round trip; then the introduction's naming and clock screens.
|
||||
|
||||
Build the required native battle engine: deterministic randomness, stats, move selection, accuracy/critical checks, damage, status, turn order, switching, fainting, experience, capture and rewards. Compare controlled seeds and states with the original, including integer rounding and overflow behavior.
|
||||
Complete and validate the native battle engine: deterministic randomness, stats, move selection, accuracy/critical checks, damage, status, turn order, switching, fainting, experience, capture and rewards. Compare controlled seeds and states with the original, including integer rounding and overflow behavior.
|
||||
|
||||
Acceptance: finish the opening quest, including encounters and the rival battle, party/inventory changes and save/reload, without emulation or manually setting story flags.
|
||||
|
||||
@@ -55,13 +85,31 @@ Acceptance: main-game/postgame playthroughs, representative optional content, ba
|
||||
|
||||
## 4. Modern mobile presentation and delivery
|
||||
|
||||
The first presentation increment replaces the landing page and handheld frame with a restrained Crystal-style interface. Game, Savegames, Map, Pokédex, Link and Friends stay above a viewport-filling native canvas. The renderer draws more world tiles as space grows instead of stretching a 160 × 144 image. The game and Map tab share a live local minimap; the atlas and unsupported tabs remain honest planned states. The linked UI reference could not be inspected through automated access because the site returned a Cloudflare challenge, so exact screenshot matching is not claimed.
|
||||
|
||||
Build touch interfaces directly over native models: party, pack, battle commands, PC and Pokégear. Keep UI separate from gameplay calculations. Add scalable text, configurable controls and accessible focus/announcements.
|
||||
|
||||
Replace the single logical native save with real slots only after party, inventory and story state have stable schemas. Each slot needs a durable ID, display metadata, independent autosave and explicit create, load, rename, duplicate, export, import and delete flows. Version every persisted model. Migrate the current singleton save into a default slot exactly once, preserve unknown or newer backups without rewriting them, and use atomic writes with recovery from the last valid record. Import must preview identity, version and conflicts before replacement.
|
||||
|
||||
Dependencies: stable serialization for every system stored in a slot, migration fixtures for every released schema, quota/error handling and a transaction boundary that also covers future Link and walking credits.
|
||||
|
||||
Acceptance: migrate existing browser data without loss, keep several independent playthroughs, recover from interrupted writes and reject incompatible or corrupt imports without changing a valid slot. Test create/load/delete/rename/duplicate, autosave isolation, export/import conflicts and upgrades from every released schema.
|
||||
|
||||
Add PWA installation/offline caching of the app shell only. ROM/data retention remains a separate explicit local preference; otherwise reselect the ROM after reopening. Add safe application updates, schema migrations, storage persistence/quota handling and portable backups. Investigate original `.sav` import only with verified structure, checksums and RTC conversion.
|
||||
|
||||
Acceptance: installation, offline startup, portrait/landscape, touch/audio, background/resume and updates on physical iPhone/Safari and Android/Chrome. Browser automation does not establish physical-device compatibility.
|
||||
|
||||
## 5. Internet Link
|
||||
## 5. World map and Pokédex
|
||||
|
||||
Promote the current-area minimap into a Johto/Kanto atlas after all map groups, connections and location names can be decoded from the selected ROM. Derive region geometry, visited areas, player location and Fly destinations from native map and story state. Do not ship copied map artwork or claim navigation through maps whose collisions and events are still unsupported.
|
||||
|
||||
Build the Pokédex from typed ROM decoders for species names, base data, evolutions, moves and graphics. Seen, caught, forms and habitat or area views must come from native game state and encounter tables. Keep ROM-derived records unavailable until a verified ROM is selected.
|
||||
|
||||
Dependencies: complete map indexing and connections, stable player/story flags, party and capture flow, encounter decoding, species graphics and save migrations.
|
||||
|
||||
Acceptance: atlas positions and Pokédex records match pinned PRET fixtures and local-ROM comparisons; visited, seen and caught state survives slot switching, backup round trips and schema upgrades. The UI must distinguish decoded data from progress the player has actually unlocked.
|
||||
|
||||
## 6. Internet Link and friends
|
||||
|
||||
Implement a game-level protocol over native state. This architecture does not need to tunnel serial timing or synchronize GB CPU cycles.
|
||||
|
||||
@@ -69,17 +117,31 @@ Separate `LinkTransport`, `TradeSession` and `BattleSession`. Start with local p
|
||||
|
||||
Trades need durable preparation, a transaction ID, agreed completion, idempotent recovery and pre-trade backups for both players. Do not retry ambiguous completion automatically. Battles need deterministic state, agreed randomness, turn commands, state checks and a disconnect policy. Define validation, room expiry and persistence before public service access.
|
||||
|
||||
Acceptance: cross-network trades/battles and induced duplicate messages, latency, disconnects and reconnects at every phase, without duplication or lost Pokémon.
|
||||
Add a separate account and relationship layer before Friends becomes active. Define a stable public identity that does not expose save-slot or ROM data. Support private invite creation, acceptance and expiry; friend removal; user blocking; and abuse reporting if user-generated text is ever added. Presence is opt-in, coarse and independently disableable. Privacy controls must cover discoverability, invite permissions and online status. Blocking must prevent new invites, presence disclosure and Link sessions in both directions.
|
||||
|
||||
## 6. Walking companion
|
||||
Dependencies: native party, PC, battle and save-slot transactions; a versioned wire protocol; authenticated identity; signaling/relay operations; account recovery and deletion; rate limits, moderation operations and a published privacy policy. Link and Friends remain unavailable until these dependencies have production ownership and failure handling.
|
||||
|
||||
Separate a platform `StepProvider`, local activity ledger and reward rules. Keep real-world steps distinct from the in-game tile counter. Deduplicate history, record credited intervals, bound invalid data and handle denied/revoked permission.
|
||||
Acceptance: cross-network trades/battles and induced duplicate messages, latency, disconnects and reconnects at every phase, without duplication or lost Pokémon. Verify invite expiry, simultaneous relationship changes, remove/re-add, block/unblock, hidden presence, account deletion and attempts to join with incompatible game or schema versions.
|
||||
|
||||
Foreground browser motion can help prototype the experience; reliable pocket/background tracking needs platform support. Evaluate a native wrapper with iOS Core Motion and Android Health Connect/step sensors, checking current permissions and hardware availability when implementing it.
|
||||
## 7. Optional Pokéwalker-style egg assistance
|
||||
|
||||
Choose the initial reward explicitly, such as companion progress or an item goal. Apply it through native game commands at safe points with a durable, idempotent ledger transaction. Sensor callbacks must not write directly into game state. Keep activity data on device by default.
|
||||
This optional mobile feature uses real-world walking to assist egg hatching after native party, breeding, eggs and faithful in-game hatching are complete. The pinned Crystal engine decrements party egg counters from overworld walking in [`CountStep`](https://github.com/pret/pokecrystal/blob/7a7881d0d62e0ddbd82dcf10e7116807487ac651/engine/overworld/events.asm#L866-L900) and [`DoEggStep`](https://github.com/pret/pokecrystal/blob/7a7881d0d62e0ddbd82dcf10e7116807487ac651/engine/pokemon/breeding.asm#L174-L196); battles do not advance them. A battle-based bonus would therefore be an explicit, separately enabled extension rather than Crystal behavior.
|
||||
|
||||
Acceptance: a real walk with a locked phone is recorded, credited exactly once after reopening, and safely reflected in the game. Verify interaction with trades and save restoration.
|
||||
Separate a platform `StepProvider`, local activity ledger and reward rules. Request read access to steps only, after an explicit explanation and opt-in. Keep real-world steps distinct from the in-game tile counter, show what interval will be credited and provide a disconnect/delete control. Do not request distance, heart rate, workouts or permission to write health records. Keep raw activity data on device by default.
|
||||
|
||||
An ordinary PWA cannot directly query Apple HealthKit, Core Motion pedometer history, Android Health Connect or Android step sensors. Reliable pocket and locked-screen behavior therefore needs a native companion or wrapper and a narrow bridge into the web game. On Apple platforms, evaluate read-only HealthKit step counts and Core Motion `CMPedometer`; HealthKit requires the capability, a purpose string and per-type authorization, while Core Motion exposes historical pedometer queries. On Android, prefer Health Connect `READ_STEPS` where available and evaluate `TYPE_STEP_COUNTER` with `ACTIVITY_RECOGNITION` as a device-local fallback. Handle absent hardware, unavailable services, denied or revoked access and partial history without blocking the game.
|
||||
|
||||
Normalize provider records into immutable local intervals with provider/source IDs, start/end times and step totals. Deduplicate overlapping samples before reward calculation. Commit each credit as one transaction containing a unique credit ID, the source interval set, the target slot and egg identity, the applied hatch-counter delta and resulting state version. Persist the ledger and game mutation atomically. Restoring an older backup must not make an already consumed interval eligible again; trading, moving or hatching an egg must close or retarget pending credits explicitly; wall-clock or timezone changes must not create new credit. Sensor callbacks only append provider observations, never mutate game state.
|
||||
|
||||
The first reward is bounded egg-hatch assistance for an egg currently in the party. Define and test the conversion rate and daily cap before release, never reduce an egg below the normal hatch trigger outside a safe game checkpoint, and show the pending effect before applying it. No party or no eligible egg means steps remain unspent or expire according to a documented rule; do not silently redirect them to another reward.
|
||||
|
||||
Store distribution is a release dependency, not an assumption. Apple says HealthKit must be used for health and fitness purposes and its review rules restrict health and Motion data use, so a game-only reward may not qualify for HealthKit/App Store approval. Google Play lists health-integrated games as an approved health-permission use case, but still requires a Health apps declaration and review of the requested permissions. Recheck both policies before implementation and submission. Core Motion or a device step sensor may reduce health-store scope, but still requires native permissions and review.
|
||||
|
||||
Dependencies: native party, breeding, eggs and hatching; stable egg identity; save-slot transactions and migrations; a native iOS and Android host; permission/privacy UI; and confirmed store eligibility for the chosen provider.
|
||||
|
||||
Acceptance: on supported physical iPhone and Android devices, a real walk with the phone locked is read with steps-only consent, credited to an eligible egg exactly once after reopening, and safely reaches the normal hatch flow. Exercise duplicate and overlapping samples, provider corrections, permission revocation, device reboot, offline use, timezone and clock changes, backup restore, slot switching, trade, egg movement and hatch between observation and credit. Denial, unsupported hardware and failed review eligibility leave the base game fully usable.
|
||||
|
||||
Official platform references: Apple [HealthKit authorization and capability setup](https://developer.apple.com/documentation/xcode/configuring-healthkit-access), [Core Motion pedometer history](<https://developer.apple.com/documentation/coremotion/cmpedometer/querypedometerdata(from:to:withhandler:)>) and [App Review Guidelines 2.5.1 and 5.1.3](https://developer.apple.com/app-store/review/guidelines/); Android [Health Connect step access](https://developer.android.com/health-and-fitness/health-connect/features/steps), [step counter sensor guidance](https://developer.android.com/develop/sensors-and-location/sensors/sensors_motion) and Google Play [Android health permissions guidance](https://support.google.com/googleplay/android-developer/answer/12991134?hl=en).
|
||||
|
||||
## Working method
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Game-first presentation plan
|
||||
|
||||
## Scope and sequence
|
||||
|
||||
1. Replace the landing page and handheld frame with a minimal, viewport-first interface inspired by Crystal's menus: cream panels, dark double borders, compact monospace text, a selection arrow and restrained blue accents. The supplied [UI reference](https://www.gameuidatabase.com/gameData.php?id=1813) blocks automated access, so exact screenshot matching is not claimed.
|
||||
2. Put Game, Savegames, Map, Pokédex, Link and Friends tabs above the viewport. Implement keyboard-accessible navigation and pause/release game input when leaving Game. Savegames exposes the existing save, export and import actions. Map shows the current supported map and player. Unimplemented game/network systems get explicit planned states, without pretend data.
|
||||
3. Expand the native renderer to the available canvas dimensions, drawing additional world tiles instead of stretching a 160 × 144 image. Preserve pixel proportions, camera centering, collision and movement. Resize while playing or paused; release observers when replacing a session. Keep the separate emulator reference untouched.
|
||||
4. Add a live local minimap with a player marker, map name and coordinates. Update movement, warps and restored saves. Share the map view with the Map tab; distinguish the current area from the future Johto/Kanto atlas.
|
||||
5. Extend the full roadmap with save slots, a ROM-backed Pokédex, online Link, friends and an optional walking companion for egg progress. Research HealthKit/Health Connect and native pedometer alternatives; ordinary browsers must not pretend to have access to health stores. Party, eggs and faithful in-game hatching precede real-step rewards. Treat any battle-based hatch bonus as an explicit extension, not original Crystal behavior.
|
||||
6. Validate production build, unit tests and Chromium/WebKit flows. Cover responsive widths, portrait/landscape, tabs/focus, pause safety, movement/minimap agreement, save restore and renderer resize. Keep ROM-derived screenshots and assets ignored.
|
||||
|
||||
## Work allocation
|
||||
|
||||
- Sol / medium: shell styling and accessible tabs (`src/ui/shell.ts`, `styles.css`, `tabs.ts`).
|
||||
- Sol / medium: adaptive native renderer and resize lifecycle (`src/game/rendering`, `src/game/runtime.ts`), with focused tests.
|
||||
- Sol / medium: roadmap, platform feasibility and concise documentation (`docs/PLAN.md`, `README.md`).
|
||||
- Integrator: live minimap, main application wiring, integration tests, visual inspection and final verification.
|
||||
|
||||
## Delivery boundaries
|
||||
|
||||
This increment delivers the presentation, existing save actions, adaptive world canvas and local minimap. Full save-slot management, Pokédex records, networking, friends, health permissions and egg rewards depend on systems outside the existing exploration milestone and remain explicitly sequenced roadmap work.
|
||||
|
||||
## Verification
|
||||
|
||||
Delivered with three Sol agents at medium effort and an integration pass. Native and reference builds, release isolation, vendor integrity and pinned-reference checks pass. All 26 unit tests and 16 Chromium/WebKit browser tests pass, including local-ROM movement, stairs, minimap restore, menu pause behavior and responsive layouts down to 320 × 568 and 844 × 390 landscape. Browser checks do not establish physical-phone or health-provider compatibility. Local visual captures remain in ignored `artifacts/`.
|
||||
@@ -0,0 +1,102 @@
|
||||
# Recovered Claude session
|
||||
|
||||
Recovered on 2026-09-23 from the local Claude Code transcript
|
||||
`~/.claude/projects/-Users-kawa-Crystal/4ac88f30-29e6-4fd5-a4b2-b6a318dd83b3.jsonl`.
|
||||
The session stopped at its usage limit at 09:54 UTC, during research, without a final handoff.
|
||||
|
||||
## Resumed increment: completed 2026-09-23
|
||||
|
||||
The movement increment below is complete. The remaining sections preserve the
|
||||
original recovery context.
|
||||
|
||||
- Added directional two-tile ledge jumps with the existing arc/shadow animation.
|
||||
Unsupported terrain, invalid destinations and occupied landings remain refused.
|
||||
- Corrected directional mats to wait for exit input. Warp arrivals keep their
|
||||
actual coordinates and appropriate facing; doors, stairs and caves animate a
|
||||
downward exit. Removing the old inward teleport also corrected Elm's scripted
|
||||
introduction position.
|
||||
- Mid-walk, mid-jump and mid-connection saves retain the source position. Landing
|
||||
scenes rewind to the actual source of a jump, rather than the intervening wall.
|
||||
- Restored compatibility with early version-3 saves lacking the money field.
|
||||
- Replaced the scratch diagnostic with synthetic movement regressions and
|
||||
optional-ROM tests covering five Route 29 ledge types. Route 29 is enabled only
|
||||
inside that test fixture, not in production.
|
||||
- Fixed the battle test suite's eager ROM read so missing-ROM runs really skip
|
||||
private tests. Updated browser stair inputs and added an exit-mat save/reload
|
||||
flow. Updated the roadmap and architecture to distinguish the existing battle
|
||||
code from its unfinished integration.
|
||||
|
||||
Final checks: 75 unit tests passed with the local ROM; without it, 55 passed and
|
||||
20 private tests skipped. All 24 Chromium/WebKit browser tests passed. Native and
|
||||
reference builds, release isolation, pinned-reference checks, vendor checks and
|
||||
`git diff --check` passed. No commit or push was made.
|
||||
|
||||
Next: validate the overworld-to-battle browser flow and complete Route 29's
|
||||
remaining script, capture/tutorial and item interactions before enabling the
|
||||
route. Player turn timing also remains a documented comparison gap.
|
||||
|
||||
## Scope and current state
|
||||
|
||||
The original request was to read ARCHITECTURE.md, PLAN.md and PRESENTATION_PLAN.md
|
||||
and continue the native port. The working tree contains substantial uncommitted
|
||||
work from multiple increments; preserve it when continuing.
|
||||
|
||||
- Opening scenes, scripted movement, starter selection, naming, the aide's Potion
|
||||
and version 3 saves are implemented and documented.
|
||||
- Native battle modules, ROM tables, damage/type parity tests, encounter handling,
|
||||
battle UI and whiteout handling have been added. These later changes are not
|
||||
fully reflected in the architecture and roadmap documents.
|
||||
- Only the original six maps are enabled in `NATIVE_MAPS`. Route 29 (`24:3`)
|
||||
remains disabled. Passing battle unit tests does not establish a playable
|
||||
Route 29 encounter or the full opening quest.
|
||||
|
||||
## Exact stopping point
|
||||
|
||||
Claude was preparing to revise player movement in `src/game/world/world.ts`.
|
||||
Its last investigation concerned spawn facing after warps. It had not implemented
|
||||
the planned ledge/warp revision.
|
||||
|
||||
The pinned local PRET checkout contains the relevant routines:
|
||||
|
||||
- `engine/overworld/player_movement.asm`: `.TryStep`, `.TryJump`,
|
||||
`.CheckLandPerms`, `.CheckWarp` and the direction tables.
|
||||
- `engine/overworld/tile_events.asm`: `CheckWarpCollision` and
|
||||
`CheckDirectionalWarp`.
|
||||
- `engine/overworld/player_object.asm`: `SpawnPlayer`.
|
||||
- `engine/overworld/map_objects.asm`: movement/turn timing.
|
||||
|
||||
Research found that ledge tops have land permission; the jump check uses the
|
||||
current tile and facing after an ordinary step fails. Doors use collision `$71`,
|
||||
downward warp mats `$70`, and stairs `$7a`. Directional warp mats require their
|
||||
designated input rather than an immediate warp simply upon entry. Verify these
|
||||
rules against the local routines before changing the existing movement flow.
|
||||
|
||||
`tests/zz-scratch.test.ts` is Claude's unfinished diagnostic: it logs local-ROM
|
||||
warp and ledge collisions, contains no assertions and unconditionally requires
|
||||
the private ROM. Replace it with meaningful optional-ROM or synthetic tests
|
||||
before treating the suite as ready for public CI.
|
||||
|
||||
## Validation after recovery
|
||||
|
||||
Run against the current working tree with the local ROM and reference checkout:
|
||||
|
||||
- `npm test`: 45 passed, including the assertion-free scratch diagnostic.
|
||||
- `npm run build`: passed.
|
||||
- `npm run test:e2e`: 22 passed across Chromium and WebKit, including native
|
||||
damage/type comparisons against original routines in the reference emulator.
|
||||
- `npm run check:reference`: ROM, pinned rebuild and profile addresses match.
|
||||
- `npm run check:release`: native output excludes emulator and game assets.
|
||||
- `npm run check:vendor`: passed.
|
||||
|
||||
These checks do not establish complete battle behavior, browser battle UI flows,
|
||||
Route 29 progression or physical-device compatibility. No gameplay source was
|
||||
changed during session recovery.
|
||||
|
||||
## Original next-increment notes (movement now completed)
|
||||
|
||||
Finish ledge and directional-warp movement with focused regression tests,
|
||||
including interrupted movement/save behavior and preservation of the existing
|
||||
opening scenes. Audit Route 29 callbacks, scripts and unsupported destinations
|
||||
before enabling it. Then test wild encounters and battle controls through the
|
||||
browser, including win, escape, loss and save/reload, and reconcile the roadmap
|
||||
with the verified behavior.
|
||||
Reference in new issue
Block a user