re(achievements): earned state comes from XAM, and my bit numbering was wrong
Two findings, one of them a correction to the previous commit. FOUND: GamePart_Debriefing enumerates XACHIEVEMENT_DETAILS from XAM (0x8218F888). The records are 36 bytes -- confirmed by the arithmetic, not by eye: the count is a byte count divided by 36 through the 0x38E38E39 multiply-high magic plus srawi 3. Field +0 is used as a shift amount, field +32 is tested for 0x00020000, and the buffer sits behind a handle that is waited on (0x824AA330 with -1) then closed (0x824AA3E0). That is the XDK struct exactly, with XACHIEVEMENT_DETAILS_ACHIEVED == 0x20000, via the XamUserCreateAchievementEnumerator / XEnumerate pattern. So the title does NOT persist earned achievements itself -- it asks the console. The lever for achievement-gated content is the emulator's PROFILE data, not the savegame. Independently, the singleton the challenge gate reads is not the object holding the save block: re-scanning all 202 accessor call sites WITH function- boundary stops touches only +80/+1956/+1960/+1964 and none of the known save offsets (+304/+316/+320/+336/+380/+440). The earlier scan that seemed to find them had register tracking bleeding into the next function -- a false positive I am recording rather than quietly dropping. CORRECTED: the previous commit claimed "bit n <-> achievement n+1" and treated the Debriefing award pass and the challenge gate as the same bit space, both as confirmed. Neither holds up: - the only place the image is observed turning an achievement into a bit does 1 << dwId with 1-based ids, so bit = the id and bit 0 is unused; - the "list index is the bit index" step assumed 0x82448338's out-parameter is the loop ordinal. It is the child entry's first word out of a 12-byte array, and whether that is an ordinal, an id or a name hash is not pinned; - the Debriefing's masks are its own fields (+208/+736/+740). Nothing observed copies them into the singleton's +80, and no writer of that bitmask has been found at all. The requirement-type/id agreement still stands, but it confirms the LIST ORDER, not the bit numbering. Consequence: if the join holds, TimeAttack's REQUIREMENT 16 is achievement 16 (Night Ravens Patch), not 17 (Solar System Defense Award). Both read plausibly as a first-challenge gate, which is exactly why it needs evidence and not the better story. Also noted: +1960 is a third bitfield on the same singleton, and a what-changed pass at 0x8219F3A4 diffs it and reports each newly set bit as bit + 64 -- so there is a wider flag-id space whose bases are not yet worked out.
This commit is contained in:
@@ -173,9 +173,16 @@ resource holds the matching 24 achievement definitions, summing to **1000G**, th
|
||||
retail total. Full table and record layout:
|
||||
[`structures/achievements.md`](structures/achievements.md).
|
||||
|
||||
So **word A (`+80`) is the earned-achievement mask** (bit `n` = achievement `n+1`),
|
||||
and **word B (`+1956`) is a second, different flag space** that requirement values
|
||||
`≥ 24` index as `bit n-24`.
|
||||
So **word A (`+80`) reads as the earned-achievement mask** and **word B (`+1956`) as a
|
||||
second, different flag space** that requirement values `≥ 24` index as `bit n-24`.
|
||||
|
||||
⚠️ **Corrected the same day:** an earlier draft said "bit `n` = achievement `n+1`" and
|
||||
called the join ✅. Both were over-claimed. The Debriefing's masks live on the
|
||||
*Debriefing* object (`+208`/`+736`/`+740`), nothing observed copies them into the
|
||||
singleton's `+80`, and the one place the image is *seen* turning an achievement into a
|
||||
bit does `1 << dwId` with **1-based** ids. So the mapping is 🟡 and, if it holds, is
|
||||
`REQUIREMENT n` = achievement **`n`** — see
|
||||
[achievements §3.1 and §4](structures/achievements.md).
|
||||
|
||||
### 5.3 What the six requirement values are 🟡
|
||||
|
||||
@@ -187,10 +194,12 @@ sound here** (the same trap the movie/subtitle map hit) — with one exception:
|
||||
value-before-key adjacency, so the **first** mission (`TimeAttack`) requiring **bit 16**
|
||||
is well-supported.
|
||||
|
||||
Bit 16 is achievement **17, "Solar System Defense Award"** — *"great achievements
|
||||
during the campaign to defend the Solar System"*, i.e. **finish the story campaign**.
|
||||
That is exactly the shape of gate you would expect on the first challenge mission, and
|
||||
it is independent corroboration that the bit space is the achievement space.
|
||||
Under the 1-based reading that §5.2 now prefers, bit 16 is achievement **16,
|
||||
"Night Ravens Patch"** — *"for challenging and eradicating the Night Raven
|
||||
Squadron"*, a stage-15-era award. (The withdrawn 0-based reading gave achievement 17,
|
||||
"Solar System Defense Award"; both are plausible gates for a first challenge mission,
|
||||
which is precisely why the numbering has to be settled by evidence rather than by
|
||||
which story reads better.)
|
||||
|
||||
The remaining five values (`25`–`29`, all `≥ 24`) therefore index **word B**, not
|
||||
achievements — most plausibly a challenge-clear chain, since there are six challenge
|
||||
|
||||
Reference in New Issue
Block a user