Crusader_Decomp/docs/map_renderer/editor-object-survey.md
2026-04-05 18:27:09 +02:00

15 KiB

Editor/Helper Object Survey

This pass widened the renderer research beyond egg and NPC spawner objects and focused on editor/helper shapes that already carry useful classification data in the exported scene payload.

Evidence Base

  • The renderer already exports shapeDefinitions[*] entries with kind, family, dimensions, visibilityTags, traits, and the matching catalog entry.
  • The public catalogs already distinguish many non-gameplay helper families that are currently easy to miss in the UI.
  • Representative catalog anchors in Remorse include:
    • 0x005A, 0x005B, 0x005C, 0x005D, 0x0066-0x0069: invisible/editor wall objects
    • 0x01B8: camera
    • 0x0290, 0x0336: LIGHT_BRIDGE_*
    • 0x0337, 0x0361: placeholder cubes and placeholder UI/editor markers
    • 0x0108, 0x0113, 0x01B9, 0x01BA, 0x025F, 0x0260, 0x02F0, 0x0373, 0x0399, 0x03A1, 0x04C8: wallgun_shape_* helper cluster

0x0251 Frame 0: VALUEBOX

  • The recovered usecode corpus now closes 0x0251 directly as VALUEBOX in both retail games, not as a generic placeholder cube.
  • Current safest read is local payload box, not world prop: the object stores numeric or text-selection data for nearby authored controllers instead of behaving like a visible gameplay pickup.
  • The caller side is much clearer than VALUEBOX.slot_20(...) itself. Checked bodies that explicitly scan nearby shape=0x0251 items include:
    • MONITNS (0x0102) and MONITEW (0x0165)
    • WALLMNS (0x0367) and Regret WALLMEW (0x0436)
    • Regret SECURNS (0x03FB) and SECUREW (0x043D)
    • Regret WATCHNS (0x04C6) and WATCHEW (0x04DE)
    • KEYPAD (0x0A0E in Remorse, 0x0A0D in Regret)
  • Those families usually match the box on shared QLo, then call VALBOX.slot_20(valueBox) to recover the stored value. Monitor, wall-display, and security-terminal paths also feed Item.getQHi(valueBox) into TEXTFILE.slot_23(...), so QHi behaves like a second text/value selector rather than dead metadata.
  • VALUEBOX::cachein also hints at a small self-initialization lane: when the decoded value is zero it calls FREE.slot_20(0x0383) and writes a replacement through VALUEBOX.slot_20(...). The slot-20 decompilation is still weak, so the conservative read is possible value initialization, not a fully closed random-number claim.
  • Decompressed .cache scenes back the helper role strongly:
    • Remorse retail caches currently expose 299 frame-0 placements. The strongest nearby controller families in the local scan are MONITEW (90 hits), MONITNS (65), and WATCHEW (18).
    • Regret retail caches currently expose 171 frame-0 placements. The strongest nearby controller families are MONITEW (32), MONITNS (21), WATCHEW (20), SECURNS (11), SECUREW (6), and WALLMNS (6).
    • Most frame-0 boxes still carry quality = 0, which is consistent with the common QLo == 0 default-link path in the callers.
    • Rare authored payloads do exist: Regret map 29 has a VALUEBOX with quality 23 (QLo 23), and Remorse maps 25, 26, and 141 all contain a nonzero example at 53118,30558,96 with quality 828 (QLo 60, QHi 3, npcNum 2).
    • Many placements occur in small chained local clusters through nextItem, which fits a backing-store/helper role better than a standalone scene-prop interpretation.
  • Practical renderer implication: 0x0251 should be labeled VALUEBOX, should keep QLo, QHi, and nextItem visible in tooltips, and should be treated as a local controller payload object rather than as a generic placeholder cube.

What This Means For The Renderer

  • A lot of the useful information is already present without more reverse-engineering. The main problem was presentation, not raw data availability.
  • Editor/helper objects often carry meaningful mapNum, npcNum, quality, or nextItem values even when they are not DTABLE-backed NPC spawners. Those raw linkage values are worth exposing because they help separate placeholder geometry from logic markers.
  • Catalog names already identify several broad classes that deserve different handling in the UI:
    • invisible walls/editor walls
    • camera/helper markers
    • light bridge / forcefield / editor-authored bridge surfaces
    • placeholder cubes and placeholder UI markers
    • auto-derived helper shapes tied to specific USECODE families like WALLGUN

Focused Caution: Suspicious Map Objects Are Not Always Helpers

  • The map-13 jump-start follow-up around the rare jump-through wall found one especially suspicious nearby placement: fixed:4767, shape 0x0135, frame 0, at world 47966,53598,97 in the decoded retail cache.
  • That object looks tempting as an editor/helper candidate when viewed only from map placement, but the decoded reference data says otherwise: 0x0135 is shape:309, a terrain item with dimensions 4 x 4 x 0 and traits solid, fixed, and land.
  • The useful classification came from USECODE rather than from the exported editor/helper buckets. In the extracted corpus, class 0x0135 is FFFLOOR, an environmental hazard/controller family with live gotHit, equip, and unequip bodies.
  • The nearby map-13 companion object is not an editor wall flag or a hidden collision override either. The closest local trigger on the same upper platform is the family-4 egg fixed:4770 (shape 17, egg id 37, subtype selector QLo 4), which currently resolves to CHANGER, not to a direct wall-solidity helper.
  • Practical renderer implication: when a placement looks suspicious in map context, do not assume it belongs in the editor/helper bucket just because it sits beside editor markers. 0x0135 is a good counterexample: it is a gameplay-side environmental floor tile that only becomes legible once the USECODE class is identified.

Implemented UI Enrichment

The tooltip now exposes generalized metadata for editor/helper objects instead of reserving extra detail almost entirely for NPC spawners:

  • Dimensions: shape dimensions from the exported shape definition
  • Tags: exported visibility tags such as editor, helper, egg, roof, and oob
  • Traits: exported rendering/collision traits such as occluding, translucent, solid, fixed, and nonzero animation type
  • Role hint: a cautious catalog-backed note for important helper families like invisible walls, cameras, light bridges, placeholders, WALLGUN helper shapes, 0x04D0 NPC spawners, and 0x024F monster eggs
  • Raw linkage: map, npc, quality, and next fields for editor/helper/egg objects so unresolved objects still expose their control data

Practical Next Targets

  • Add dedicated filters or list views for helper subfamilies such as invisible walls, camera markers, light bridges, and placeholder cubes.
  • Add shape-family frequency summaries so repeated helper markers can be audited across a map.
  • Decode more shape-specific field semantics for the still-unresolved editor objects, especially the remaining non-promoted invisible-wall, camera/helper, music-controller, and secret-door-switch families, and keep folding any new results back into the dedicated USECODE-link note.
  • Find the No Regret replacement for the Remorse 0x024F monster-egg workflow instead of assuming the same shape is reused.

0x0318 Frame 0: CRUMORPH

  • The older placeholder cube label is no longer the best behavioral read for 0x0318. Both extracted corpora now name class 0x0318 as CRUMORPH: Remorse EUSECODE_extracted/class_event_index.tsv entry 173 and Regret REGRET_USECODE_extracted/class_event_index.tsv entry 174 both expose a live equip body at slot 0x0A.
  • The two recovered equip bodies differ slightly in helper naming, but they agree on the same high-level lane. Both scan nearby family-6 actors, compare the pad QLo against mutable actor field 0x63, reject dead actors, transfer control to the first live match, wait until control sticks, and then dispatch TRIGGER.slot_20 lane 0 or 1 depending on whether that controlled actor is still alive.
  • Current best read is therefore control-transfer morph pad, not decorative cube and not DTABLE-backed NPC spawner. The object's authored low quality byte is the local control key; npcNum does not carry the actor target directly, and the actor-side match is not a stable exported scene field.
  • Static scene evidence is strongest in Regret, which is why the viewer promotion was first justified there. The decompressed .cache scenes repeatedly show nearby same-QLo 0x04B1 helpers close enough to expose a cautious local CRUMORPH -> CMD_LINK overlay rule.
  • The deeper actor-target side remains intentionally unexported. The same actor-key follow-up that covered NPC_ONLY still applies here: the compared actor byte is mutable field 0x63, and recovered TRIGGER.slot_29 / slot_2B lanes can rewrite it after load. That keeps CRUMORPH -> actor arrows out of the viewer for now.
  • Practical viewer implication: 0x0318 should be labeled CRUMORPH, should expose its QLo / QHi / mapNum / npcNum / nextItem bytes in tooltip metadata, should open CRUMORPH::equip from the USECODE action, and should keep only the already-evidenced nearby same-QLo 0x04B1 arrows.

Newly Promoted Regret-Only Controllers

  • 0x0366 remains NPC_ONLY, but the latest decompressed .cache sweep tightens its practical viewer behavior: actor-target arrows are still not justified, while cautious local NPC_ONLY -> 0x04B1 same-QLo arrows are now strong enough to expose.
  • 0x04c6 / 0x04de are now promoted as WATCHNS / WATCHEW, not generic editor leftovers. Their recovered slot_20 bodies scan nearby 0x0510 posts by shared QLo and then bracket TRIGGER.slot_20 around a watcher-specific follow-up lane.
  • 0x0510 is now better treated as a SECRET_DOOR_POST helper target rather than an unresolved standalone controller. The strongest current viewer behavior is a cautious local arrow from WATCHNS / WATCHEW plus tooltip decoding of its QLo/QHi bytes.
  • 0x05e1 is closed as CRYOBOX, and nearby 0x05df / 0x05e0 pressure-barrier faces are now promoted out of the unresolved bucket as local arrow targets keyed by shared QLo.
  • 0x0451 / 0x05ae are now closed as CRAZYEW / CRAZYNS, small Regret-only hit-driven NPC wake-up relays rather than vague contextual map labels.
  • 0x056d is now closed as VIDEOBOX, a gated controller with a direct equip body, even though its higher-level gameplay meaning is still less explicit than the watcher and cryobox lanes.

Shared Trigger Follow-Up: 0x00A2, 0x03C1, And 0x04E7

0x04E7 Frame 0: DEATHBOX In Both Games

  • The npc death icon label now has a clean cross-game closure, not just a Remorse-side guess. Both extracted corpora expose class 0x04E7 as DEATHBOX, and both corpora keep the active exported body at slot 0x0A (equip / func0A).
  • That means the Remorse equivalent is exact rather than approximate: same shape id, same class label, same nearby-DEATHBOX scan from NPCDEATH.slot_20, and the same practical viewer interpretation as an NPC-death helper/controller keyed by local QLo.
  • Practical viewer implication: Regret should no longer leave 0x04E7 as an anonymous editor object when the underlying usecode/export evidence already matches Remorse exactly.

0x00A2: PANELEW

  • Both extracted corpora now close 0x00A2 directly as PANELEW, the east-west counterpart to PANELNS, not as a generic unnamed wall button.
  • Recovered body PANELEW::use is small but consistent across both games:
    • if frame == 0, it returns immediately
    • otherwise, if the panel's map byte is clear, it dispatches TRIGGER.slot_20 lane 0 from the panel item itself
  • The handler does not need to read a second bespoke target field because the downstream trigger family already uses the panel's local QLo as the practical authored link id.
  • Practical viewer implication: 0x00A2 should be labeled PANELEW, should open PANELEW::use from the USECODE action, and should participate in the same cautious nearby same-QLo 0x04B1 helper-arrow rule already used for PANELNS and other local switch/controller shapes.

0x03C1: GENERATR

  • The old generator hunch is directionally right, but the extracted name is now explicit in both games: class 0x03C1 is GENERATR.
  • The direct active lane is very small and decisive. GENERATR::gotHit does not contain a long custom destruction script; it simply excludes the source item and immediately spawns TRIGGER.slot_20 lane 0 from that same item.
  • Current safest read is therefore destroyable generator/controller rather than free-standing scripted puzzle object: destroying it is useful because it forwards the object's local trigger key into the standard trigger network.
  • There is also a second, narrower set-piece lane in Remorse. Recovered SATARG::use explicitly scans nearby shape=0x03C1 items during its countdown/shutdown sequence and drives them through ITEM.slot_28 beside the related 0x03BF bank, which fits authored generator-bank or power-node shutdown scenes rather than a different standalone class meaning.
  • Practical viewer implication: 0x03C1 should be labeled GENERATR, should open GENERATR::gotHit from the USECODE action, and should expose the same cautious nearby same-QLo 0x04B1 helper arrows as other trigger-source objects because its recovered destruction lane feeds directly into TRIGGER.

Actor-Key Family Follow-Up

  • The latest actor-link follow-up did not justify exporting a stable NPC_ONLY -> actor or CRUMORPH -> actor overlay from static map/cache data alone.
  • Current best read is that the compared value is mutable actor field 0x63, not a DTABLE row and not a field that the current scene export already carries.
  • A direct Regret DTABLE row check at byte offset 0x63 is not enough to rescue that idea: sampled rows still read as zero there, so the actor key is not simply a persistent NPCDat attribute that can be copied through the existing preview pipeline.
  • The same corpus also shows why the field is unstable: TRIGGER.slot_29 / slot_2B can rewrite actor field 0x63 on nearby matched NPCs, so the relevant actor-side link id can change after startup.
  • The broader family using this same hidden actor-key mechanism is now clearer though: CRUMORPH, NPC_ONLY, WATCHNS, WATCHEW, THRMBCKN, THRMBCKE, SURCAMNS, and SURCAMEW all compare controller-local bytes against actor field 0x63 in one of their recovered lanes.
  • Practical renderer stance stays conservative: keep only the already-evidenced local helper arrows in the overlay, and surface the actor-key behavior in metadata/tooltips until a runtime or spawn-time export can close field 0x63 directly.

0x04B1 now has a stable CMD_LINK -> TRIGGER.slot_20 viewer target, and 0x04E3 is already promoted as SKILLBOX::equip, so they no longer belong in the unresolved editor-object bucket here.