strats: custom types stay editable after importing object types (custom code kept last), references between custom types by name, edit can change where fields come from, opcode aliases with clearer names, script view gotos 400 -> 31 (labeled break/continue, condition chains, jumps to return), script language 2: event handlers, switch, short-circuit && ||, constant folding, schema parameter names, plain numbers in cells
This commit is contained in:
1 parent
d6f84be125
commit
386a06006d
21 files changed
+1771
-252
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 184 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
+82
-33
@@ -74,11 +74,12 @@ L_0218:
|
||||
| – globals (pushGlobal, popGlobal, …) | `g12` |
|
||||
| – properties (pushProp, popProp, pushPlayerProp, …) | name from props.tsv (`x`, `rotY`, `floorHeight`) or `prop17` |
|
||||
| – branches/calls (jz jnz jzYield jnzYield jmp jmpYield call callYield pushCodeWord pushCodeAddr popCodeWord) | label (or a number = raw word offset) |
|
||||
| – renamed opcodes | former names (`flagEC10000` …, `op-aliases.tsv`) still assemble |
|
||||
| – `switch` | label of the `.switch` table |
|
||||
| – `onEvent entry, slot[, hi=N]` | label of the `.event` entry, slot number |
|
||||
| – `skipArgs`/`print` (0x02/0x03) | raw words: count, items… (`hi=N` first if the opcode word has high bits) |
|
||||
| `push v` (0x45) | number; `tex:N` marks a texture index (before shadowTexture/spawnParticle/…) |
|
||||
| `address ref` (0xb2) | `model:N[+off]`, `anim:N[+off]`, `unit:N[+off]`, `@label[+off]` (own unit), or a number (negative = DEFANIM.WAD animation) |
|
||||
| `address ref` (0xb2) | `model:N[+off]`, `anim:N[+off]`, `unit:N[+off]`, `unit:Name[+off]` (custom types, see below), `@label[+off]` (own unit), or a number (negative = DEFANIM.WAD animation) |
|
||||
| `soundAddress sound:N` (0xd7), `topSay text:N` … (0xf0/0xfa) | level sound / text index |
|
||||
| `debugName "Name"[, k]` (0xd4 0xea rel) | name string: the k-th (default first) occurrence of the string + NUL in the unit that starts a word or follows a NUL; or a label |
|
||||
| other long ops | as many numbers as inline words (`spawn 3, 6, 0, 0, 0`) |
|
||||
@@ -108,21 +109,31 @@ where the blocks nest:
|
||||
| jump to the end / head of the innermost loop | `break` / `continue` (also as `if (c) break`) |
|
||||
| `switch` + `jmp end` with the cases in between | `switch (v) { case 1.0: … break … }` (`default:` when the jmp goes to a case-like block) |
|
||||
|
||||
Everything else stays `goto label` (mostly multi-level breaks out of nested loops and `||` chains
|
||||
that jump to a common far target). Over all 1461 units: **11 019 → 400 gotos** (2026-11-07;
|
||||
guarded by `StratPseudoTest`, which also checks balanced blocks and that every remaining goto has
|
||||
its label). Inline operands in `<>`: `spawn<3, 6, 0, 0, 0>(10.0, 204, 450, unit:35+0x28)`.
|
||||
| jump out of an outer loop (to its end / head) | `break name` / `continue name`, the loop shown as `name: loop {` (`while`, `do`) |
|
||||
| jump to a `return` / `end` / `remove` | `return` / `end` / `remove` (the same instruction) |
|
||||
| conditional jumps separated only by expression code, to a common false target / the body | one condition with `&&` / `||` (short-circuit; also what the compiler generates) |
|
||||
| `if (a) { if (b) {…} }` with nothing else in the outer block | `if (a && b) {…}`; leading `if (c) break` lines of a loop → `while (!c && …)` |
|
||||
|
||||
Everything else stays `goto label`. Over all 1461 units: **11 019 → 400 → 31 gotos** (2026-11-07,
|
||||
second pass; 138 labeled break/continue). The 31 left are one pattern in the Llama strat of every
|
||||
level: a jump from inside a then-part into the else part (`if (a) { call; if (!b) goto else; … }
|
||||
else {…}`); earlier versions showed these as a nested `if` without the else, which was wrong
|
||||
(`fits` now refuses an inner if that targets the outer if's else label). Guarded by
|
||||
`StratPseudoTest` (balanced blocks, every goto has its label, every `break name` names a loop).
|
||||
Inline operands in `<>`: `spawn<3, 6, 0, 0, 0>(10.0, 204r, 450r, unit:35+0x28)`. Raw integers
|
||||
pushed on the stack are written with an `r` suffix (`204r`), as in the script language (below);
|
||||
`1.0`-style and `deg` values as in the assembly.
|
||||
Example (Coin):
|
||||
|
||||
```
|
||||
strat Coin:
|
||||
setModel(model:5)
|
||||
collRadius(409)
|
||||
collRadius(409r)
|
||||
onEvent ev_0000, 0 // event type 4 → L_0084
|
||||
if (v1) { collisionOn<32768>() ... }
|
||||
if (v0) {
|
||||
if (self.floorMaterial == -1.0) { skipArgs … } else {
|
||||
self.y = self.floorHeight + 204
|
||||
self.y = self.floorHeight + 204r
|
||||
self.rotY = rnd(4096.0)
|
||||
}
|
||||
}
|
||||
@@ -132,10 +143,15 @@ loop { turnLeft(5.625deg); yield }
|
||||
## Script language (`StratCompiler`) – writing NEW behaviour
|
||||
|
||||
A small structured language in the style of the script view, compiled to the assembly above (so
|
||||
everything the assembler checks still applies). Implemented slice (2026-11-07): strats, subroutines,
|
||||
aliases, assignments, expressions, if/else if/else, while, loop, do-while, break/continue, yield,
|
||||
calls of any opcode by name. Tests: `StratCompilerTest`; verified in game (village 1:
|
||||
`img/mods/strats_script_game.jpg`).
|
||||
everything the assembler checks still applies). Language version 2 (2026-11-07): strats, subs,
|
||||
aliases, parameter names, assignments, expressions with constant folding, short-circuit `&&`/`||`,
|
||||
if/else if/else, while, loop, do-while, switch, break/continue, yield, event handlers, calls of any
|
||||
opcode by name. Tests: `StratCompilerTest`. In game (village 1, apptest, 2026-11-07): version 1
|
||||
scripts `img/mods/strats_script_game.jpg`; version 2 (`StratsGameLevel … v2`: a custom type, then
|
||||
an imported Spider in the same session, the custom type edited afterwards, compiled Toucher/Ticker
|
||||
with `on touched` / `on event(0x40, 30)`, switch, `&&`/`||`) loads and plays without errors
|
||||
(`img/mods/strats2_game_import.jpg`); the handlers' visible effect was not confirmed (the test
|
||||
objects were out of the camera's view under the slow harness).
|
||||
|
||||
```
|
||||
// bobs one cell up and down and turns
|
||||
@@ -143,8 +159,11 @@ strat Bobber {
|
||||
alias base = v0 // .alias base = v0
|
||||
alias phase = v1
|
||||
setModel(model:5) // any opcode: name<inline operands>(stack arguments)
|
||||
base = self.y + 1.0
|
||||
base = self.y + 1 // 1 = one cell
|
||||
phase = 0
|
||||
on touched { // event handler (type 4), runs as a subroutine
|
||||
soundPlay(sound:6)
|
||||
}
|
||||
loop {
|
||||
phase = phase + 4deg
|
||||
self.y = base + sin(phase)
|
||||
@@ -160,26 +179,44 @@ sub wobble { // called with "call wobble", ends with return
|
||||
|
||||
| Construct | Compiles to |
|
||||
|---|---|
|
||||
| `strat Name { … }` | `.string "Name"`, label `Name:`, `debugName "Name"`, body, `end` unless the body cannot fall through |
|
||||
| `strat Name { … }` | `.string "Name"`, label `Name:`, `debugName "Name"`, body, `end` unless the body cannot fall through; event handler code behind it |
|
||||
| `sub name { … }` / `call name` / `return` | label, body, `return` / `call name` / `return` |
|
||||
| `x = e`, `x += e` (`-=`, `*=`, `/=`) | e, pop op of x; `x += 1.0` / `x -= 1.0` → address + `inc`/`dec` |
|
||||
| places | `vN`, alias, `gN`, `self.prop`, `player.prop`, `parent.prop`, `parent.vN`, `camera.`/`target.`/`target2.`/`boss.`/`dialog.prop` (props.tsv names or `propN`) |
|
||||
| literals | as in the assembly: `10.0` = ten, `10` = 10 raw units (1/4096), `90deg`, `0x10`; 16-bit values use `pushShort`, others `push` |
|
||||
| references | `model:N`, `anim:N`, `unit:N` (`address`), `sound:N` (`soundAddress`), `tex:N` (`push`) |
|
||||
| operators (low → high) | `||` `|` (or) · `&&` (and) · `&` · `==` `!=` · `<` `>` `<=` `>=` · `<<` `>>` · `+` `-` · `*` `/` · unary `-` `!` |
|
||||
| `op<a, b>(e1, e2)` | e1, e2, `op a, b`; the argument count must match the opcode's pops; a value-returning op used as a statement is followed by `pop` |
|
||||
| `if (c) {…} else if … else {…}` | `c; jz else; …; jmp end; else: …` |
|
||||
| `while (c) {…}` / `loop {…}` | head label, `c; jz end`, body, `jmp`/`jmpYield head` |
|
||||
| `do {…} while (c)` | body, `c; jnz head` |
|
||||
| `x = e`, `x += e` (`-=`, `*=`, `/=`) | e, pop op of x; `x += 1` / `x -= 1` (= 1.0) → address + `inc`/`dec` |
|
||||
| places | `vN`, alias, parameter name, `gN`, `self.prop`, `player.prop`, `parent.prop`, `parent.vN`, `camera.`/`target.`/`target2.`/`boss.`/`dialog.prop` (props.tsv names or `propN`) |
|
||||
| numbers | plain integer = game units: `10` = 10.0 (40960 raw); `1.5`, `90deg` as in the assembly; **raw words**: `215r` or hex `0x10` |
|
||||
| references | `model:N`, `anim:N`, `unit:N` / `unit:Name` (`address`), `sound:N` (`soundAddress`), `tex:N` (`push`) |
|
||||
| operators (low → high) | `||` · `&&` · `|` · `&` · `==` `!=` · `<` `>` `<=` `>=` · `<<` `>>` · `+` `-` · `*` `/` · unary `-` `!` |
|
||||
| constant folding | operators over constants are computed with the VM's rules (20.12 `*` = a·b>>12, `/` = (a<<8)/b<<4, shifts by b>>12, comparisons 0/1): `2 * 3 + 0.5` → `pushShort 6.5` |
|
||||
| `op<a, b>(e1, e2)` | e1, e2, `op a, b`; the argument count must match the opcode's pops; a value-returning op used as a statement is followed by `pop`. Inline operands `<…>` are raw words as in the assembly |
|
||||
| conditions (`if`, `while`, `do … while`) | **short-circuit**: `a && b` → `a; jz F; b; jz F`, `a || b` → `a; jnz T; b; jz F; T:`; `!` swaps the jump; constant conditions need no code. In a value (`x = a && b`) both sides are evaluated (`and`/`or` opcodes) |
|
||||
| `if (c) {…} else if … else {…}` | `c → else; …; jmp end; else: …` |
|
||||
| `while (c) {…}` / `loop {…}` | head label, `c → end`, body, `jmp`/`jmpYield head` |
|
||||
| `do {…} while (c)` | body, `c → head` |
|
||||
| `switch (e) { case 1: … break … default: … }` | `e; switch tab; jmp default/end`, case bodies in order (C rules: fall through, `break` leaves the switch, `continue` the enclosing loop); table `.switch n` + `.case [imm] v, label` (short form when v fits 16 bits). Case values are constants |
|
||||
| `on touched { … }` / `on event(type[, param]) [slot n] { … }` | `onEvent ev, slot` where it stands (slots 0, 1, … in order unless given); entry `.event type, param, handler`; the handler body (ends with `return`; `remove`/`end` allowed) behind the strat. type/param/slot are raw words; type 4 = touched (`collisionOn` + `collRadius` needed, like Coin), 0x40 = timer, 0x80/0x100 = player distance |
|
||||
| `break` / `continue` / `yield` / `end` | `jmp end` / `jmp head` (do: the condition) / `jmpYield next` / `end` |
|
||||
| `use rawNumbers` | the version-1 number rule (plain integers are raw words) for the rest of the script |
|
||||
|
||||
Layout: event entries and switch tables go to the **start** of the unit (like the original code):
|
||||
data behind a terminating instruction would be decoded as dead code by `StratCode`'s
|
||||
terminator-follower pass and break the listing.
|
||||
|
||||
**Parameter names**: `StratCompiler.compile(src, names)` takes predefined names → `vN`; the editor
|
||||
passes the parameter names of the object schema of the type the custom type's fields come from
|
||||
(`StratEdits.paramNames`, the same names as the script view's aliases, e.g. `snapToFloor` = v0
|
||||
for Coin). The script's own `alias` wins.
|
||||
|
||||
**Numbers, compatibility**: language version 1 (before 2026-11-07) read `10` as 10 raw units. The
|
||||
compiler now writes the marker line `; script language 2` behind the embedded source;
|
||||
`embeddedSource` of older output (no marker) puts `use rawNumbers` in front of the script, so an
|
||||
old type opened with *Edit type…* compiles to the same code. Stored types are assembly anyway
|
||||
(the script is a comment), so loading never recompiles.
|
||||
|
||||
The generated assembly starts with the script as `;| ` comment lines, so the editor can show the
|
||||
script again (*Edit type…*). Comments: `//`, `/* */`; `;` and newlines separate statements.
|
||||
|
||||
**Next steps (not implemented)**: event handlers (`on touched { … }` → `.event` table + `onEvent`),
|
||||
`switch`, `spawn` with typed arguments, local names for parameters from the object schema, `for`,
|
||||
constant folding, typed numbers (int vs fixed) instead of the assembly's literal rules,
|
||||
short-circuit `&&`/`||` (now: both sides are evaluated, like the original `and`/`or` opcodes).
|
||||
**Not implemented**: `for`, `spawn` with typed arguments, typed variables (int vs fixed), a view of
|
||||
event handlers as `on … { }` (the script view shows `onEvent` + the handler label).
|
||||
|
||||
## Editing in the level editor (`editor.tools.strats`)
|
||||
|
||||
@@ -197,7 +234,8 @@ short-circuit `&&`/`||` (now: both sides are evaluated, like the original `and`/
|
||||
source text (the cloned unit's listing with the strat renamed, or a template), entry label,
|
||||
type fields/parameters taken from an existing type. *Check* assembles and verifies; *Create*
|
||||
appends the unit at the end of the STPC code region (nothing else moves), adds the type to the
|
||||
catalogue (Assets → Objects), stores `stratEdits.types` `{name, basedOn, entry, source, proto}`.
|
||||
catalogue (Assets → Objects), stores `stratEdits.types` `{name, basedOn, entry, source, proto
|
||||
[, fieldsFrom]}` (`fieldsFrom` = type of the fields/parameter names when it differs from basedOn).
|
||||
Verification: the merged STPC is disassembled again (no decode errors, entry decoded, every
|
||||
`address` operand of the new unit hits a model, animation set or code, and the new unit's
|
||||
listing re-assembles to the same words).
|
||||
@@ -206,8 +244,20 @@ short-circuit `&&`/`||` (now: both sides are evaluated, like the original `and`/
|
||||
custom units (`TypeEdits.edit`, one undo step) and the placed objects move to the new entry.
|
||||
Delete warns with the number of objects that use the type and removes them with it
|
||||
(`TypeEdits.delete`: `Edits.delete` of the users + the type list change, one undo step).
|
||||
Creating is undoable too (`TypeEdits.create`), except when imported types follow the custom
|
||||
block (then appended as before).
|
||||
Creating is undoable too (`TypeEdits.create`). In edit mode *Type fields / parameters from* can
|
||||
be switched to another type (new placements start with its fields; placed objects keep theirs);
|
||||
`(keep current fields)` is the default. Renaming a type also renames `unit:Old` in the other
|
||||
custom types.
|
||||
* **References between custom types**: `unit:N` operands that point at a custom type are stored
|
||||
as `unit:TypeName` (`StratEdits.symbolic` on create/edit; on load for older projects, with the
|
||||
saved `session.firstUnit`); the assembler resolves names through `Layout.withUnitNames`, the
|
||||
listing prints them (`Names.unitName`). Deleting a referenced type is refused ("unknown unit
|
||||
name").
|
||||
* **Imports in the same session** (CrossImport `CodeHook`): the merge is computed on the code
|
||||
without the custom units (`mergeBase`), and the commit cuts the custom units off, merges, and
|
||||
appends them again behind the imported code (`StratEdits.aroundImport`; objects follow by type
|
||||
index and offset from the entry) – the same order as on load, so editing/deleting/undoable
|
||||
creating keep working without reopening. (Imports themselves still clear the undo history.)
|
||||
* **Language** (dialog): *Assembly* or *Script* (compiled by `StratCompiler`, see above);
|
||||
switching Script → Assembly shows the generated code.
|
||||
* **Load order** (`ProjectIO.LoadHook.order()`): constants of base units (−10) → imported types
|
||||
@@ -218,10 +268,9 @@ short-circuit `&&`/`||` (now: both sides are evaluated, like the original `and`/
|
||||
## Limits
|
||||
|
||||
* Custom types are edited and deleted as a whole list: the custom units are cut off the code and
|
||||
appended again (objects follow their type's new entry). Not possible while object types imported
|
||||
after the custom ones sit behind them in the code (save and reopen the project first; on load the
|
||||
custom types always come last). A custom type that addresses another custom type's unit with
|
||||
`unit:N` breaks when that index changes. Constants of custom types are changed through their source.
|
||||
appended again (objects follow their type's new entry). Projects saved by older versions with
|
||||
imports behind the custom types are reordered on load as before. Constants of custom types are
|
||||
changed through their source.
|
||||
* `pushShort` holds only −8.0…7.99; bigger values need a source edit (`push`).
|
||||
* The script view is a reading aid (gotos where blocks do not nest; expressions assume the
|
||||
documented pop/push counts; ops with variable stack use are shown raw).
|
||||
|
||||
+11
-6
@@ -21,8 +21,13 @@ properties). Language/syntax: `notes/strat-language.md`. Disassembler/assembler:
|
||||
registered with 0x113; 0x14a is a no-op (FUN_004268c0 only acts for 0); 0x9c's value is dead;
|
||||
0x18a/0x18b set the pending particle settings consumed by the next spawnParticle; 0x1a9's top
|
||||
value is the rain texture and the others are wind x, amount, wind z; all no-op/drop stubs verified.
|
||||
Still low: 0x34 and 0xf2 (no reader of their flag bits found). Names unchanged (stored sources use
|
||||
them); see the table for the new descriptions.
|
||||
Still low: 0x34 and 0xf2 (no reader of their flag bits found); see the table for the new descriptions.
|
||||
* **Renamed opcodes (aliases)**: placeholder names whose meaning the review established got clear
|
||||
names – 0x2f `flagEC10000` → `freezeOffCamera`, 0x31 `flagEC2` → `touchable`, 0x33 `flagEC100` →
|
||||
`noFloorPhysics`, 0x14a `hudReset2` → `hudResetNoop`. The old names stay valid mnemonics
|
||||
(resource `op-aliases.tsv`, `OpTable.alias`), so stored sources still assemble; listings and the
|
||||
compiler use the new names. Names of flags without a known reader (0x32, 0x34, 0x141–0x144,
|
||||
0x14b) keep their address-style names.
|
||||
* **252 opcodes matched to Argonaut names** (column *ref*: Croc 2 PSX demo jump table / Croc 1
|
||||
handler names), by handler behaviour and table position. 99 slots are no-ops, error stubs or
|
||||
pop-only stubs (dropped Croc features).
|
||||
@@ -120,11 +125,11 @@ ops = operands (inline words for long ops, the 16-bit argument for short ops); p
|
||||
| 0x2c | `nop_0x2c` | - | 0 | 0 | | high | - | No-op (shared empty handler); unused. <sub>426500</sub> |
|
||||
| 0x2d | `nop_0x2d` | - | 0 | 0 | | high | - | No-op (shared empty handler); unused. <sub>426500</sub> |
|
||||
| 0x2e | `nop_0x2e` | - | 0 | 0 | | high | - | No-op (shared empty handler); unused. <sub>426500</sub> |
|
||||
| 0x2f | `flagEC10000` | imm | 0 | 0 | 1888 | medium | - | arg!=0 sets, 0 clears +0xEC bit 0x10000 = "freeze when off-camera": the camera pass (FUN_00436190) sets +0xEC 0x8000 when the strat is outside the camera range; with both bits set the frame loop (0x54c603) and the strat-vs-strat collision loop (0x54cc1a) skip it. Used by ~1350 strats (pickups, triggers, enemies). <sub>54f720</sub> |
|
||||
| 0x2f | `freezeOffCamera` (was `flagEC10000`) | imm | 0 | 0 | 1888 | medium | - | arg!=0 sets, 0 clears +0xEC bit 0x10000 = "freeze when off-camera": the camera pass (FUN_00436190) sets +0xEC 0x8000 when the strat is outside the camera range; with both bits set the frame loop (0x54c603) and the strat-vs-strat collision loop (0x54cc1a) skip it. Used by ~1350 strats (pickups, triggers, enemies). <sub>54f720</sub> |
|
||||
| 0x30 | `trackPlayer` | imm | 0 | 0 | | medium | - | If no player yet: re-executes itself next frame (pc-=4, yield); else arg sets/clears +0xEC bit 0x4000 = update distance to player each frame (+0x148). <sub>54fa80</sub> |
|
||||
| 0x31 | `flagEC2` | imm | 0 | 0 | 410 | medium | - | arg sets/clears +0xEC bit 2 = "others can stand on / touch me": in the strat collision loop (0x54cc96) a strat touching a strat with this bit gets +0xE8 0x400000 (and 0x800000 when it moves) = properties 32/33; also readable as property 0x1f. Set by Llama, Coin, Jar, EnemyCoin, RubyIdol. <sub>54e090</sub> |
|
||||
| 0x31 | `touchable` (was `flagEC2`) | imm | 0 | 0 | 410 | medium | - | arg sets/clears +0xEC bit 2 = "others can stand on / touch me": in the strat collision loop (0x54cc96) a strat touching a strat with this bit gets +0xE8 0x400000 (and 0x800000 when it moves) = properties 32/33; also readable as property 0x1f. Set by Llama, Coin, Jar, EnemyCoin, RubyIdol. <sub>54e090</sub> |
|
||||
| 0x32 | `flagE8_80000000` | imm | 0 | 0 | | medium | - | arg sets/clears +0xE8 bit 31; no reader of the bit found in the exe (scan of all +0xE8 flag tests); unused in the levels. <sub>54dd90</sub> |
|
||||
| 0x33 | `flagEC100` | imm | 0 | 0 | 60 | medium | - | arg sets/clears +0xEC bit 0x100; the collision response (0x4044f7) skips the floor/slope handling when it is set. Used by LlamaSpit, DropObject, RollerCoaster, KuscoTurtle (objects that move by script, not by floor physics). <sub>54dd30</sub> |
|
||||
| 0x33 | `noFloorPhysics` (was `flagEC100`) | imm | 0 | 0 | 60 | medium | - | arg sets/clears +0xEC bit 0x100; the collision response (0x4044f7) skips the floor/slope handling when it is set. Used by LlamaSpit, DropObject, RollerCoaster, KuscoTurtle (objects that move by script, not by floor physics). <sub>54dd30</sub> |
|
||||
| 0x34 | `flagEC200000` | imm | 0 | 0 | 50 | low | - | arg sets/clears +0xEC bit 0x200000; no direct test of the bit found in the exe (all +0xEC flag tests scanned). Used by Llama, RiverCroc, RiverLog, Rock, river NPCs (river/canoe level objects). <sub>54dd60</sub> |
|
||||
| 0x35 | `nop_0x35` | - | 0 | 0 | | high | - | No-op (shared empty handler); unused. <sub>426500</sub> |
|
||||
| 0x36 | `nop_0x36` | - | 0 | 0 | | high | - | No-op (shared empty handler); unused. <sub>426500</sub> |
|
||||
@@ -403,7 +408,7 @@ ops = operands (inline words for long ops, the 16-bit argument for short ops); p
|
||||
| 0x147 | `nop_0x147` | - | 0 | 0 | | high | - | Empty handler FUN_00426500 (shared no-op); does nothing. <sub>426500</sub> |
|
||||
| 0x148 | `gotoLevel4_1` | - | 0 | 0 | | medium | - | Hardcoded level change: next level (0x584EB4/EB8/EBC/EC0) = 4/1/1/0, previous level (0x585008..14) = 4/1/4/0, game state 0x584638 = 7 (load level). <sub>54e430</sub> |
|
||||
| 0x149 | `nop_0x149` | - | 0 | 0 | | high | - | Empty handler FUN_00426500 (shared no-op); does nothing. <sub>426500</sub> |
|
||||
| 0x14a | `hudReset2` | - | 0 | 0 | | high | - | Calls FUN_004268c0(2), which returns at once for any argument other than 0 (verified in the assembly): a no-op. Unused. <sub>54f700</sub> |
|
||||
| 0x14a | `hudResetNoop` (was `hudReset2`) | - | 0 | 0 | | high | - | Calls FUN_004268c0(2), which returns at once for any argument other than 0 (verified in the assembly): a no-op. Unused. <sub>54f700</sub> |
|
||||
| 0x14b | `setGlobal5fd086` | imm | 0 | 0 | | medium | - | Stores the low 16 bits of the inline word in global 0x5FD086 (never read elsewhere; dead leftover). <sub>54e890</sub> |
|
||||
| 0x14c | `removeCollPoint` | - | 1 | 0 | 49 | medium | stSetCollPoint (inverse) | pops id (fixed, >>12); removes the collision point with that id from the strat's collision point list (+0xC8 array of 4-byte entries, count +0xC6). Counterpart of 0xc6 (add/set collision point). <sub>54e720</sub> |
|
||||
| 0x14d | `setFlagEC_400000` | flags | 0 | 0 | | high | - | Inline word: nonzero sets, zero clears bit 0x400000 of strat flags2 (+0xEC); the bit selects which height constant own property 0xF2 returns. <sub>54f780</sub> |
|
||||
|
||||
Reference in new issue
Block a user