Crusader_Decomp/docs/f7-overlays.md
2026-04-02 01:15:16 +02:00

12 KiB

F7 Debug Overlays In Retail CRUSADER.EXE

This note documents the three cheat-gated F7-family overlays in the live NE CRUSADER.EXE database and what each one represents on screen.

The practical keyboard side is already summarized in docs/ne-segment1.md. This file focuses on the overlay consumers themselves, the recovered geometry math, and what the map viewer can safely reproduce from static scene data.

Toggle points

Inside World_HandleKeyboardInput_13e8_14b4, the three overlay hotkeys toggle three different globals before forcing a camera refresh through the active camera process:

  • 13e8:1a7c toggles 1478:2bca for plain F7
  • 13e8:1a50 toggles 1478:2bc9 for Alt+F7
  • 13e8:1a20 toggles 1478:0ee0 for Ctrl+F7

All three are still gated by the broader cheat/debug latch at 1478:0844, so they are part of the Laurie/debug family rather than always-on retail UI features.

The live database and exported evidence agree on the three consumers:

  • Camera_1180_15ef handles the plain F7 grid and the Ctrl+F7 egg-hatcher overlay
  • Snap_1058_0814 handles the Alt+F7 snap overlay
  • EggHatcher_1090_0921 handles the Ctrl+F7 diamond outlines through the shared helper at 1180:1ce5

Palette colors and flash timing

The overlay colors are not hardcoded RGB values inside the overlay consumers. They are palette-indexed line draws that ride the shared CycleProcess palette animator in segment 1438.

Recovered retail evidence now closes the important pieces:

  • CycleProcess_InitColorTables (1438:0480) seeds the runtime color-cycle tables at 1478:6848..1478:6871
  • CycleProcess_Update (1438:011b) advances those rows by +2 intensity units per update tick and writes them into palette entries 8..14
  • Snap_1058_0814 pushes color index 0x09
  • EggHatcher_1090_0921 pushes color index 0x0d
  • Camera_1180_15ef stores and uses color index 0x0e for the plain F7 grid lines

So the current overlay-to-palette mapping is:

  • plain F7 grid = palette color 14
  • Alt+F7 snap overlay = palette color 9
  • Ctrl+F7 egg-hatcher overlay = palette color 13

The recovered cycle rows explain the visible behavior:

  • color 9 is a blue ramp that rises 0 -> 63 in steps of 2 and wraps
  • color 13 is a white ramp that rises 0 -> 63 in all three channels in steps of 2 and wraps
  • color 14 is primarily a green ramp, but its row is flagged through the special word-flag == 1 path, so each wrap injects an additional small random-looking RGB offset before the next ramp cycle

For the viewer that means the correct match is not one static CSS color per overlay. The viewer should simulate the same discrete palette-cycle phase and then derive the on-screen RGB from the live palette index assigned to each overlay.

The retail game is updating those colors in its normal engine/palette lane, not in a browser-style wall-clock timer. For the viewer it is acceptable to run the same phase logic at a slower cadence if that produces a closer visual impression on a modern display.

Plain F7: coarse world-cell grid

What it represents

Plain F7 is the simple debug background grid. It is not an object-family overlay and it is not tied to egg processes.

Current best read from the live camera path is:

  • the grid is aligned to the world coordinate lattice
  • each coarse cell is 0x200 world units wide in both world axes
  • the visible shape is an isometric diamond because the game projects the world lattice into screen space

That means the overlay is best understood as a coarse world-cell coordinate grid useful for orientation and spatial debugging.

Viewer reproduction rule

The viewer should not anchor this grid to the middle of the screen. The right model is:

  • use the world origin-aligned 0x200 x 0x200 lattice
  • project every visible coarse cell that intersects the current viewport
  • let the lattice continue indefinitely across the visible world instead of only drawing a fixed 3 x 3 patch around the viewport center

That is closer to the game-space meaning of the overlay than a screen-centered approximation.

Ctrl+F7: egg-hatcher trigger diamonds

What it represents

Ctrl+F7 is not a third generic grid. It visualizes the trigger footprint used by live EggHatcherProcess objects.

The live control flow is:

  • 13e8:1a20 toggles 1478:0ee0
  • Camera_1180_15ef checks 1478:0ee0
  • eligible live EggHatcherProcess objects are routed through EggHatcher_1090_0921
  • EggHatcher_1090_0921 calls the shared diamond helper at 1180:1ce5

The process/runtime note in docs/ne-segment1.md already closes the gameplay meaning: for non-monster egg families, these processes watch an avatar footprint against egg-centered X/Y/Z trigger windows and fire hatch or unhatch behavior on boundary crossings.

Geometry source

The recovered runtime uses the same egg range values that the process runner tests:

  • Egg_GetXRange(itemno) returns the high nibble of the egg-range byte
  • Egg_GetYRange(itemno) returns the low nibble of the same byte
  • each nibble expands in steps of 0x40 world units in the current viewer-side evidence model
  • the vertical window is about +/- 0x30 Z units

For authored family-4 usecode-trigger eggs in the viewer, the packed range byte already exists in the decoded map item payload, so the static reproduction is defensible.

Why it can appear blank in game

This overlay walks live EggHatcherProcess objects, not all possible egg-family map items. A blank Ctrl+F7 result only means there is no currently eligible live egg-hatcher outline being drawn at that moment.

Alt+F7: SnapProcess rectangles, not generic egg coverage

The important correction

The first viewer approximation treated Alt+F7 as a broad snap-oriented egg-family overlay. The recovered runtime is narrower than that.

The key proof comes from the object-entry path that feeds the snap process:

  • the live/extracted logic only calls Snap_AddSnapEgg when g_snapProcess != 0
  • and when the entering item's shape number is exactly 0x04fe

The exported live note at 10a0:2c82 summarizes the same behavior directly: when shape 0x4fe enters, we trigger the snap process.

So Alt+F7 is not a generic "all eggs" overlay. Its runtime source is the SnapProcess egg list, and the recovered producer for that list is currently tied to shape 0x04FE items.

Geometry source

The geometry is recovered more tightly now too, and the important detail is that the helper is not drawing a symmetric world-centered diamond from item_x,item_y alone.

The Snap_1058_0814 consumer does this per active SnapProcess entry:

  • qHiHiNibble = (Item_GetQHi(itemno) >> 4) & 0x0f
  • qHiLoNibble = Item_GetQHi(itemno) & 0x0f
  • mapSigned = sign_extend_8(Item_GetMapArray(itemno))
  • npcSigned = sign_extend_8(Item_GetNPCNum(itemno))

Then it builds the helper inputs as:

x_{helper} = item_x + qHiHiNibble \cdot 0x20 + mapSigned \cdot 0x20

y_{helper} = item_y + qHiLoNibble \cdot 0x20 + npcSigned \cdot 0x20

xRange_{helper} = qHiHiNibble \cdot 2

yRange_{helper} = qHiLoNibble \cdot 2

and finally calls the shared overlay primitive with color 0x09:

  • FUN_1180_1ce5(x_helper, y_helper, item_z, xRange_helper, yRange_helper, 9)

That helper works in projected screen space. Starting from the projected helper center, it emits a four-segment polygon with these deltas:

  • point A = center + ( yRange * 0x10, -yRange * 0x08 )
  • point B = point A + ( -xRange * 0x10, -xRange * 0x08 )
  • point C = point B + ( -yRange * 0x10, yRange * 0x08 )
  • close back to center

So the game is not drawing a simple min/max world rectangle and then projecting it. It is feeding an offset center and doubled nibble step counts into a dedicated screen-space overlay helper. That is why the earlier viewer reconstruction read too small.

In practical terms for the viewer:

  • use the BRO_BOOT / 0x04fe item as the authored source row
  • offset the helper center by the packed signed bytes and nibble terms exactly as above
  • use doubled nibble counts as helper step counts
  • reproduce the helper polygon itself rather than a centered approximation

This is materially different from the Ctrl+F7 egg-hatcher path:

  • Ctrl+F7 is tied to live EggHatcherProcess trigger windows
  • Alt+F7 is tied to the SnapProcess list and the explicit Snap_GetSnapEggRange rectangle math for shape 0x04fe

What the overlay represents

Current safest read is:

  • Alt+F7 visualizes snap-process coverage regions associated with the subset of runtime objects that are inserted into the SnapProcess egg list
  • those regions are authored through the 0x04fe item's own QHi, mapNum, and npcNum bytes rather than the generic family-4 egg-hatcher nibble layout
  • this is related to, but not identical with, the family-4 egg trigger overlay shown by Ctrl+F7

Probably related to the game's broader snap subsystem, but not proven as a pure camera-only feature.

What is directly supported by the recovered retail evidence is:

  • the overlay consumer is Snap_1058_0814, not a camera helper
  • the producer path adds only shape 0x04fe (BRO_BOOT) items into the SnapProcess list
  • an inline live note at 10a0:2c82 says that when shape 0x04fe enters, it triggers the snap process
  • another recovered note inside the SnapProcess body marks one related branch as snap to this egg

So the defensible statement is:

  • yes, it is related to the engine's snap behavior
  • no, the currently recovered evidence does not justify calling it only a camera-snap overlay

The best present label is still SnapProcess coverage or snap-region overlay, not camera snap grid. The subsystem may influence camera behavior, controlled-NPC placement, or both, but the proven path is the SnapProcess path itself.

Why BRO_BOOT appears to own it

The viewer-side tie to BRO_BOOT is not arbitrary. That shape tie is exactly what the retail producer currently shows.

Recovered producer behavior:

  • when g_snapProcess != 0
  • and a newly entering item has shape 0x04fe
  • the game calls Snap_AddSnapEgg

That is why the static viewer reproduction binds Alt+F7 to BRO_BOOT items. It is not because BRO_BOOT is being used as a loose guess for a nearby effect; it is because the current live evidence says those are the items that seed the SnapProcess overlay list.

Viewer guidance

The map viewer can reproduce these overlays with different confidence levels:

  • plain F7: strong static reproduction, because it is just a world-aligned coarse grid
  • Ctrl+F7: strong static reproduction for authored family-4 trigger eggs, because the packed X/Y range bytes are already decoded in scene data
  • Alt+F7: narrower static reproduction using only shape 0x04fe items and the exact recovered SnapProcess helper inputs and helper polygon; broader egg-family approximations should be avoided

Current viewer policy after the latest correction:

  • keep the palette colors matched to the recovered cycle-color indices
  • allow the viewer-side animation cadence to be slower than retail if the result reads more like the in-game flash on modern displays
  • prefer reproducing the helper polygon exactly over re-expressing it as a simplified centered world diamond

Evidence anchors

  • 13e8:1a20, 13e8:1a50, 13e8:1a7c: hotkey toggles in World_HandleKeyboardInput_13e8_14b4
  • 1058:0137: Snap_GetSnapEggRange
  • 1058:021b: Snap_AddSnapEgg
  • 1058:0814: Alt+F7 overlay consumer
  • 1090:0921: Ctrl+F7 overlay consumer
  • 1180:15ef: camera-side overlay helper
  • 1180:1ce5: shared diamond helper
  • 10a0:2c82: live note that shape 0x04fe entering triggers the snap process

Cross-reference evidence also lives in: