8.6 KiB
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
CycleProcessrows written into palette entries8..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/animSpeedrules 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:
- many editor/helper shapes are tagged
SI_TRANSLand use the low Crusader translucent xform slots - those low slots map heavily to source palette indices
8..14 CycleProcess_Updateadvances those same palette rows globally- when editor/helper sprites use those slots, they inherit the flashing/cycling colors automatically
- some shapes also have nonzero
animType, so they change frame as well as color
Evidence Base
Live CRUSADER.EXE / Ghidra side
CycleProcess_Updateat1438:011badvances the shared palette-cycle rows and writes them back throughSuperVGA_SetPaletteColorat1438:0366- the same recovered cycle rows already explained the F7-family overlay colors in docs/f7-overlays.md
Gamepal_InitXformpalDatStruct/Gamepal_LoadXformpalDat/Gamepal_ReadXformpal_1028_0348at1028:01db,1028:0250, and1028:0348are the live xform-palette load pathItemType_LoadTypeflagDat/Item_GetTypeflagDataat10f8:0275/10f8:0336are the live typeflag load/access anchors for the 9-byte CrusaderTYPEFLAG.DATrowsItem_PaintSpriteat1198:02e4still skipsSI_EDITORin 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.
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.DATis a 9-byte format - byte
4high nibble =animType - byte
5low nibble =animData - byte
5high nibble =animSpeed - byte
6bit0=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_InitColorTablesseeds the cycle rowsCycleProcess_Updateadvances them- the rows are written back into live palette entries
8..14
Those same rows already drive:
- plain
F7 Alt+F7Ctrl+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= byte4high nibbleanimData= byte5low nibbleanimSpeed= byte5high nibble
Recovered/open-source animation behaviors used by the viewer:
animType 1/3: increment through frames;animDatachooses unconditional, 50%, or block-loop behavioranimType 2: random frame changesanimType 4: random start, then run through framesanimType 5: usecode-driven animation hook; viewer leaves this as static because the live script side is not reproduced hereanimType 6: loop from frame1while leaving frame0as a resting/sentinel state
Viewer Implementation
Metadata fixes
The map renderer now carries all three Crusader animation fields through the exported shape definition:
animTypeanimDataanimSpeed
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
CycleProcessrows written into palette entries8..14 - translucent editor/helper sprites really do depend heavily on those same low slots
- Crusader
TYPEFLAG.DATcarries realanimType/animData/animSpeedfields 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
gametickanimation 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 5shapes
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:0336for the Crusader 9-byte typeflag animation/editor field layout1438:011bfor the shared palette-cycle row reuse by both F7 overlays and translucent editor/helper colors