Crusader_Decomp/docs/map_renderer/editor-item-animation.md
2026-04-02 01:15:16 +02:00

187 lines
No EOL
8.6 KiB
Markdown

# Editor-Item Animation In Retail Crusader And The Viewer
This note closes the current map-viewer animation lane for editor/helper objects that flash, cycle colors, or step through multiple frames.
The key result is that two different animation systems overlap in this lane:
- frame animation from Crusader `TYPEFLAG.DAT`
- palette-slot animation from the shared `CycleProcess` rows written into palette entries `8..14`
The viewer now reproduces both, with one important caveat:
- the frame-selection semantics are evidence-backed, but the exact retail wall-clock tick length is still not directly closed from the live DOS executable, so the viewer uses the recovered `animType/animData/animSpeed` rules with a viewer-side step cadence that stays in family with the already-recovered palette cycle
## Short Answer
The flashing editor walls and helper surfaces are not a separate editor-only special effect process.
Current best model:
1. many editor/helper shapes are tagged `SI_TRANSL` and use the low Crusader translucent xform slots
2. those low slots map heavily to source palette indices `8..14`
3. `CycleProcess_Update` advances those same palette rows globally
4. when editor/helper sprites use those slots, they inherit the flashing/cycling colors automatically
5. some shapes also have nonzero `animType`, so they change frame as well as color
## Evidence Base
### Live `CRUSADER.EXE` / Ghidra side
- `CycleProcess_Update` at `1438:011b` advances the shared palette-cycle rows and writes them back through `SuperVGA_SetPaletteColor` at `1438:0366`
- the same recovered cycle rows already explained the F7-family overlay colors in [docs/f7-overlays.md](docs/f7-overlays.md)
- `Gamepal_InitXformpalDatStruct` / `Gamepal_LoadXformpalDat` / `Gamepal_ReadXformpal_1028_0348` at `1028:01db`, `1028:0250`, and `1028:0348` are the live xform-palette load path
- `ItemType_LoadTypeflagDat` / `Item_GetTypeflagData` at `10f8:0275` / `10f8:0336` are the live typeflag load/access anchors for the 9-byte Crusader `TYPEFLAG.DAT` rows
- `Item_PaintSprite` at `1198:02e4` still skips `SI_EDITOR` in the normal gameplay renderer, so most of this animation is normally only visible on debug/editor/helper lanes unless another overlay or engine-side viewer exposes those objects
### Renderer-side direct pixel evidence
The earlier translucency pass already established that representative editor/helper translucent shapes are dominated by source palette slots `8`, `9`, `10`, `11`, `13`, and sometimes `14`.
Representative probe families:
- invisible/editor walls `0x005A..0x0069`
- helper `0x00E9`
- `Zappy_Surface_*` `0x044D` / `0x044E`
That evidence is recorded in [docs/map_renderer/translucency-xformpal.md](translucency-xformpal.md).
### Open-source Crusader engine cross-check
The missing frame-animation semantics are closed well enough by the Crusader-specific loaders in ScummVM and Pentagram:
- Crusader `TYPEFLAG.DAT` is a 9-byte format
- byte `4` high nibble = `animType`
- byte `5` low nibble = `animData`
- byte `5` high nibble = `animSpeed`
- byte `6` bit `0` = `SI_EDITOR`
The ScummVM Crusader item update path also preserves a concrete `animateItem()` switch for `animType` values `1..6`, which is enough to reproduce the frame-selection rules even though the exact DOS tick duration is still not directly timed in the live retail pass.
## Retail Model
### 1. Shared palette-cycle rows drive the flashing colors
This part is already directly evidenced from the live NE executable.
- `CycleProcess_InitColorTables` seeds the cycle rows
- `CycleProcess_Update` advances them
- the rows are written back into live palette entries `8..14`
Those same rows already drive:
- plain `F7`
- `Alt+F7`
- `Ctrl+F7`
The editor/helper flashing lane reuses that same machinery rather than inventing a separate color animator.
### 2. XFORMPAL makes the low slots matter for translucent editor/helper shapes
The editor/helper walls and related helper surfaces are often translucent, and their source pixels disproportionately use the low slot family `8..14`.
That means their apparent color is effectively delegated to the current shared cycle rows.
In practice, the visible rule is:
- if a translucent editor/helper sprite is built from those low slots, its hues will flash when the shared cycle rows change
### 3. Some editor/helper shapes also have real frame animation
Crusader typeflags also carry per-shape animation metadata.
Closed field layout for the Crusader 9-byte row:
- `animType` = byte `4` high nibble
- `animData` = byte `5` low nibble
- `animSpeed` = byte `5` high nibble
Recovered/open-source animation behaviors used by the viewer:
- `animType 1` / `3`: increment through frames; `animData` chooses unconditional, 50%, or block-loop behavior
- `animType 2`: random frame changes
- `animType 4`: random start, then run through frames
- `animType 5`: usecode-driven animation hook; viewer leaves this as static because the live script side is not reproduced here
- `animType 6`: loop from frame `1` while leaving frame `0` as a resting/sentinel state
## Viewer Implementation
### Metadata fixes
The map renderer now carries all three Crusader animation fields through the exported shape definition:
- `animType`
- `animData`
- `animSpeed`
The tooltip trait list now shows all three when present.
### Atlas/reference change
Static scene exports previously only guaranteed the specific frame used by the authored map item.
That is not enough for animated shapes.
The reference build now expands visible shapes with nonzero `animType` to include every frame from the shape archive, so the client can step frames at render time instead of getting stuck on the authored start frame.
### Palette-cycle reproduction
The client now carries a compact rendering descriptor for the low xform-cycle slots:
- source slot `8..14`
- the baked atlas RGBA that corresponds to the current XFORMPAL-remapped translucent output
At render time, translucent editor/helper sprites are copied into a small sprite canvas and any pixel matching one of those slot RGBA values is recolored from the current shared cycle-row RGB for the same slot.
That lets the viewer animate the same low-slot translucent editor/helper art without inflating the scene payload with raw pixel streams.
### Frame animation reproduction
The client now steps `animType` shapes using the recovered Crusader rules above.
Current approximation boundary:
- the semantic frame-advance rules are evidence-backed
- the exact retail wall-clock tick size is still not directly timed from live DOS execution
- the viewer therefore uses a stable viewer-side animation step that stays aligned with the already recovered palette-cycle cadence instead of pretending to know the exact original millisecond rate
That is good enough to reproduce the visible behavior for map-viewer/editor purposes without overclaiming a closed retail timing constant.
## Practical Scope In The Viewer
The current viewer pass targets the objects the user actually asked about:
- editor-tagged shapes
- helper/occluding editor geometry
- translucent editor/helper surfaces that inherit the low cycle slots
The frame-animation support is intentionally a little broader than the pure color-cycle support, because `animType` is real shape metadata and some animated map shapes are not strictly editor-only.
The palette-cycle recolor stays narrower and only applies to the translucent editor/helper lane where the evidence is strong.
## What Is Closed Versus Still Open
### Closed enough for the viewer
- the shared flashing colors come from `CycleProcess` rows written into palette entries `8..14`
- translucent editor/helper sprites really do depend heavily on those same low slots
- Crusader `TYPEFLAG.DAT` carries real `animType/animData/animSpeed` fields in the 9-byte row
- the viewer can now reproduce both the frame-step and palette-cycle sides in a defensible way
### Still open
- the exact live DOS wall-clock interval behind the per-item `gametick` animation updates
- whether any remaining helper families need a different XFORMPAL table than the current viewer default for hue reproduction
- the full live usecode behavior behind `animType 5` shapes
## Ghidra Notes Applied In This Batch
This batch also adds concise live-DB comments to keep the provenance visible at the key shared anchors:
- `10f8:0336` for the Crusader 9-byte typeflag animation/editor field layout
- `1438:011b` for the shared palette-cycle row reuse by both F7 overlays and translucent editor/helper colors
## Related Notes
- [docs/map_renderer/translucency-xformpal.md](translucency-xformpal.md)
- [docs/editor-object-visibility.md](../editor-object-visibility.md)
- [docs/f7-overlays.md](../f7-overlays.md)