formats+tools: the counter's neighbours are its own rendered digits

With the per-entity searches refuted at word and bit level, the question became
which object owns the counter. Sampling +-0x200 around it across a 4->8
transition: the control interval moved 0 of 256 words, and the step moved nine -
the counter plus four words holding ASCII '4' -> '8' NUL-padded, and four
pointers into 0xbcad2xxx that swap with them. Read live at HUD 008, all four
character slots hold '8'.

So the neighbourhood is the HUD's rendered text for this counter, which reframes
the address: it is the HUD widget's value rather than "the mission's own
objective counter" as this file called it.

Recorded against that, because it is already measured: there is no separate
mission-side copy moving on the same step. ob_hunt scans all of guest memory and
requires a match across two transitions, and it left exactly one address.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Sylpheed RE agent
2026-08-24 09:48:57 +00:00
parent 01468b804a
commit ac17398515
3 changed files with 208 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
{
"counter_va": 3182794344,
"n0": 4,
"n1": 8,
"hud_b": 8,
"noisy_words": 0,
"moved": [
{
"va": 3182794044,
"delta_from_counter": -300,
"before": 872415232,
"after": 939524096
},
{
"va": 3182794060,
"delta_from_counter": -284,
"before": 872415232,
"after": 939524096
},
{
"va": 3182794076,
"delta_from_counter": -268,
"before": 3165464588,
"after": 3165463948
},
{
"va": 3182794108,
"delta_from_counter": -236,
"before": 3165463948,
"after": 3165464588
},
{
"va": 3182794344,
"delta_from_counter": 0,
"before": 4,
"after": 8
},
{
"va": 3182794444,
"delta_from_counter": 100,
"before": 872415232,
"after": 939524096
},
{
"va": 3182794460,
"delta_from_counter": 116,
"before": 872415232,
"after": 939524096
},
{
"va": 3182794476,
"delta_from_counter": 132,
"before": 3165466508,
"after": 3165465868
},
{
"va": 3182794508,
"delta_from_counter": 164,
"before": 3165465868,
"after": 3165466508
}
]
}

View File

@@ -198,3 +198,45 @@ not able to look often enough.
**Still open, and untouched:** ❔ what the counter counts, and whether an
`OB`-badged entity carries a flag in its entity object. That is the part the
autopilot actually needs, and knowing the address is only its precondition.
## ✅ 2026-08-24 — what is AROUND the counter: its own rendered digits
With the per-entity searches refuted at both word and bit level
(`../mission-freeze-and-ob-flag.md`), the next question was what object owns the
counter. It sits at `0xbdb59668`, inside the entity-heap window, so the answer is
readable directly: sample ±0x200 around it across one transition and keep the
words that move **with** it
([`ob_neighbourhood.py`](../../tools/re-capture/ob_neighbourhood.py),
[`captures/ob-counter-neighbourhood-stage02.json`](../captures/ob-counter-neighbourhood-stage02.json)).
Control first: over an 8-second interval while the counter sat still, **0 of the
256 words in the window changed**. So the window is quiet, and anything that
moves on the step is a real neighbour rather than noise.
On `4 → 8`, **nine** words moved — the counter and eight others, in two kinds:
| offset from the counter | before → after | what it is |
|---|---|---|
| `-0x12c`, `-0x11c`, `+0x64`, `+0x74` | `0x34000000 → 0x38000000` | **ASCII `'4'` → `'8'`**, NUL-padded |
| `-0x10c`, `-0xec`, `+0x84`, `+0xa4` | `0xbcad258c ↔ 0xbcad280c`, `0xbcad2d0c ↔ 0xbcad2f8c` | guest pointers into `0xbcad2xxx` |
Read live a moment later with the HUD showing `008`, all four character slots
hold `'8'`. So the neighbourhood is the **HUD's rendered text for this counter**
the digit as a character in four places, each with a pointer that swaps as the
digit changes (a glyph or sprite record).
### 🟡 Which reframes what the address IS
This file has called `0xbdb59668` "the mission's own objective counter". The
evidence now says something narrower: it is **the HUD counter widget's value**,
sitting beside the characters it renders.
🔴 **But there is no separate mission-side copy that moves with it**, and that was
already measured: `ob_hunt.py` scans *all* of guest memory and requires a
candidate to match across two transitions, and it left **exactly one** address.
Whatever the mission script keeps internally either does not change on the same
step or is not a plain big-endian word.
**Next:** follow one of the `0xbcad2xxx` pointers — if they resolve to glyph or
sprite records, the widget is confirmed and the search for a mission-side count
moves to the objects those digits are *fed from*.