re: the bark queue, Priority ordering, and Yes = a one-shot line
sub_822109B0 allocates 68-byte nodes from a pool capped at 128; the Pattern byte at +23 doubles as the occupancy flag. Priority orders the pending list descending; the >=10 front-push arm is dead because the disc's range is 1..9. The tick sub_8220FC50 does rule[+36] |= (1 << node[+25]) & rule[+32], so a line enters the used mask only if its Yes bit is set: Yes = one-shot, No = repeatable. 388 one-shot lines on the disc. Closes what reads +32. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
@@ -265,11 +265,11 @@ can never reach, because it skips the record first. Thirteen dead records out of
|
||||
|
||||
### 🟡 What this does *not* settle
|
||||
|
||||
`Probability` and the line pick are settled above. **Still open: everything
|
||||
after the hand-off to `sub_822109B0`** — how `Priority` orders the queue, whether
|
||||
`Interval` is a cooldown per event or per speaker, what `IntervalFluctuation`
|
||||
randomises, and where `+36`'s bits are set. `+32` (the disc `Yes` mask) is still
|
||||
read by nothing that has been identified.
|
||||
`Probability`, the pick, the queue, `Priority` and the `Yes`/`No` flag are all
|
||||
settled above. **What remains is only the two interval fields:** whether
|
||||
`Interval` (`+20`) is a cooldown per event, per rule or per speaker, and what
|
||||
`IntervalFluctuation` (`+24`) randomises against. Neither is read by the entry,
|
||||
the pick, the enqueue or the tick paths read so far.
|
||||
|
||||
🔴 One handle was tried and refuted: searching the whole image for functions
|
||||
that touch `+16`/`+17`/`+18`/`+20`/`+28`/`+32`/`+36` returns dozens of unrelated
|
||||
@@ -404,6 +404,75 @@ hand-off, not on the way in. Within the whole chatter compilation unit
|
||||
`sub_82213840` (the comparator) and `sub_82210670` — which is what makes this
|
||||
attribution safe where a binary-wide offset search is not.
|
||||
|
||||
## ✅ The queue, `Priority`, and what `Yes`/`No` actually means
|
||||
|
||||
**Settled 2026-08-27** from `sub_822109B0` (enqueue) and `sub_8220FC50` (the
|
||||
per-frame tick, called from `sub_821AB650` and `sub_821B5FB8`).
|
||||
|
||||
### The pending queue
|
||||
|
||||
`sub_822109B0` allocates from a fixed pool: **68-byte nodes starting at
|
||||
`this+32`**, with `[this+8740]` as the live count and `[this+8736]` as the list
|
||||
head. **If the count is already 128 it returns 0 and the bark is dropped.**
|
||||
|
||||
A slot is free iff its byte at `+23` is zero — and `+23` holds **`Pattern`**,
|
||||
which is never 0 for a loaded rule (the enum is 1…4). The presentation field
|
||||
doubles as the occupancy flag.
|
||||
|
||||
| node | content |
|
||||
|---|---|
|
||||
| `+4` | the chosen message id |
|
||||
| `+8` | the speaker entry |
|
||||
| `+12` | the rule object |
|
||||
| `+16` | `EffectiveTime` (frames) |
|
||||
| `+20`, `+21` | zero at enqueue |
|
||||
| `+22` | `Priority` |
|
||||
| `+23` | `Pattern` — also the in-use flag |
|
||||
| `+24` | state byte, zero at enqueue |
|
||||
| `+25` | the chosen message **index** |
|
||||
|
||||
### `Priority` orders the list, and its fast path is dead
|
||||
|
||||
Insertion compares `Priority` against **10**. At or above 10 the node is pushed
|
||||
straight onto the front with no ordering; below 10 it is spliced ahead of the
|
||||
first node with a strictly smaller `Priority`, leaving the list **descending by
|
||||
`Priority`**. **No shipped record reaches 10** — the disc's range is 1…9 — so the
|
||||
front-push arm never runs on the retail data, and every bark takes the ordered
|
||||
path.
|
||||
|
||||
`sub_82210AF0` (called only from the tick) walks the list and returns the largest
|
||||
`[node+20]` among pending nodes whose `Priority` is **higher** than the one being
|
||||
considered and whose `[node+24]` is not `0x10` — a preemption / ducking query
|
||||
against higher-priority speech already queued.
|
||||
|
||||
### ✅ `Yes`/`No` is a one-shot flag — the `+32`/`+36` pair closes
|
||||
|
||||
The tick ends a line with exactly this, at `0x82210160`:
|
||||
|
||||
```
|
||||
r10 = node[+25] ; the index of the line just spoken
|
||||
r9 = rule[+32] ; the Yes mask, straight off the disc
|
||||
r8 = rule[+36] ; the used mask, zeroed by the loader
|
||||
rule[+36] = ((1 << r10) & r9) | r8
|
||||
```
|
||||
|
||||
The spoken line's bit enters the **used** mask **only if its `Yes` bit is set**.
|
||||
Since `sub_82210670` treats a message as eligible only when its bit in `+36` is
|
||||
clear, the meaning is exact:
|
||||
|
||||
* **`Yes` → the line is one-shot.** Once spoken it is permanently removed from
|
||||
that rule's pool.
|
||||
* **`No` → the line repeats.** Its bit never enters `+36`.
|
||||
|
||||
That is what the census counts: **8 940 `No` and 388 `Yes`** — 388 lines across
|
||||
the disc are authored to be heard once. It also closes the earlier open question
|
||||
"what reads `+32`": nothing until a line finishes, and then only to gate this
|
||||
one AND.
|
||||
|
||||
The tick also branches on `Pattern < 3` (using `this+8776` on the taken side), so
|
||||
`Window` (3) is on a different presentation path from `Sound` (1) — consistent
|
||||
with the two values the disc ships.
|
||||
|
||||
## 🟡 Not settled
|
||||
|
||||
* The *policy* the seven fields drive — see "what this does not settle" above.
|
||||
|
||||
Reference in New Issue
Block a user