re: timer_set's second argument is a SECOND countdown, not a warning threshold
mission-phase-timers.md left 180 open as "a limit and a warning
threshold is the obvious reading, but not established". Reading
sub_822639B8 -- ScriptPhase::Update 0x82263528, same dt as the
stopwatch bank -- settles it the other way:
if running: [+304] += dt
if armed: [+308] -= dt while [+308] > 0
else [+312] -= dt, clamped at 0
[+312] is never compared with [+308]; it is decremented, and only in
the A<=0 arm. Two sequential countdowns. Disc-wide the second
argument is 180 in all 29 timer_set sites while the first varies
(600 x19, 1200 x8, 900, 1800).
Built-ins 123-127 are vtable slots 90-94 on five scalars at
[phase+304..320]. 125 and 126 have ZERO call sites in all 28 scripts:
the script arms, starts and stops this clock but never reads it.
Corrects mission-phase-timers.md, which merged this clock with
stopwatch 0 -- timer_resume starts [+304], set_flag(0) one instruction
later starts the stopwatch the timeline's kind=0 reads.
Docs only; all seven ISL artefacts regenerate byte-identical.
This commit is contained in:
@@ -293,6 +293,49 @@ unknown, what evidence exists, and what the first step would be. Move an item in
|
||||
no writer searched for — a game-speed setter would be one; and 31 `read_freg`
|
||||
sites index by a computed value rather than an immediate.
|
||||
|
||||
* ✅🔴 **(2026-08-27) `timer_set`'s SECOND ARGUMENT IS A SECOND COUNTDOWN — the
|
||||
"warning threshold" reading is REFUTED. [structures/isl-mission-timer](structures/isl-mission-timer.md).**
|
||||
`mission-phase-timers.md` left it open as "a limit and a warning threshold is
|
||||
the obvious reading, but it is **not** established". Reading the updater
|
||||
settles it the other way. The **mission timer** is five scalars on the
|
||||
ScriptPhase — `[+304]` elapsed (up), `[+308]` countdown A, `[+312]` countdown
|
||||
B, `[+316]` running, `[+320]` armed — zeroed together by `sub_8225FEF8`, and
|
||||
driven by **`sub_822639B8`, called from `ScriptPhase::Update` at `0x82263528`
|
||||
with `fmr f1, f30` — the SAME `dt` the stopwatch bank gets**, so it counts the
|
||||
same seconds. Its body: `if running: [+304] += dt`, and `if armed:` **`[+308]
|
||||
-= dt` while `[+308] > 0`, ELSE `[+312] -= dt` clamped at 0.** 🔑 A threshold
|
||||
would be *compared*; `[+312]` is never compared with `[+308]` anywhere — it is
|
||||
decremented, and the `bc 12, gt` at `0x822639FC` jumps **away** to the A arm,
|
||||
so B only runs once A is spent. **Two sequential countdowns.** Disc-wide, 29
|
||||
`timer_set` sites: first argument 600 ×19 / 1200 ×8 / 900 / 1800, **second
|
||||
argument 180 in all 29** — a per-mission limit then a fixed 3-minute stage.
|
||||
(Stated as consistent-with, not as the proof; the disassembly is the proof.)
|
||||
✅ **The five built-ins are vtable slots 90–94** (`0x8226C690`): 127
|
||||
`timer_set(a,b)` arms and loads A/B (as **doubles** from `local[0]`/`local[1]`),
|
||||
123 `timer_resume` starts the elapsed counter, 124 `timer_stop` stops it and
|
||||
disarms, 125 `timer_reset` zeroes all three floats, 126 `timer_elapsed` returns
|
||||
`[+304]`. 🔑 **125 and 126 have ZERO call sites in all 28 scripts** — the script
|
||||
arms, starts and stops this clock but **never reads it**. Its only consumer read
|
||||
here is a 32-byte message (`0xAB03E5BA` → the bus at `[0x828F35DC]`) carrying
|
||||
elapsed, B, running, and `expired = armed && A <= 0`.
|
||||
🔴 **CORRECTION to `mission-phase-timers.md`:** "timer 0 is started by
|
||||
`timer_set(1200,180)` then `timer_resume`, with a 1200-second limit" **merges
|
||||
two clocks**. `timer_set`/`timer_resume` arm and start THIS object;
|
||||
`set_flag(0)`, one instruction later, starts **stopwatch 0**, which is what the
|
||||
timeline's `kind = 0` reads. They start together and so read almost the same
|
||||
value — which is why the merge was invisible. The 1200 s is the mission timer's,
|
||||
not stopwatch 0's.
|
||||
✅ This also unblocks the naming collision noted in
|
||||
[isl-timers](structures/isl-timers.md): 123–127 act on five *scalars*, 8/9/93
|
||||
on a 32-entry *bank*. Not renamed here — that is its own change and its own
|
||||
artefact diff; everything regenerates byte-identical as it stands.
|
||||
🟡 Not settled: **who subscribes to `0xAB03E5BA`** — the literal appears at
|
||||
exactly one site, the producer, but `0xAB03` is the high half of many message
|
||||
tags here and dispatch is not by literal compare, so one occurrence is **not**
|
||||
evidence of no consumer. So whether running out of time ends the mission is
|
||||
unread, as is what B reaching zero does, and whether all 170 `timer_stop` sites
|
||||
are phase teardown.
|
||||
|
||||
## ✅✅ SOLVED — the mission freeze was a modal sign-in dialog (2026-08-26)
|
||||
|
||||
`XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the
|
||||
|
||||
Reference in New Issue
Block a user