Skip to content
codingncaffeine edited this page Oct 6, 2026 · 1 revision

Parity

The goal is that everything the original game ships makes its way into SiegeFX and behaves the way it did. This page is the measurement. One command, siegefx parity ledger <install>, reads the original's data and the compiled engine and counts, for each kind of authored content, how much of it some engine path can act on. tools/receipts.sh runs it before every push and fails when a section handles fewer items than the committed baseline (goldens/parity-ledger.baseline.txt).

The ledger

2026-10-06, the GOG data, SiegeFX 0.4.0+bc91b30:

Section Authored Handled Gap By use An item counts as handled when…
commands 43 40 3 99.9% the command catalog the engine's dispatcher and NIS indexer consult lists it
trigger-verbs 24 23 1 99.8% the engine names the verb (triggers dispatch by name)
quests 31 30 1 96.9% the engine's quest catalog defines it (journal text and objective)
skrit-components 152 95 57 84.9% the engine names the script (a native replacement or the VM)
ai-jobs 118 3 115* 2.5% the engine names the job script
template-sections 170 114 56 98.4% the engine names the section
template-fields 934 397 537 81.9% the engine names the field
mood-fields 26 21 5 88.6% the engine names the field
ui-interfaces 125 13 112* 11.0% the engine names the interface
effect-keys 136 136 0 100.0% the effect engine reports the key consumed (live probe)
sounds 676 674 2* 99.7% a field the engine reads names the sound, or the engine names it itself
animation-skrit-api 31 17 14 73.2% the engine names the extern (bridge member or literal)

Authored counts the distinct items the data has; by use weighs each by how often the data uses it, so a field set on five thousand templates counts for more than one set once.

Handled is a ceiling, not a promise. It means some engine path can act on the item by name. Whether it then behaves as the original does is checked against the original itself, running beside SiegeFX under Proton (tools/ds1/).

* The native AI reimplements behaviours without naming the original job scripts, and most screens are native panels drawn with the original art that never name their interface file, so a job or screen they cover still counts as a gap until it is mapped. Sounds that no data names are left out (unused by the original, or played by its own code).

How each row is measured

  • Commands — the engine dispatches scripted commands through one catalog, and the ledger reads that same catalog, so the audit cannot disagree with the dispatcher.
  • Named rows (trigger verbs, skrit components, AI jobs, template sections and fields, mood fields, UI interfaces, the animation-script API) — the ledger reads every literal and member name compiled into the engine; an item is handled when the engine's code names it.
  • Quests — the engine's quest catalog.
  • Sounds — through the engine's own sound-database loaders: a sound is handled when a field the engine reads names it, or the engine names it.
  • Effect keys — a live probe: every authored effect script runs through the engine's effect VM, which reports the keys it consumed.

Every check was built with a planted fault it must catch.

What the gaps are

  • Commands (3): cmd_ai_c_drop, cmd_ai_c_equip, cmd_ai_c_stop — one use each, in the opening region.
  • Trigger verbs (1): start_camera_fx — 21 uses, all in elite-difficulty container templates.
  • Quests (1): quest_fort_kroth2, granted by a legionnaire's conversation.
  • Sounds (2): two button-press sounds named only in interface fields the engine does not read.
  • Mood fields (5): the music repeat and intro delays; the authored day length (timeofday.realminutesperworldhour — the world clock runs the authored 1.6 minutes per hour as a constant); two frustum fields used only by a stress-test map.
  • Template fields: the most-used unread ones are category_name, pcontent.modifier_min/max (the random magic modifiers on generated loot), aspect.priority, aspect.lodfi_upper/lower, mind.personal_space_range, common.membership, inventory.min_pile and trapped.fire_event.

Every gap, with an example of where the data uses it: siegefx parity ledger "<install>" --out=DIR writes one list per section.

Across Windows and Linux

  • Effect traces: every spell's cast effect run through the effect VM with a fixed seed. The 248 traces generated on Windows come out byte for byte on Linux; the gate compares all of them (goldens/sfx-timelines) before every push.
  • Movement: the chase-sim audit (1,122 pathfinder-verified walks) gives the same 49 failures on Linux as its last recorded Windows run.

Reproduce it

siegefx parity ledger "<your Dungeon Siege folder>" --out=parity
tools/receipts.sh        # the whole gate; --update-baseline records a deliberate change

Clone this wiki locally