Tutorial (Lecture) Mode
11.1What makes lecture mode different
| Aspect | Normal mode | Lecture mode (gameStatus[0]==1) |
|---|---|---|
| Life pool | penalties drain it; 0 = game over | penalties accumulate per category but never drain (profile 1 in subLifePoint) |
| Stop judgment | bonuses + penalties | teaching messages (entryStopLecture) instead of bonuses |
| Departure | startMapFunc states 0–4 | states 5/6 — signal-go + autodrive begins |
| Items | none | five consumable items (speed×2, brake boost, time-stop, score×2, rescue) — controlItem is gated on the lecture profile |
| Teaching prompts | — | unskippable text panels that freeze the game (GameCondition |= 2) |
11.2The lecture record: 80 bytes each
All teaching content is one flat array at 0x5b8870: fixed 80-byte records,
scanned by pointer stepping, no linked list:
| Offset | Field | Notes |
|---|---|---|
| +0x00 | lecture ID | what entryLecture(id) looks up |
| +0x04 | min display count | how long the panel stays |
| +0x08 / +0x0c | condition masks | gated on game-status / mode selectors |
| +0x10..0x1c | window + text positions | word-menu screen coordinates |
| +0x28 | window style | _lect_basewindow: 1 → fixed texture 0x13d, else abs(v)+8 texture index |
| +0x2c | char* text | the message itself (strcpy into the menu) |
| +0x38 | voice ID | ≥0 → VoicePlay; −1 = silent |
| +0x3c | PCM timeout | −1 = no audio gate; else 3000-frame (50 s) cap |
| +0x40 | freeze type | 1 → GameConditionBk |= 2 (the freeze) |
| +0x48 | chained_lecture_id | auto-chain: when this lecture closes, that one starts immediately — multi-page sequences without caller logic |
/* the lecture display machine (DAT_006d42bc) */
state 1: show word menu with rec->text; freeze via GameCondition |= 2 // type 1
state 2: while (PcmCheck()) { if (++cnt > 3000) cancel; } // voice gate
state 3: when word menu closes → cancelLecture()
→ if (rec->chained != -1) __sub_entrymlecture(rec->chained) // auto-chain
procLecture @ 0x1c70ec. The
freeze bit is what makes tutorials "stop the world" while the instructor talks.11.3When lectures fire
Two trigger families, both resolved completely:
- Threshold triggers —
LectDispCheck(@0x1c74bc) compares live values against per-record thresholds: brake applied whileDistStop < 250/180/45m, speed over limits at specific distances (1775/1145/100/400/402 m), ATS/ATC events, and the one-shotLectDispFlg64-byte array (dual-purpose byte +0x38) that makes every hint fire exactly once per run. - Scripted route events —
CheckEventLecturewalks event group 0 (EVENT_TAGstream, the same architecture as tunnel events): types 0x30/0x35–0x41 fire lecture 0x33 (or 0x1d/0x1e by time-zone policy, gated onspeed < 5.0).
11.4The autodrive instructor
In lecture departure (startMapFunc states 5/6) the game sets the signal
(changeStartSignalGo) and hands throttle to the autorun system
(AutoRun @ 0x1a40cc, called from ttTrainGo when
gameMode==2... and the lecture variant): dual scanners (a target-speed
scanner over the route's speed limits and a brake-point scanner over the stop target) compute notch/brake commands each frame, with the −1.0 sentinel trick marking "no command". The
player's inputs are suggestions the instructor demonstrates; the teaching prompts
commentate ("now apply brake B5; you should stop within the yellow band").
11.5The debug flags behind it
The boot-flag cluster (five consecutive bytes @ 0x6c8748: UndeadFlag,
DebugData, JoinDebugFlag, GameLoopFlag, MenuLoopFlag) interacts with tutorials:
-debugdata unlocks all diagrams and maxes credits; -undead sets
GameCondition bit 6 (in the game-over suppression mask) once per train init via
ttTrainInit; -menuloop/-gameloop drive the attract
loops (and, as this report's capture harness found, -menuloop also skips the
boot caution screens, because MainTask checks it before displaying them).