Crusader_Decomp/docs/movable-wall-trigger-investigation.md

16 KiB

Movable Wall Trigger Investigation

This note records the current evidence for movable walls that do not advertise their opener through the viewer's older helper-arrow rules.

Result

The checked cases fit one local cluster pattern:

  • a family-4 usecode trigger egg sits beside the wall
  • a nearby 0x04B1 CMD_LINK helper uses the egg id from mapNum as its QLo link byte
  • that helper is the practical local opener for the wall face

The viewer now draws that cluster as two links when the pattern is present:

  • egg -> CMD_LINK
  • CMD_LINK -> movable wall

The rule is intentionally narrow. It only applies to checked TRIGEGG / ONCEEGG style eggs when a nearby CMD helper and one of the verified movable-wall target shapes are both present.

Checked Cases

Map 13

  • wall: fixed:3964
  • visible wall face near 49790, 50206, 0
  • nearby trigger egg: fixed:3970, shape 0x0011, mapNum = 5, near 49794, 50598, 0
  • second nearby trigger egg with the same egg id: fixed:3955, shape 0x0011, mapNum = 5, near 49604, 50516, 0
  • stacked CMD helpers in the same local lane:
    • fixed:3972, shape 0x04B1, near 49790, 50558, 0, mapNum = 38, npcNum = 155, quality = 0x0105
    • fixed:3956, shape 0x04B1, near 49790, 50558, 4, mapNum = 46, npcNum = 155, quality = 0x0005
    • fixed:3976, shape 0x04B1, near 49790, 50558, 8, mapNum = 134, npcNum = 208, quality = 0x0005

This is still the cleanest same-column movable-wall cluster, but the deeper map-13 pass shows that it is not just one egg wired straight to one wall.

Map 13: Proven Trigger Chain

The currently proven chain is:

  • avatar crosses the hidden family-4 TRIGEGG footprint for egg id 5
  • leaving that footprint runs TRIGEGG::unhatch, not hatch
  • TRIGEGG::unhatch spawns TRIGGER.slot_20(..., 0x81, ...)
  • TRIGGER.slot_20 scans nearby 0x04B1 CMD helpers and keeps only the phase-1 lane (mapNum & 8)
  • in this local stack, that selects fixed:3956
  • the selected CMD then routes into the item-targeting trigger worker path

So the wall-opening logic for fixed:3964 is definitely tied to the 0x81 unhatch path, meaning the authored event fires when the player leaves the trigger region rather than when entering it.

Map 13: Why This Still Looks Like A Set Piece

Several nearby placements suggest a more specific authored sequence than a simple hidden strip trigger:

  • there are two separate TRIGEGG items using the same egg id 5 in the same local area
  • there are three stacked 0x04B1 helpers at the same x/y with different z values and different encoded payloads
  • nearby helper/door-like pieces also sit in the same cluster, including shape 1278 and several 353 / 354 objects

That combination looks more like a local puzzle or staged control cluster than a generic walk-near-door opener.

Map 13: Current Open Gap

The last mutation step is still unresolved, but the current gap is narrower than before.

The relevant phase-1 CMD path does reach TRIGGER.slot_23, and the selected helper in the checked stack (fixed:3956, mapNum = 46, quality = 0x0005) now decompiles cleanly enough to read its top-level lane. Its mapNum & 3 mode selects slot_23 case 2, and that case is not a hidden mutation body. It is currently just a scan over nearby decoded target-shape items with two filters:

  • Item.getQLo(item) == baseLink
  • ref != item

and no direct action on the matches.

That point is now supported by both the repaired high-level pseudocode and the lower semantic-layer output for TRIGGER.slot_23, slot_24, and slot_26: all three families still reduce their case-2 lane to a bodyless match scan.

For the checked map-13 cluster, that scan target is now known more precisely:

  • fixed:3956 and its phase-0 sibling fixed:3972 both decode to target shape 0x019B (shape:411)
  • the only nearby non-CMD object with low-byte link 5 is fixed:3968, a shape:411 helper-geometry record at 49918, 50238, 48
  • the upper stacked helper fixed:3976 decodes to target shape 0x04D0 (shape:1232), but there are no nearby shape:1232 targets in this local cluster at all

So the local QLo = 5 objects around the wall reduce to four items:

  • fixed:3972 phase-0 CMD helper
  • fixed:3956 phase-1 CMD helper
  • fixed:3976 upper CMD helper with no local target
  • fixed:3968 helper-geometry target

Current best interpretation:

  • the local trigger source is known
  • the relevant phase-1 helper is known
  • the selected phase-1 helper now looks like an intentional scan-only selector aimed at helper target fixed:3968, not a direct wall mutator
  • the upper stacked helper currently looks inactive for this cluster because it has no local shape:1232 target to scan
  • that makes the final wall mutation for fixed:3964 more likely to live in a sibling helper, another usecode family that reacts to the scanned helper-geometry target, or a different edge/phase of the local trigger cluster, not inside this specific case-2 body

So map 13 should still be documented as a verified trigger cluster with an unresolved final mutation, but the strongest current read is no longer “empty loop probably means bad decompilation.” The stronger read is “the chosen phase-1 CMD helper appears to be a deliberate scan-only lane.”

Map 13: Current Best Gameplay Trigger Path

Even without the final helper-consumer body, the local egg geometry now narrows the likely player action down substantially.

The hidden family-4 trigger eggs beside the wall form an ordered west-to-east run by egg id:

  • fixed:3910 = egg id 1
  • fixed:3945 = egg id 2
  • fixed:3944 = egg id 3
  • fixed:3959 = egg id 4
  • fixed:3955 = egg id 5
  • fixed:3970 = egg id 5

The last two id-5 eggs are narrow strips that sit directly in the northbound approach lane for wall fixed:3964.

  • fixed:3955 covers x = 49540..49668, y = 50196..50836
  • fixed:3970 covers x = 49730..49858, y = 50278..50918
  • wall fixed:3964 sits at 49790, 50206, which lines up with the eastern strip and lies just beyond its north boundary

That means the most likely gameplay action is:

  • approach the wall from the south side, not from the north
  • enter the eastern id-5 strip aligned with the wall face
  • keep moving north toward the wall until the avatar leaves that strip across its north edge

That northbound exit is the exact movement that matches the proven TRIGEGG::unhatch -> TRIGGER.slot_20(..., 0x81, ...) -> fixed:3956 chain.

So the current best practical trigger instruction is not just “walk through an egg.” It is “come up from the south, get into the narrow id-5 lane in front of the wall, and cross out of that lane northward toward the wall.”

What is still not closed is whether the earlier id-1..4 strips are mandatory setup for the wall or just sibling lanes in the same authored corridor. The current code evidence proves the final northbound id-5 exit, but does not yet prove that ids 1..4 must be traversed first.

For gameplay testing, the screen-space direction should be stated more clearly:

  • decreasing world y is not plain screen-up; in this isometric projection it reads as up-right on the screen
  • increasing world x with roughly stable y reads as rightward on the screen

So the current best practical route on screen is:

  • sweep left-to-right across the lower hidden trigger corridor for ids 1 -> 2 -> 3 -> 4
  • continue a little farther right into the first narrow id-5 strip (fixed:3955)
  • drift slightly down-right into the second narrow id-5 strip (fixed:3970)
  • then cut up-right out of that second strip toward the wall face at fixed:3964

This wording matches the actual screen anchors in the authored scene cache:

  • id 4 strip anchor: (15555, 11793)
  • first id 5 strip anchor: (15645, 11796)
  • second id 5 strip anchor: (15672, 11830)
  • wall face anchor: (15741, 11781)

That makes the final move leg visually specific: from the lower-left side of the wall, move up-right toward the wall after entering the second id-5 strip.

Map 13: Practical Clarifications

Do the wall shooters matter?

Current best read: probably not for the wall opener itself.

The visible wall launcher near this setup is fixed:3958 at 49246, 50942, 48. Its low quality byte is 7, while the checked movable-wall trigger lane uses local link ids 1..5 and the final wall-facing lane uses id 5.

Nearby authored objects support that split:

  • wall lane helpers: fixed:3972, fixed:3956, fixed:3976 with local ids centered on the id-5 corridor
  • wall-facing helper target: fixed:3968 with low byte 5
  • launcher object: fixed:3958 with low byte 7

No nearby id-7 trigger egg or id-7 0x04B1 controller helper has been found in the same local corridor. So the current best interpretation is that the launcher is a sibling trap lane, not the wall-opening lane.

That means destroying the launcher should not be expected to disable the wall trigger path. This is still an evidence-backed inference rather than a fully closed runtime proof, but the current local link data points strongly that way.

Can the wall-trigger sequence be retried?

On the trigger side, yes.

The last two wall-facing id-5 eggs are plain TRIGEGG subtype eggs (quality low byte = 0), not ONCEEGG. The live egg-hatcher runner sets the internal hatched flag when the avatar enters the trigger footprint and clears it again on exit, calling hatch and unhatch on those boundary crossings.

So the trigger geometry is inherently reusable:

  • enter the strip -> hatch
  • leave the strip -> unhatch
  • walk back in and out again -> the same boundary logic can fire again

Also, the selected phase-1 helper fixed:3956 uses mapNum = 46, which does not set the 0x10 low-priority self-clear bit in TRIGGER.slot_20. So the helper itself does not look one-shot from the currently recovered routing path.

The remaining caveat is only the still-unresolved final consumer after the scan lane. The trigger side is repeatable; the last unclosed world-change side might still have an authored one-shot elsewhere, but there is no current evidence for that in the id-5 egg path itself.

How do the last two id-5 eggs work if they are lines?

They are narrow trigger strips, not square areas.

For both wall-facing id-5 eggs, npcNum = 4, which decodes to:

  • xRange = 0
  • yRange = 4
  • worldXRange = 0
  • worldYRange = 256
  • zWindow ~= +/- 48

So in world-space they are centered on a single x line and extend along y. In the isometric screen projection that reads as a narrow diagonal strip running roughly down-left / up-right on screen.

The runner compares the avatar footprint against that trigger window, not just a single point. So a zero-width xRange does not mean the player has to hit one impossible exact pixel. It behaves like a thin line trigger that the avatar body can cross.

Practical movement consequence:

  • if you move along the strip, you stay inside it and nothing new happens after the first entry
  • if you cross into it, hatch fires
  • if you cross back out of it, unhatch fires

For the wall case, the proven useful event is the unhatch on the second id-5 strip. So the movement that matters is not "stand in the line" but "pass through the line and leave it on the wall-facing side."

Are ids 1..4 actually required?

Current best read: no, they do not look required.

This is now supported by the recovered trigger code and the authored local lane layout.

Locally, ids 1..4 are four copies of the same controller pattern:

  • each egg is a plain TRIGEGG subtype egg
  • each one routes into a pair of nearby 0x04B1 helpers with the same mapNum values as the id-5 lane (38 at z=0, 46 at z=4)
  • each helper pair targets exactly one nearby shape:411 helper-geometry object whose QLo matches the egg id

The code path for those helpers does not show any accumulating setup behavior.

  • TRIGEGG::hatch and unhatch temporarily rewrite the egg item's local QLo to the egg id and call TRIGGER.slot_20
  • TRIGGER.slot_20 carries that id as the current baseLink
  • the selected slot_21 -> slot_23 case 2 path for ids 1..5 is a scan-only lane over nearby matching targets
  • that lane returns process_result = baseLink unchanged
  • none of the id-1..4 helpers use the add/subtract cases that would roll the link id forward to the next lane
  • none of the id-1..4 helpers set the mapNum & 16 self-clear bit either

So crossing ids 1..4 does not currently show any recovered mechanism that would arm id 5, advance a shared link counter, or mutate a helper object.

The strongest current interpretation is:

  • ids 1..4 are sibling scan lanes in the same authored corridor
  • they are not the required setup for wall fixed:3964
  • the only lane that still lines up with the wall is the paired id-5 trigger near the wall face

So for practical gameplay testing, ids 1..4 can be dropped from the step list. If the wall opens at all through this local trigger cluster, the critical movement should be the paired id-5 strip crossing beside the wall, not a full 1 -> 2 -> 3 -> 4 -> 5 sweep.

Map 13: Door-Family Closure And Remaining Gap

The wall face itself is now better closed than the opener.

  • fixed:3964 is shape 0x01AB
  • recovered DOOR.slot_21 handles shape 0x01AB by dispatching DOOR2.slot_2C
  • DOOR2.slot_2C is the actual open animation for this wall family: it advances frames 1..11, then changes the item to shape 0x0215
  • shape 0x0215 is a non-solid, non-drawn terrain state in the exported reference data, so this is a real hidden-wall-open transition rather than just a cosmetic frame swap

So the unresolved part is no longer what the wall does when opened. The unresolved part is still the caller that reaches DOOR.slot_20 -> DOOR.slot_21 -> DOOR2.slot_2C for this specific wall.

The most important newly ruled-out direct-caller families on map 13 are:

  • no controller-family object near this wall room with local QLo = 202
  • no family-4 egg on map 13 whose encoded egg id is 202
  • no nearby SECRTEGG or DOOREGG close enough to target this wall through the recovered secret-door scan radius
  • no nearby watcher / secret-door-post family object in the wall room

That leaves the current state as:

  • the local id-5 trigger strip is proven to fire a real local trigger lane
  • the wall face is proven to have a real hidden-door open path
  • the exact authored bridge between those two facts is still not closed from the current recovered data

So the exact player steps for opening fixed:3964 are still unresolved. The current local egg/CMD corridor remains evidence-bearing, but it can no longer be promoted to a verified opener sequence.

Map 1

  • wall: fixed:6850
  • visible wall face near 53278, 61054, 96
  • nearby trigger egg: shape 0x0011, mapNum = 17, near 53662, 61086, 104
  • nearby CMD helper: shape 0x04B1, quality = 0x0111, near 53566, 61054, 96

This case gives the strongest byte-level confirmation because the CMD helper QLo is 17, which matches the egg id mapNum = 17 exactly.

Map 27

  • wall: fixed:6510
  • visible wall face near 20938, 23870, 3
  • nearby trigger egg: shape 0x0011, mapNum = 15, near 19966, 23582, 0
  • nearby CMD helper: shape 0x04B1, quality low byte = 15, near 19934, 23614, 0

This is the loosest of the three examples, but it still fits the same egg-id -> CMD QLo neighborhood pattern and falls inside the wider movable-wall cluster distance used by the overlay.

Viewer Rule

The current implementation does not try to solve every movable wall in the game. It only draws this verified cluster:

  • source egg class: TRIGEGG or ONCEEGG
  • match byte: egg mapNum == nearby CMD helper QLo
  • CMD helper must be item-targeting and locally near the egg
  • CMD helper must also be locally near one of the checked movable-wall face shapes

Current movable-wall target shape whitelist:

  • 0x01AB
  • 0x0393
  • 0x03E8

Those shapes came from the inspected examples above. If future investigations recover more walls using the same cluster, extend the whitelist only with checked placements.

Why Not Reuse The Existing Door Rule

The older door overlay path expects a direct same-egg-id or same-QLo match against door-family targets.

These walls did not fit that assumption cleanly:

  • the opener signal is carried by a nearby usecode egg id
  • the local 0x04B1 helper is the observable routing object beside the wall
  • at least one checked wall face does not expose the same QLo as the helper

That is why the viewer now treats this as a separate trigger-cluster overlay instead of quietly broadening the generic door whitelist.