Commit graph

8 commits

Author SHA1 Message Date
acamilo
349a1fd28c Merge fix/loop-row50: a battle turn is the fly's only while the move list is drawn 2026-09-22 22:13:08 +00:00
dev
6588897ab3 docs: a menu is up while its box is on screen (section 12.18, row 50)
macros.md gains 12.18 and macros-wram.md a section 10 for the accessor and the
survey that found it: press at every battle frame with a rollback pulse, and
ask every byte of WRAM and HRAM which of them separates a honoured press from
a refused one.

The half of row 50 that was wrong is where the fix is. The move list was not
drawn: MoveSelectionMenu's cursor bytes are never cleared and SelectMenuItem
decrements wCurrentMenuItem back into the one-based range on its way out, so a
turn's whole text and animation read as an open list with a placeable cursor.

The battle bag is the same trap on wListMenuID and is named rather than fixed,
because the figure that tells its list from the frame after it closes has not
been surveyed yet.
2026-09-22 18:43:05 +00:00
acamilo
a8afd8f448 Merge feat/catch-reward: a catch reward, adapter v6 with a v5 migration, and a rung restart 2026-09-22 18:41:15 +00:00
alex
23a4d7379b rewards: a catch reward, adapter v6 with a v5 migration, and a rung restart
The operator's decision of 2026-09-22: pay the fly for keeping a wild Pokemon,
bump the adapter properly, and restart the live run from an early checkpoint
rather than from scratch.

The rule. `catch` is the catalog's ninth kind, appended so the key order
`counts` serializes in does not move. 0.30 for a species this run had never
owned, 0.10 for a repeat, three payouts per species for the lifetime of the
ledger; the `species` rule is untouched, so a first catch of a new species pays
0.80 across two kinds. The catch is read from `wCapturedMonSpecies` ($d11c),
whose comment in ram/wram.asm is "0 if no mon was captured": ItemUseBall zeroes
it before every throw and writes wEnemyMonSpecies into it only on the branch
that keeps the Pokemon, and UseBagItem's `.returnAfterCapturingMon` zeroes it
again and sets wBattleResult to 2 -- a value written on exactly two paths in
the game, that one and a link battle whose opponent ran. Both are required, so
a byte read out of a half-initialised battle cannot pay. Not wPartyCount: a
catch with a full party raises wBoxCount instead, and wPartyCount also rises
for a gift, a trade and a PC withdrawal.

"Never owned this run" is the `species` payout inside the same battle, because
nothing else can set a Pokedex bit during one. It is not read off the captured
species byte: that is the cartridge's internal index while the owned bitset is
by Pokedex number, and nothing in WRAM converts between them.

The address was resolved by tools/resolve_wram.py, not written by hand. The
tool needed NUM_TMS and NUM_HMS, which the decomp defines through its `const`
enumeration, so it now counts them from the file's own add_tm/add_hm
definitions and cross-checks NUM_TMS against the literal the same file
declares.

The feed's kinds are closed, so `catch` publishes on `wildwin` and nothing in
packages/feed or apps/stage changed. Deliberately not `pokedex`: the `species`
rule already pays for the bit the same catch sets. The stage's ticker copy is
keyed on the feed kind, so a catch row reads "wild win" -- stated in
docs/rewards-learning.md rather than left to be discovered.

v5 -> v6. STATE_VERSION stays 4: the rule adds one counter, `catchCounts`, and
changes nothing else, so a v5 state restores with it empty. That migration is
opt-in and needs all three of: the adapter segment being the only difference
between the two compatibility strings, the running adapter listing the
checkpoint's adapter in `migrates_from()`, and the deploy naming it in
FLY_ACCEPT_ADAPTERS. flysim applies the rule at restore and 05-deploy's gate
applies the same rule before it flips the symlink, writing the variable into
fly.env so the two cannot disagree.

The restart. infra/bin/fly-reset-to-milestone <N> archives both stores to a
dated directory, rewrites milestone-<N>.checkpoint with the ratchet's attempts
and recoveries at zero, installs it as the newest generation of both stores,
clears the milestone archives above N and the event log, and prints what it
did. It refuses while flysim is running and refuses a rung the run never
reached. The envelope work is in flysim::reset (`flysim
--reset-to-milestone N`); the shell script is the operator's wrapper.

Tests: catalog values and order; a synthetic WRAM trace of a catch (new,
repeat, cap, already-owned species, trainer/Safari/old-man/missed-ball
negatives, rollback replay); a v5 state restoring with the counter at zero; a
v5 checkpoint fixture accepted with the opt-in and refused without it; the
reset tool against copies of a state dir in temp directories; and a ROM-gated
catch from a rung-9 forest checkpoint, driven by the shipping THROW BALL macro.

The compatibility string differs from main's in exactly one segment, checked by
splitting both on `/`: pokered-unique8-v5 -> pokered-unique8-v6.
2026-09-22 17:30:00 +00:00
acamilo
bffbaca394 docs: row 54, the mid-step survey and both arms of the hunt
macros.md gains section 12.17; macros-wram.md section 9 gains the frame-by-frame trace of a step,
the three readings that come out of it and the one byte that tracks a step exactly and is recorded
unused; macros-traps.md closes rows 54 and 54b, strikes the two residuals they worked, and prints
both checkpoints' before and after whole -- including the arm where the ethos check's "fewer
flagged windows, more distinct tiles" does not hold, and why.
2026-09-22 17:19:25 +00:00
acamilo
5b9f5a54ca docs: section 12.12, the nurse's box
What was live, what the survey read, and what the three candidate
readings in the brief turned out to be: not the prompt, not HEAL, but the
dialog pad dealt unconditionally with TALK to get back into it. The
scene-by-scene table splits the dialog row in two and the pad-empty sweep
gains the reopen ledger's own residual. macros-wram.md narrows its "no
observable for a choice" claim rather than withdrawing it.
2026-09-22 10:39:15 +00:00
claude
b9e01dea5b docs: macros.md section 15 and the WRAM table behind it
Section 15 is the contract for map-aware walks: what is decoded, the one ROM
read and why it is a read of the cartridge image, what the window fallback is
for and how it says so, and the proof. macros-wram.md section 9 is the bytes --
four addresses with their encodings, the bank-aware read on the seam, the corner
the cartridge settled, the two gates against a plausible-but-wrong decode, and
the survey of Pallet Town and Viridian Forest.
2026-09-22 04:21:54 +00:00
acamilo
660c3cf00d flybrain v0.4.0: public tree (history retained privately)
Some checks failed
ci / node 22 (test + typecheck) (push) Has been cancelled
ci / rust stable (cargo test --workspace --release) (push) Has been cancelled
ci / infra/tests/lint.sh (push) Has been cancelled
ci / playwright apps/stage (allowed to fail) (push) Has been cancelled
2026-09-21 15:09:46 +00:00