691 lines
38 KiB
Markdown
691 lines
38 KiB
Markdown
# Recovered Claude session
|
|
|
|
Latest continuation: see **Controlled capture comparisons: 2026-09-30**
|
|
at the end of this file. Earlier sections are historical snapshots.
|
|
|
|
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.
|
|
|
|
## Battle integration increment: 2026-09-23 (resumed from Codex)
|
|
|
|
Codex committed and pushed `c08d250`, then stopped mid-increment with the
|
|
keyboard/D-pad battle test failing. Claude Code completed it:
|
|
|
|
- Browser battle flows run through the real UI via `tests/battle-fixture.ts`
|
|
(encounter selection only; production maps stay gated): win with level-up and
|
|
Smokescreen, escape, whiteout, keyboard/D-pad menus, mid-battle backup restore
|
|
and unsupported-effect rollback. `tests/battle-world.test.ts` covers the same
|
|
at world level, plus pending stat experience and whiteout callback rollback.
|
|
- Saves accept stored stats between the no-stat-exp and full-stat-exp values,
|
|
since `GiveExperiencePoints` awards stat experience without `CalcMonStats`.
|
|
- A script warp (e.g. whiteout) validates its destination and commits healing,
|
|
money loss and destination callbacks together; aborts restore state and map.
|
|
- Keyboard and on-screen D-pad navigate battle menus (`battle-selected`); A
|
|
continues messages, B leaves the move list.
|
|
- Fixed a phone-width layout bug: a long notice sat in the Play button's auto
|
|
grid column and crushed the status text, pushing the game panel off-screen.
|
|
Below 720px the notice now has its own row.
|
|
- Test fixes: the navigation test now presses A through the intro message, and
|
|
uses a real pointer click on the D-pad (synthetic pointer events cannot be
|
|
captured).
|
|
|
|
Final checks: 82 unit tests with the local ROM (55 passed, 27 skipped without
|
|
it); 36 Chromium/WebKit browser tests; native and reference builds; release,
|
|
vendor and reference checks; `git diff --check`. Not committed.
|
|
|
|
Next: Route 29 (`24:3`) scripts, catching tutorial and items before enabling it;
|
|
then capture, switching and PACK in battle.
|
|
|
|
## Route 29 and Cherrygrove increment: 2026-09-23
|
|
|
|
Enabled Route 29, its Route 46 gate, Cherrygrove City and its five buildings.
|
|
Item balls, the Pokémon Center nurse and the Poké Mart were each ported by a
|
|
Sonnet sub-agent in an isolated worktree, reviewed against the disassembly and
|
|
merged; the rest was done directly.
|
|
|
|
- Fruit trees run `FruitTreeScript`; a native `CheckDailyResetTimer` clears
|
|
the daily engine flags once per game day. `VAR_BOXSPACE` reads an empty box.
|
|
- Item balls run `FindItemInBallScript` with a native `TryReceiveItem`.
|
|
- The nurse runs `PokecenterNurseScript`; `HealParty` now applies
|
|
`ComputeMaxPP`'s PP Up clamp. `EnterMapWarp`'s spawn recording makes
|
|
whiteouts return to the last Pokémon Center entered.
|
|
- Standard marts run natively (`StandardMart`/`BuyMenu`/`SellMenu`).
|
|
- Battle command `recoil` (Struggle) was the only refusal found by a local
|
|
stress run of 360 Route 29 battles across starters and times of day.
|
|
- Save format 3 gained `fruitTrees`, `dailyReset` and `lastSpawnMap`
|
|
(migrated by absence).
|
|
- The phone-width status bar layout and parity test map counts were fixed.
|
|
|
|
Still refused: `catchtutorial` and Cherrygrove's rival scene (both after the
|
|
Mystery Egg), Route 30/46. NPCs do not roam yet.
|
|
|
|
Next: NPC roaming movement (`map_objects.asm` random walk/spin, radius and
|
|
visibility rules, deterministic RNG in tests), trainer sight lines and trainer
|
|
battles, Route 30 and Mr. Pokémon, capture and the catching tutorial.
|
|
|
|
## Trainer AI continuation: 2026-09-24
|
|
|
|
The trainer foundation was subsequently committed through `3e92936`. The next
|
|
AI increment translates Opportunist, Aggressive and Risky scoring, including
|
|
the ROM's stall/reckless/risky tables and Aggressive/Risky's deterministic
|
|
pre-variation damage estimate. Smart is now the only refused move-scoring layer,
|
|
so the rival remains gated. Continue with Smart before the rival, or with
|
|
trainer sight lines and normal trainer-object scripts for the already-supported
|
|
Youngster and Bug Catcher classes on Route 30.
|
|
|
|
## AI layer review: 2026-09-24 (resumed from Codex)
|
|
|
|
Claude Code checked Codex's uncommitted Opportunist, Aggressive and Risky layers
|
|
against `engine/battle/ai/scoring.asm`. The HP thresholds, `AI_50_50` (≥128),
|
|
`79 percent - 1` (200), last-wins ties, the power < 2 and reckless exclusions,
|
|
the strict-borrow KO test and the constant-damage paths all match.
|
|
|
|
One fix: `AIDamageCalc` goes through `EnemyAttackDamage` and
|
|
`BattleCommand_DamageCalc`, and both read `wCriticalHit`. A flag left over from
|
|
an earlier move therefore selects unboosted stats (ignoring screens) and
|
|
doubles the estimate. `enemyAIDamage` now reads the native `criticalHit`
|
|
instead of hard-coding `false`. It also reuses `truncate`. A local-ROM test
|
|
fixes the estimate at 4, 3 (Reflect) and 6 (leftover critical).
|
|
|
|
Known side effects of `AIDamageCalc` that are not modelled: it overwrites
|
|
`wCurDamage`, `wTypeModifier`, `wAttackMissed` and `hBattleTurn`. `CheckTurn`
|
|
resets the modifier and miss flag before each move. Whether the `wCurDamage`
|
|
overwrite can reach Counter/Mirror Coat still needs checking before those
|
|
effects are ported.
|
|
|
|
Final checks: 147 unit tests with the local ROM; 42 Chromium/WebKit browser
|
|
tests; native and reference builds; reference, release and vendor checks;
|
|
`git diff --check`. Not committed.
|
|
|
|
Next (unchanged): Smart AI before the rival, or trainer sight lines and
|
|
normal trainer-object scripts for Route 30's Youngster and Bug Catcher.
|
|
|
|
## Route 30 trainers: 2026-09-24
|
|
|
|
Chose option 2 from the review above: trainer sight lines and trainer-object
|
|
scripts. Both Route 30 trainers have two Pokémon, so the increment also ports
|
|
the trainer's send-out and switch AI. Route 30 and its Berry house are now
|
|
enabled in production.
|
|
|
|
- World: `_CheckTrainerBattle` at step end (before warps, coordinate events and
|
|
encounters) and on idle ticks; `TalkToTrainer` for `OBJECTTYPE_TRAINER`;
|
|
`BGEVENT_ITEM` hidden items. A refused sighting is not restarted until the
|
|
player moves (native safeguard against a rollback loop).
|
|
- Interpreter: `loadtemptrainer`, `trainertext`, `trainerflagaction`,
|
|
`scripttalkafter`, `endifjustbattled`, `checkjustbattled`, `writeobjectxy`,
|
|
`encountermusic`, `loadmem wRunningTrainerBattleScript`, `readmem
|
|
wHiddenItemID`, and callasm `TrainerWalkToPlayer`/`SetMemEvent`.
|
|
`applymovementlasttalked wMovementBuffer` decodes the native buffer.
|
|
- Battle: multi-Pokémon trainer parties (`HandleEnemyMonFaint`,
|
|
`EnemyPartyMonEntrance`, `FindMonInOTPartyToSwitchIntoBattle` with its
|
|
`BattleRandom` fallback), `AI_SwitchOrTryItem`/`CheckAbleToSwitch`/`AI_Switch`
|
|
with the original type-matchup, `e`-carry and quarter-HP bugs, and
|
|
`wPlayerUsedMoves`. `BattleTrainer` now requires `switchFlags`.
|
|
- Stress (local, not committed): 1,080 Route 30 battles; the only refusal was
|
|
Chikorita's Reflect at level 12 (`screen`), a pre-existing gap.
|
|
|
|
Final checks: 160 unit tests with the local ROM; 44 Chromium/WebKit browser
|
|
tests including the Route 30 sighting through the UI; native and reference
|
|
builds; reference, release and vendor checks; `git diff --check`. Not committed.
|
|
|
|
Next: Mr. Pokémon's house (Oak, Pokédex, Mystery Egg) and the return to Elm;
|
|
Reflect/Light Screen; then Smart AI before the rival. Joey (after the Egg)
|
|
needs `askforphonenumber` and the phone standard scripts.
|
|
|
|
## Reflect and Light Screen: 2026-09-24
|
|
|
|
Completed the battle gap found in the Route 30 stress run. `screen` now runs
|
|
both moves from ROM effect scripts. Independent five-turn counters include
|
|
the setup turn, do not refresh on repeated use, survive enemy send-outs and
|
|
expire with ROM text in `HandleScreens` order. The existing damage path handles
|
|
physical/special defense and critical stage rules.
|
|
|
|
Seven new local-ROM regressions cover player and enemy use, PP on failure,
|
|
concurrent durations, expiration order, send-out persistence and damage stats.
|
|
Also moved the NPC test's eager ROM read into `beforeAll`, restoring its
|
|
intended skip behavior when no ROM is available.
|
|
|
|
Checks: 167 unit tests with the local ROM; 76 passed and 91 skipped without it;
|
|
44 Chromium/WebKit browser tests; native and reference builds; reference,
|
|
release and vendor checks; `git diff --check`. Screen routines were reviewed
|
|
against pinned PRET source, not compared by executing the original routines.
|
|
Changes are uncommitted.
|
|
|
|
Next: Mr. Pokémon's house and the Mystery Egg; Smart AI before enabling the
|
|
rival; capture and the catching tutorial. Joey's post-Egg phone scripts remain
|
|
unsupported.
|
|
|
|
## Mr. Pokémon and the return to Elm: 2026-09-24 (resumed from Codex)
|
|
|
|
Codex had enabled Mr. Pokémon's house and added `NameRival`, `blackoutmod`,
|
|
`reloadmap`, the queued Elm call and the no-handler Smart AI subset. It
|
|
stopped with all four quest browser tests failing and without docs. Claude
|
|
Code finished the increment:
|
|
|
|
- The rival scene needed `special FadeOutMusic` (audio only, now accepted).
|
|
- The quest fixture's constant `() => 0` RNG hung `BattleCommand_DamageVariation`,
|
|
which redraws until the byte is at least 217. The fixture now uses a seeded LCG.
|
|
Relocating to Cherrygrove had also carried the house's moved Mr. Pokémon and
|
|
Oak onto the Guide Gent and rival (ids 2 and 3), producing an unrestorable
|
|
save. The fixture now clears objects and starts off the Guide Gent's tile.
|
|
- The browser test expected `specialPhoneCall` 1; `SPECIALCALL_ROBBED` is 2.
|
|
- `NameRival` yielded a naming choice with zero pages, because `promptbutton`
|
|
had already flushed them. The dialogue never reached its last page, so the
|
|
officer scene soft-locked. It now shows the ROM's "RIVAL'S NAME?" and reads
|
|
the "SILVER" default from ROM. As in `InitName`, blank names of any number of
|
|
spaces take the default. The naming input's accessible label no longer says
|
|
"Nickname".
|
|
- Elm's call now runs the ROM's `CheckSpecialPhoneCall.script` →
|
|
`Script_ReceivePhoneCall` wrapper. It reads the condition and caller script
|
|
from `SpecialPhoneCallList` instead of hard-coding id 2, adds `memcall`, and
|
|
shows `HangUp`'s timed "Click!". Ringing and the caller name box are still
|
|
not presented.
|
|
- Added tests: the rival scene for all three starters and both triggers, a
|
|
`CANLOSE` loss, reload after each scene, the Elm call (indoors, outdoors,
|
|
mid-call reload), the officer naming (named, blank, all-space, reload at
|
|
the naming screen), the Egg handover and the aide's Poké Balls, plus a
|
|
browser naming-field test.
|
|
|
|
Checks: 191 unit tests with the local ROM (80 passed, 111 skipped without it);
|
|
50 Chromium/WebKit browser tests; native and reference builds; reference,
|
|
release and vendor checks; `git diff --check`. Not committed.
|
|
|
|
Next: capture and the Route 29 catching tutorial (`catchtutorial`), the
|
|
first remaining refusal in the opening quest. Then the ringing presentation,
|
|
player switching and items in battle. Joey's post-Egg phone scripts remain
|
|
unsupported.
|
|
|
|
## Capture and the catching tutorial: 2026-09-24
|
|
|
|
Continued the roadmap with the first refusal remaining in the opening quest.
|
|
|
|
- Battle PACK opens the Balls pocket and runs `PokeBallEffect`: the Poké,
|
|
Great, Ultra and Master Ball multipliers, the original HP arithmetic
|
|
(including the overflow above 341 maximum HP), the sleep/freeze bonus
|
|
(BRN/PSN/PAR add nothing), `HELD_CATCH_CHANCE` and the catch draw.
|
|
`GetPokeBallWobble` draws per shake from `WobbleProbabilities` and picks
|
|
the break-free text. Trainer battles block the ball but still use it and
|
|
the turn. `catchRate` is exported for pure vectors.
|
|
- A catch reloads the Pokémon as `LoadEnemyMon` does (the wild item roll is
|
|
redrawn, then the original item restored), keeps HP/status/item/DVs,
|
|
restores the moves and PP it appeared with, adds it to the party with
|
|
`SetCaughtData`, registers it and offers a nickname (`InitName` default
|
|
for blank names). `NewDexDataText` shows when the Pokédex is owned.
|
|
`caughtData` is now shared with `givepoke`.
|
|
- `catchtutorial` runs `BATTLETYPE_TUTORIAL`: "DUDE" from the ROM as
|
|
`<PLAYER>`, no send-out, an automatic catch that keeps nothing, and
|
|
prompts that continue on their own. Both Route 29 triggers, declining and
|
|
`CatchingTutorialDudeScript`'s repeat offer run from the ROM.
|
|
- Text: `TX_LOW` ($05) is read as a line break (`ItemUsedText` needs it).
|
|
- UI: PACK lists the Balls pocket (B closes it); the in-battle nickname
|
|
prompt reuses the naming field. The help dialog and README describe the
|
|
current milestone.
|
|
- Refused: a catch with six Pokémon (the PC is not ported), other balls,
|
|
non-ball items in battle and a transformed target.
|
|
- Stress (local, not committed): 2,160 wild battles, 2,047 catches, no
|
|
refusals.
|
|
|
|
Checks: 207 unit tests with the local ROM (82 passed, 125 skipped without
|
|
it); 54 Chromium/WebKit browser tests; native and reference builds;
|
|
reference, release and vendor checks; `git diff --check`. The existing
|
|
keyboard/D-pad test now steps through the enabled PACK button. No
|
|
emulator comparison of the capture routines was run. Not committed.
|
|
|
|
Next: the PC and boxes (catching with a full party, `SendMonIntoBox`, Bill's
|
|
call), then player switching and other items in battle, and party and bag
|
|
menus. The Dude's back picture, ball animation and Pokédex page are not
|
|
presented.
|
|
|
|
|
|
## Overworld foundation recovery: 2026-09-25
|
|
|
|
Resumed Claude Code session `5d15e2b5-2020-4f49-83e7-eddee08c2315`, whose user
|
|
request was “Complete the overworld foundation.” Its last successful check
|
|
compared Johto and Ice Path animation with the original VRAM; the session then
|
|
hit its usage limit. The previous handoff ended at capture and was stale.
|
|
|
|
Preserved and validated Claude's uncommitted implementation:
|
|
|
|
- Turn delays, bumps, ice and currents, forced movement, dynamic return warps,
|
|
elevator menus, pits and arrival timing. Six original-engine traces cover
|
|
outdoor, connected, ledge, interior, scripted-follow and cave movement.
|
|
- Surf, Cut, Strength, Whirlpool/Waterfall interaction paths and cycling rules;
|
|
Strength boulders can fall into script-controlled holes. Later maps are
|
|
enabled only inside tests, not in the production map list.
|
|
- Working map blocks, `changeblock`, `changemapblocks`, rollback and minimap
|
|
invalidation; cave/water/Kanto encounter tables and `wildoff`.
|
|
- Additional NPC movement, variable sprites and Pokémon icons; all movement
|
|
command decoding and teleport/fishing/skyfall/shake/flicker presentation.
|
|
- Tileset animations on private graphics, grass sprite priority and special
|
|
map palettes. Johto and Ice Path match 96 original VRAM frames after matching
|
|
the reference animation state, including the scrolling scratch buffer.
|
|
|
|
Recovery changes:
|
|
|
|
- Removed `zz-grid.test.ts` and `zz-explore.spec.ts`, temporary diagnostics with
|
|
no assertions. The grid diagnostic also read a private ROM unconditionally.
|
|
- Added grass-priority/transparency and special-palette regressions, and ran
|
|
all 36 tilesets for 2,048 animation frames each while checking that cached
|
|
ROM graphics stay unchanged. `NUM_TILESETS` is verified by `check:reference`.
|
|
- Reconciled PLAN, ARCHITECTURE and NATIVE_PORT with the actual implementation
|
|
and its remaining gaps.
|
|
|
|
Validation: 271 unit tests passed with the local ROM. With an absent
|
|
`CRYSTAL_ROM_PATH`, 127 passed and 144 skipped. The full Chromium/WebKit run
|
|
passed 64 tests with 8 intentional WebKit skips; two of those passes were the
|
|
subsequently removed exploratory test, leaving 62 substantive browser checks.
|
|
The eight new original-engine comparisons run in Chromium only. Native and
|
|
reference builds, reference addresses/constants, release isolation and vendor
|
|
checks passed. No physical-device or CI run was performed. Changes remain
|
|
uncommitted; no push was made.
|
|
|
|
The whole foundation milestone is not complete. Continue with:
|
|
|
|
1. Room decorations: the two decoration specials still implement empty slots;
|
|
stored choices, ownership and the selection flow are absent.
|
|
2. Player bag-menu access to `GameWorld.useBicycle()`. Its rules are tested,
|
|
but it is not reachable through the current game controls.
|
|
3. Remaining reference acceptance: movement traces exclude the original's
|
|
map-entry tick and compare position/facing/selected actor positions, not
|
|
event flags. Most special poses and palettes lack executed-reference or
|
|
screenshot comparisons. The Celebi forest animation stays on frame one.
|
|
|
|
Do not clear those checklist items or enable later maps based on the existing
|
|
movement and rendering tests alone.
|
|
|
|
|
|
## Overworld foundation completed: 2026-09-25 (resumed from Codex)
|
|
|
|
After the recovery above, Codex continued with "Complete the foundation" and
|
|
stopped during its final validation, before updating this file. It had
|
|
already marked the milestone done in PLAN.md. Its work:
|
|
|
|
- Room decorations (`world/decorations.ts`): the initial bed and Town Map
|
|
poster, ownership through `DecorationAttributes` event flags, the bedroom
|
|
PC's selection and put-away flows (including left/right doll placement),
|
|
room blocks and variable sprites from saved choices, save validation and
|
|
migration of saves without decorations. The poster opens the native map.
|
|
- Start/Select opens Key Items; the Bicycle follows the native indoor and
|
|
outdoor rules, with keyboard and touch controls (`foundation-browser.spec.ts`).
|
|
- Movement traces now compare event flags as well as positions. Pose checks
|
|
compare direction, visibility and vertical offset during scripted
|
|
movement. An executed `LoadMapPals` matches 192 native palette cases.
|
|
Restless Ilex Forest and Tin Tower animation match original VRAM.
|
|
- Fixed fishing and flicker pose timing against the original routines.
|
|
|
|
Claude Code finished the increment. Codex had just added two pose traces.
|
|
Tree shake passed. Skyfall departure (`skyfall_top`) failed:
|
|
`StepFunction_SkyfallTop` leaves `OBJECT_SPRITE_Y_OFFSET` at $60 on the tick
|
|
that ends the command, and the offset persists through later steps. Actors
|
|
now keep a `yOffset`. Skyfall, teleports, the fishing bite and jumps clear it,
|
|
because those routines write the offset again. In the game, only the player
|
|
uses `skyfall_top` (Ruins of Alph chambers, Burned Tower), just before a warp.
|
|
The traces now number fourteen. PLAN and NATIVE_PORT were updated to match.
|
|
|
|
Checks: 276 unit tests with the local ROM (127 passed, 149 skipped without
|
|
it); 81 Chromium/WebKit browser tests passed and 19 were skipped intentionally
|
|
(the engine parity tests run in Chromium only); native and
|
|
reference builds; reference, vendor and release checks; `git diff --check`.
|
|
Not committed.
|
|
|
|
Next (PLAN section 2): the PC and boxes (a catch with a full party,
|
|
`SendMonIntoBox`, Bill's call), then the introduction's naming and clock
|
|
screens. Also open there: player switching and non-ball items in battle,
|
|
controlled-seed comparisons beyond damage and type effectiveness, and a
|
|
continuous opening-quest playthrough with save/reload. Later maps stay gated
|
|
until their scripts and story are supported.
|
|
|
|
## The PC and boxes: 2026-09-25
|
|
|
|
The foundation above was committed and pushed as `451464f`. This increment
|
|
continues PLAN section 2 with its first open item.
|
|
|
|
- `party/storage.ts`: 14 boxes of `BoxMon` (a party struct without status,
|
|
HP and stats), the current box, box names (null is the ROM's "BOX" and
|
|
number) and 50 PC item stacks. `SendGetMonIntoFromBox` deposit and
|
|
withdraw, `RestorePPOfDepositedPokemon` and `CalcLevel` are shared helpers.
|
|
`maxPP` (ComputeMaxPP) now also serves `HealParty`.
|
|
- `scripts/pc.ts`: `PokemonCenterPC` and the house PC. The Pokémon Center PC
|
|
opens Bill's PC (deposit, withdraw, release, change and name boxes) and the
|
|
player's PC (item withdraw, deposit and toss, the empty mail box), plus
|
|
Oak's rating once the Pokédex is owned. The house PC adds DECORATION. Menu
|
|
strings, lists and texts are read from the ROM (`PC` table in the profile,
|
|
verified by `check:reference`). The generic menu effect gained per-item
|
|
`details` (levels, box counts). A `notice` effect covers unported
|
|
options without aborting.
|
|
- Facing tiles now use the ROM's `TileCollisionStdScripts` in any direction,
|
|
as in the original (the old table only fired when facing up).
|
|
- Capture with a full party: `SendMonIntoBox` puts the catch first in the
|
|
current box, with nickname and `BallSentToPCText`. A full box keeps the ball
|
|
(`Ball_BoxIsFullMessage`). Filling the box sets `BATTLERESULT_BOX_FULL`.
|
|
`reloadmapafterbattle` then queues Bill's call through a new `memscript`
|
|
effect (`LoadMemScript`). It is kept in memory only and runs before scene
|
|
scripts.
|
|
- Save format 3 gained `storage` and `pcItems`, migrated by absence.
|
|
|
|
Not ported: MOVE PKMN W/O MAIL and the stats screen (notices), printing,
|
|
`givepoke` with a full party (still refused; unreachable in the open maps),
|
|
the save messages after a box switch, and the tutorial with a full party and
|
|
box (the original loops forever; refused).
|
|
|
|
Checks: 290 unit tests with the local ROM (130 passed, 160 skipped without
|
|
it); 83 Chromium/WebKit browser tests passed, 19 skipped intentionally
|
|
(including a new Pokémon Center PC flow in both browsers); native and
|
|
reference builds; reference, vendor and release checks; `git diff --check`.
|
|
Not committed.
|
|
|
|
Next (PLAN section 2): the introduction's naming and clock screens; player
|
|
switching and non-ball items in battle; MOVE PKMN W/O MAIL and the stats
|
|
screen with the party menu; a continuous opening playthrough.
|
|
|
|
## The introduction's naming and clock: 2026-09-25
|
|
|
|
The PC increment above was committed as `3bdca00`. This increment finishes
|
|
the next open item of PLAN section 2.
|
|
|
|
- `scripts/intro.ts` (`IntroRun`): `InitGender`, `OakSpeech` with
|
|
`InitClock` and `NamePlayer`, as a native generator the world runs like a
|
|
script (`GameWorld.beginIntro`). Texts, menus, preset names and time
|
|
strings come from the ROM through a new `INTRO` profile table verified by
|
|
`check:reference`.
|
|
- New effects: `portrait` (Oak's trainer picture or the player's, decoded
|
|
by `PokemonData.trainerPic`, `playerPic` and `trainerPalette`) and a
|
|
`clock` stepper choice.
|
|
- Game clock: `clock.minuteOffset` is added to the device time for time of
|
|
day, weekday, NPC hours and the daily reset. The host's `deviceWeekday`
|
|
became `clockDay`.
|
|
- `GameSession.load` calls the runtime's optional `newGame()` when nothing
|
|
is saved. Saves gained `intro` (true while pending; a save made then
|
|
restarts the introduction). The shell's name/character fields are gone.
|
|
- Browser fixture specs strip `this.world?.beginIntro();` from the served
|
|
runtime, since their worlds stand in for saved sessions. Fresh-load tests
|
|
play the intro with `tests/intro-driver.ts`.
|
|
|
|
Not presented: palette fades, Wooper's cry, the picture slide while
|
|
naming, `ShrinkPlayer` and music. Intentional change: the steppers start at
|
|
the device time instead of 10:00.
|
|
|
|
Checks: 298 unit tests with the local ROM; native and reference builds;
|
|
reference, vendor and release checks; `git diff --check`; 87
|
|
Chromium/WebKit browser tests passed, 19 skipped intentionally (including
|
|
the new intro flow and a reload during it, in both browsers). Committed and
|
|
pushed to `main` as `b13fd20`.
|
|
|
|
Next (PLAN section 2): player switching and non-ball items in battle; MOVE
|
|
PKMN W/O MAIL and the stats screen with the party menu; a continuous opening
|
|
playthrough.
|
|
|
|
## Remaining opening-milestone items: 2026-09-30
|
|
|
|
The introduction was committed and pushed as `b13fd20` (handoff note
|
|
`eb03a20`). Asked to go over what was left and do the quickest items
|
|
first, this session took PLAN section 2's open items in that order:
|
|
|
|
1. Evolution decoder: `PokemonData.evolutions` returns typed level, item,
|
|
trade, happiness and stat records (Tyrogue's are four bytes). A
|
|
local-ROM test compares all 251 lists with the pinned
|
|
`evos_attacks.asm`. Evolving is not ported.
|
|
2. Reference vectors: `tests/reference-parity.spec.ts` now also calls the
|
|
original `CalcMonStats` (300 cases, including levels above 100 for the
|
|
999 cap; the trampoline sets BC, DE and HL) and `CalcExpAtLevel` (all
|
|
600 growth/level pairs). A mutation (removing the cap) was confirmed to
|
|
fail. Symbol loading and the ROM hand-off are shared helpers now. The
|
|
checklist item stays open for random-driven routines (accuracy,
|
|
criticals, damage variation, capture).
|
|
3. Continuous playthrough: `tests/playthrough.test.ts` plays a new game
|
|
from the intro to the catching tutorial through `GameWorld` inputs with
|
|
a seeded RNG, reloading a JSON save after every stage. Wild battles are
|
|
fought, or fled below half HP (fighting everything whited out on Route
|
|
29). The rival battle is lost with this seed (`CANLOSE`), and the story
|
|
continues. The stages share one world, so run the whole file.
|
|
4. Switching and healing items in battle (details in NATIVE_PORT):
|
|
- PKMN/`TryPlayerSwitch`/`PlayerSwitch`/`BattleMonEntrance` with
|
|
`SendOutMonText`/`WithdrawMonText`; `AskUseNextPokemon`,
|
|
`ForcePlayerMonChoice`, `DoubleSwitch`; Shift mode's
|
|
`OfferSwitch`. New `party` prompt (`menu`, `cancel`) answered through
|
|
`battleChoose` (a slot or -1), and `{ action: "pkmn" }`.
|
|
- Items pocket: `CheckItemContext`, `ItemEffects` dispatch by ROM
|
|
address, `RestoreHPEffect` and `StatusHealingEffect` with the ROM's
|
|
tables and party menu texts. `PARTYMENUTEXT_*` values are PRET's
|
|
($F0-based; `check:reference` caught a wrong value).
|
|
- UI: PKMN party list with the SWITCH/STATS/CANCEL submenu (STATS
|
|
disabled), and ITEM/BALL POCKET tabs in PACK (opens on Items). The
|
|
keyboard test now passes through the enabled PKMN button.
|
|
|
|
Known limits: `hBattleTurn` at the battle menu is not modelled everywhere,
|
|
so a status heal that would make `CalcPlayerStats` reapply a penalty to a
|
|
paralysed or burned enemy is refused. `WithdrawMonText` treats the
|
|
multiplicand's leftover high byte as zero. X items, Poké Doll, Full
|
|
Restore, revives and the stats screen are not ported.
|
|
|
|
Checks: 324 unit tests with the local ROM (130 passed, 194 skipped
|
|
without it); 93 Chromium/WebKit browser tests passed, 19 skipped
|
|
intentionally; native and reference builds; reference, release and
|
|
vendor checks; `git diff --check`. Committed and pushed to `main` as
|
|
`f8e0f9c`.
|
|
|
|
Next (PLAN section 2): controlled-seed comparisons of random-driven
|
|
battle routines. Then PLAN section 3/4 items: the party and bag menus
|
|
outside battle (with the stats screen and MOVE PKMN W/O MAIL), evolution
|
|
itself, and the remaining battle items.
|
|
|
|
## Battle items, hBattleTurn and the stats screen: 2026-09-30
|
|
|
|
After `f8e0f9c`/`cfd083c`, the user asked for the items the previous
|
|
summary listed as refused or not ported:
|
|
|
|
- Every non-ball item effect usable in battle, found by reading each
|
|
item's battle context and `ItemEffects` entry from the ROM: Full
|
|
Restore, Revive/Max Revive, Energypowder, Energy Root, Heal Powder,
|
|
Revival Herb, Bitter Berry, Ether/Max Ether/Elixer/Max Elixer/
|
|
MysteryBerry (new `move` prompt), X items, X Accuracy, Guard Spec, Dire
|
|
Hit and Poké Doll. `ChangeHappiness` now reads `HappinessChanges`
|
|
(including the `wPartyMenuCursor` quirk), which also fixed level-ups:
|
|
`LevelUpHappinessMod`'s larger gain where the Pokémon was caught was
|
|
missing (new `landmark` battle option). A second participant set
|
|
(`wBattleParticipantsIncludingFainted`) serves revives.
|
|
- `hBattleTurn` at the battle menu: `DoBattle` ends on the player's turn,
|
|
full turns end on the enemy's, and `chooseTrainerMove` now returns
|
|
`enemyTurn` when `AI_Types`, `AI_Status` or `AIDamageCalc` ran. The
|
|
status-heal refusal is gone; the enemy's penalty is reapplied as in the
|
|
original.
|
|
- Stats screen: three pages from ROM strings (`STATS` profile table,
|
|
verified by `check:reference`), `TypeNames` and `GetGender`. It opens from
|
|
BattleMonMenu and from Bill's PC (a `stats` script effect;
|
|
`world.statsScreen`).
|
|
- Emulator comparisons: a new reference test runs `SendOutMonText` (with
|
|
its final `jp BattleTextbox` patched to `ret` in the in-page ROM copy),
|
|
`WithdrawMonText`'s text routine, `RestoreHealth` (with `wHPBuffer1` set
|
|
as `ItemRestoreHP` leaves it), `RestorePP`, `ChangeHappiness` and
|
|
`CalcPlayerStats` with both turns. A mutation of `calcPlayerStats` was
|
|
confirmed to fail. The pure helpers are exported from `battle.ts`.
|
|
|
|
Remaining: Kurt's and the Park Ball; the leftover multiplicand byte in
|
|
`WithdrawMonText` is assumed zero; no whole battle has been compared with
|
|
the original.
|
|
|
|
Checks: 337 unit tests with the local ROM (131 passed, 206 skipped
|
|
without it); 97 Chromium/WebKit browser tests passed, 19 skipped
|
|
intentionally; native and reference builds; reference, release and
|
|
vendor checks; `git diff --check`. Committed and pushed to `main` as
|
|
`b13e09e`.
|
|
|
|
## Controlled random battle comparisons: 2026-09-30
|
|
|
|
Resumed from `be7575a` with a clean working tree. The user requested a bounded
|
|
increment suitable for a limited session. Continued PLAN section 2 with
|
|
accuracy, criticals and damage variation; capture stays as the next item.
|
|
|
|
- `tests/reference-random.spec.ts` runs the original, unpatched
|
|
`BattleCommand_Critical`, `BattleCommand_CheckHit` and
|
|
`BattleCommand_DamageVariation` in the reference emulator. The native
|
|
commands receive the same ten-byte Link RNG stream. Results include the
|
|
final RNG stream/cursor, so extra or missing draws are detected too.
|
|
- Per browser: 2,560 critical cases (all random bytes at all five reachable
|
|
stages and held-item exceptions), 2,914 accuracy cases (all stage pairs,
|
|
Foresight, BrightPowder, bypasses, Dream Eater/substitute and Jump Kick
|
|
miss damage), and 2,149 variation cases (0/1, rounding, 16-bit boundaries,
|
|
rejected draws and RNG stream regeneration).
|
|
- Shared ROM input and symbol helpers moved from `reference-parity.spec.ts`
|
|
into `tests/reference-fixture.ts`. No ROM bytes or extracted assets added.
|
|
- Deliberately changing critical `<` to `<=`, accuracy `>=` to `>`, and the
|
|
damage divisor from 255 to 256 each made its comparison fail. All three
|
|
mutations were reverted; no production gameplay change was needed.
|
|
|
|
Boundary: these compare isolated commands with controlled random inputs.
|
|
They do not compare a whole battle, the hardware-timed non-Link RNG, or the
|
|
Protect text path. Lock-On/Fly/Dig remain refused. This does not enable Link
|
|
battles or later maps.
|
|
|
|
Checks: 337 unit tests passed with the local ROM; 131 passed and 206
|
|
skipped with an absent ROM. All 103 Chromium/WebKit browser tests passed,
|
|
with the existing 19 intentional WebKit skips. Native and reference builds,
|
|
reference, vendor and release checks, and `git diff --check` passed. No CI
|
|
or physical-device run. This increment was initially left uncommitted and
|
|
is included in the subsequent capture-comparison delivery below.
|
|
|
|
Next: controlled-input capture comparisons (`PokeBallEffect` and
|
|
`GetPokeBallWobble`), then the party/bag menus outside battle, MOVE PKMN W/O
|
|
MAIL and evolution. Keep section 2's capture checklist open until verified.
|
|
|
|
|
|
## Controlled capture comparisons: 2026-09-30
|
|
|
|
Continued PLAN section 2 from the existing uncommitted accuracy, critical and
|
|
damage-variation comparisons. Preserved that work and completed its next
|
|
capture-comparison item.
|
|
|
|
- `tests/reference-capture.spec.ts` compares the native capture decision with
|
|
the calculation inside `PokeBallEffect`, then its shake loop with
|
|
`GetPokeBallWobble`. Per browser: 3,220 capture cases and 7,424 shake cases,
|
|
including supported ball multipliers, all catch-rate bytes, HP scaling and
|
|
overflow, status bonuses, equality boundaries, every random byte at each
|
|
wobble-table entry, every escape count and guaranteed catches. Final rate,
|
|
caught/escaped outcome, shake count and random-draw count agree.
|
|
- Capture uses hardware `Random`, not `BattleRandom`. The private in-page ROM
|
|
copy replaces `Random` with a supplied-byte reader; the fixture enters
|
|
after the UI setup and inserts a return after `wWildMon` is written.
|
|
Catch arithmetic, multipliers and `GetPokeBallWobble` remain unmodified.
|
|
- Extracted `rollCapture` and `ballWobbles` as private production helpers
|
|
called by `pokeBallEffect`, without changing gameplay behavior. Added
|
|
maximum HP 683 beside 342 in the synthetic divide-by-zero regression.
|
|
- Deliberately changing success `<=` to `<`, formula floor to ceiling, and
|
|
shake `>=` to `>` each failed the comparisons. Mutations were reverted.
|
|
|
|
Boundary: isolated capture decision/shakes with supplied random bytes, not
|
|
hardware RNG timing, animation, caught-mon reloading, party/PC writes or a
|
|
whole battle. No actual item has `HELD_CATCH_CHANCE`; that effect remains
|
|
covered by pure vectors. Native division-by-zero refusal remains in place;
|
|
the emulator fixture omits the hanging HP inputs. No additional balls or
|
|
maps are enabled.
|
|
|
|
Checks: 337 unit tests passed with the local ROM; 131 passed and 206 skipped
|
|
with an absent ROM. All 107 Chromium/WebKit browser tests passed, with the
|
|
existing 19 intentional WebKit skips. The four new capture tests skip cleanly
|
|
without a ROM. Native and reference builds, reference, vendor and release
|
|
checks, and `git diff --check` passed. No CI or physical-device run.
|
|
The accuracy, critical, damage-variation and capture comparisons were committed
|
|
together as `00972ba` and pushed to `origin/main`; the remote commit was
|
|
verified. This handoff-only follow-up records that delivery.
|
|
|
|
Next: party and bag menus outside battle, MOVE PKMN W/O MAIL and evolution.
|
|
PLAN section 2 is complete within its recorded acceptance boundaries.
|