Repository navigation
Releases: VirInvictus/opends
Release list
xmi2mid-v0.1.0
xmi2mid v0.1.0 (2026-10-06)
- xmi2mid 0.1.0: the XMI-to-MIDI converter (mineout Phase A
deliverable 2), branch-aware where the classic public-domain
xmi2mid flattens. Each sequence payload becomes a format-0 SMF
at 120 Hz (ticks map 1:1, note-ons resolved to real note-offs)
plus a JSON sidecar carrying the RBRN branch table, FOR/NEXT
loop spans, branch-select events, and TIMB patch lists, so a
port's music director can reproduce the adaptive behaviour the
Mel library runs (file-formats.md 5). All 83 DS1 sequences and
all 36 floppy-tree DS2 sequences convert; branch counts match
the dig's independent table (byte check corrected its track-8
LSEQ/PSEQ entries to 6), and the floppy set is branch-free,
matching the no-RBRN-in-DS2 finding. The conversion pinned two
container quirks: shipped XDIRs declare their FORM size as
covering only INFO, with CAT following as a sibling past the
declared extent, and EVNT chunks may carry trailing pad bytes
after the EOT meta (the decoder stops at EOT). Synthetic-payload
selftest covering both quirks is wired into CI.
ovr-map-v0.3.6
ovr-map v0.3.6 (2026-10-07)
ovr-mapv0.3.6: the Mel-name adoption batch. Eleven new
verified rows insyms/ds2.tomlname the embedded Mel audio
library end to end:mel_error(the fatal-error reporter, whose
version string pins DS2's library at "Mel Real Mode Version
2.2.7"),mel_register_graphic_shutdown,mel_open_animation,
mel_animation_manager(the game-visible branch consumer: XMIDI
callback values 1..0x22 switch the music branch, the RBRN
follower), the branch pairmel_break_loop_and_branch_to/
mel_branch_to(BreakLoop has zero static callers in the
shipped image: retained API, unused, consistent with DS2
carrying no RBRN), the wait pairmel_measure_wait/
mel_beat_wait, and three data cells:
gmel_indirect_control_array(ICA[0] = desired branch, ICA[0x7f]
= the loop-break flag the NEXT events consume),
gmel_current_branch,gmel_branch_taken. Ground truth: the
DSO v1.0 client's own intact Mel layer, disassembled from
.dso-online/tools/mdark.binat the symbols.txt offsets (only
AIL proper is stubbed there); all eleven carrydso_source.
The catalogue now names 143 DS2 locations (135 verified, 14
DSO-sourced). Evidence: docs/port-digs-2026-10-07.md 1.
ovr-map-v0.3.5
ovr-map v0.3.5 (2026-10-06)
- ovr-map 0.3.5: the symbol catalogue grows by twelve
verified DS1 rows from the capability/trigger digs (the
capability mask builder and walker, evidence in
docs/port-digs-2026-09-21.md 2; the GPL script entry, executor,
opcode dispatcher, and the seven trigger-table plumbing
functions: sorted inserts, link-in, allocator, remove-head, and
both flush stages, evidence in docs/port-digs-2026-10-06.md 3).
All twelve are resident and verified; DS1 takes no DSO names
(wrong codebase heritage), so the rows are descriptive with the
digs as their evidence chain. The release also carries the
September corrections the catalogue had been waiting on: five
existing rows move to corrected addresses (DS1 load_resource to
0x29ea4 via the segtab byte-offset reading, DS1 overlay_manager
to 0x3be27, DS2 load_resource to 0x2e69b, DS2 overlay_manager to
0x40544, DS2 save_record_writer to 0x08e3) and the README's
overlay-descriptor notes are corrected (relocation count is in
bytes; the stub's fifth byte is reserved). Names render in
--disasm,--verify, and--callgraphwith--syms.
opcode-fuzz-v0.3.1
opcode-fuzz v0.3.1 (2026-10-07)
opcode-fuzzv0.3.1: the recipe loop's first real drive.
The full extract -> author -> pack -> run -> DARKRUN-diff loop
works end to end: the swap-and-run synthesised its repro
fixture, booted DS1 through the repro harness, and computed the
world-state diff. The drive caught two latent tool bugs, both
fixed: the synthesised fixture's TOML refused the DOS redirect
path (DSUN.EXE > d:\dsun.logemitted as an unescaped basic
string; now a single-quoted literal), and the factory
DARKRUN.GFF pre-snapshot still looked under the retired
__support/save/layout (now the canonical install file). The
first probe (twogpl byte inc GBYTE[100]sentinels around a
gpl global ret, swapped into boot candidate GPL-9) booted
clean and returned an identical-file diff, which settles the
probe design: VM-state sentinels do not surface in the
world-state file, so recipes need a world-visible epilogue
(agpl request 5toggle whose visible-object record the world
file carries) or a save-based diff. The recipe-format decision
is settled on that evidence: the 15 unnamed gap opcodes are
Custom-param and best-effort-refused by gpl-asm, so probes wait
on one encoder feature (rawdb <hex>emission), after which
recipes are plain.asmfiles andfuzz <opcode>is a thin
driver. recipes/README.md carries the drive record and the
decision.
Mining completion (2026-10-06): the document guide
The mining release: a guide to the documents
This release posts the annotated inventory of OpenDS's static-mining
campaign: every document the campaign produced or rewrote, tagged,
described, and explained. The campaign's assignment was to mine SSI's
Dark Sun CRPGs (Shattered Lands 1993, Wake of the Ravager 1994)
until nothing was left to dig: every chunk kind documented with
offset-level evidence, every named reverse-engineering hole resolved
or closed as a written negative. The bar was mechanical, and it is
met: the format-coverage gap list is empty, 57 of the 78 catalogued
chunk kinds appear in the corpus and every one of them is documented,
and the other 21 are proven never to have shipped as
chunk kinds in any held artifact.
Two things make this batch trustworthy rather than merely voluminous.
First, every document cites its evidence: file paths, byte offsets,
instruction dumps, and corpus counts that anyone with the GOG install
can re-derive. Second, before release, four independent
claim-verification passes re-ran the corpus counts, re-decoded the
cited bytes and tables, and re-executed the tools from scratch. They
confirmed every headline finding and caught eleven wrong secondary
details (a converter bug that failed 41 of 83 music files, a sample
rate generalized from half the corpus, a song pool off by one, two
miscounts, three offset slips, and a version bump that never reached
the build file). Everything below reflects the corrected state. Where
a claim is still open or a guess, the document says so in those
words; this guide preserves those flags.
All documents live in the repo at the tag this release points to;
links below resolve to that exact tree.
The inventory (every mined document, tagged)
| Document | Tags | One line |
|---|---|---|
docs/port-digs-2026-10-06.md |
NEW · dig record | The campaign's lab notebook: ten sections, one per closed question, each with the decisive offsets. |
docs/audio-cues.md |
NEW · audio | Which script requests which sound: 684 call sites across both games, with durations and context-derived meaning guesses. |
docs/format-coverage.md |
NEW · regenerated | The completion bar itself: machine-generated, gap list empty, 57/78 kinds in corpus. |
docs/file-formats.md |
EXTENDED · CORRECTED | The format reference. Twelve new or rewritten sections; two long-standing claims corrected. |
docs/audio-routing.md |
CORRECTED | The id-to-sound routing model; DJ.DAT's layout description fixed. |
docs/object-formats.md |
EXTENDED · CORRECTED | The record layouts; the combat block's special-attack machinery resolved on both sides. |
docs/rules-tables.md |
EXTENDED | The AD&D-rules layer; the derived-stats question closed and overlay 46 named. |
docs/bestiary-ds1.md, docs/bestiary-ds2.md |
CORRECTED | The per-creature catalogues; their "enum candidates, not shown" era ends. |
docs/spell-effects.md |
EXTENDED · CORRECTED | The spell engine; gains the corrected special list and DS2's fire gate. |
docs/combat-flow.md |
EXTENDED | The combat loop; the "behind the frame wall" note resolves into named code. |
docs/screen-flow.md |
CORRECTED | The screens; the 14-byte PREF claim fixed at 11/9 bytes. |
docs/exploration-flow.md |
CORRECTED | The movement layer; the trigger-table cells are list heads, not function pointers. |
docs/dso-symbols.md |
EXTENDED | The Dark Sun Online symbol index; coverage snapshot and the adoption ledger. |
tools/audio-extract/ |
NEW · tool v0.1.0 | Opens every audio box: WAVs, payload dumps, inventories, and the cue sweep. |
tools/xmi2mid/ |
NEW · tool v0.1.0 | Branch-aware XMI-to-MIDI conversion with the adaptive-music sidecar. |
tools/gff-edit/ |
tool v0.6.3 | The container foundation; its kind catalogue now matches the corpus exactly. |
tools/ovr-map/ |
tool v0.3.5 | The overlay mapper; twelve new verified DS1 symbols from the trigger digs. |
Part 1: the maps (start with these three)
docs/format-coverage.md: the completion bar, zeroed
Every Dark Sun data file is a GFF container: a table of contents
listing chunk types by FOURCC, then the chunks themselves. The
campaign's mechanical bar was that a machine-generated report,
format-coverage.py, finds no chunk kind in the shipped games that
our documentation does not describe. This release regenerates that
report against a 78-kind catalogue: 57 kinds appear in the corpus and
all 57 are documented; the other 21 are the subject of Part 4 below.
The report also pins the corpus itself: 120 GFF containers across the
GOG installs and the Internet Archive release-lineage trees, and 584
other files (binaries, patches, media) accounted for. When someone
asks "is there anything left to dig?", this file is the answer, and
the answer is no.
docs/port-digs-2026-10-06.md: the lab notebook
Ten sections, one per closed question, each written the day the dig
concluded and each carrying its decisive evidence (the instruction
bytes, the table dumps, the caller chains). It is the document to
read when a summary here is not enough. In order:
- DATA (the DS2 spell-system file, below in Part 3).
- RBRN (the adaptive-music tables, Part 2).
- The capability lists (the steal/talk/give machinery, Part 4).
- The never-shipped census (Part 5).
- The wave-2 kind decodes: MAP, VECT, CMAT, CPAL (Part 3).
- Armour overlays, disproven (Part 4).
- The bestiary special-attack enums (Part 4).
- Combat +8/+10/+12 and overlay 46 (Part 4).
- The save-kind quartet: PLYL, ALL, GREQ, PREF (Part 5).
- Session state, the running index.
docs/file-formats.md: the reference itself
The document a tool author actually reads. This release adds twelve
sections and corrects two claims. The additions: DATA (Part 3), VECT
(the 256-direction circle, Part 3), CMAT and CPAL (the DS1 still
frames and their palettes, Part 3), PLYL / ALL / GREQ / PREF (Part 5),
the full XMI container hierarchy with the adaptive-music machinery
(Part 2), the BVOC payload structure (Part 2), the never-shipped
census (Part 5), and the measured identifications of every external
file (Part 5). The corrections: the old text claimed XMI delta times
were "two bytes per event"; the corpus says they are runs of bytes
under 0x80 summed up to the next status byte. And the old audio
presence table implied all samples were 8000 Hz; the corpus holds two
rates (Part 2).
Part 2: the audio documents (sound, music, and the machinery that plays them)
docs/audio-cues.md: who asks for which sound
The games play sounds two ways: the script VM requests them by id
(gpl sound), and the engine fires some by itself (UI clicks, combat
resolution). This document is the complete map of the first kind. A
sweep of the disassembled bytecode found 251 sound requests in DS1
covering 55 distinct ids, and 433 in DS2 covering 127 distinct ids
plus one computed at runtime, all of them in each game's GPLDATA.GFF.
For every id the table gives: the matching digital-sample chunk (DS1
sound id equals its BVOC chunk id; DS2's mapping adds one), its
duration, how many scripts call it, and a meaning guess derived from
the strings the calling script prints nearby ("bashes down the door!",
"Soldiers, cover my retreat!"). Three facts fall out: gpl music is
never emitted in either game, so music ids have no static binding
(the engine will not contradict whatever a port chooses); four
scripted DS1 ids point at samples that do not ship (19, 30, 87, 127:
those call sites are silent in a stock install); and 56 of DS1's 111
samples are never script-referenced at all, meaning they are engine-
driven and their naming needs the planned ear pass. Every meaning in
the table is labelled a guess; the ear pass remains the confirmation
step.
The BVOC facts (docs/file-formats.md, BVOC section)
The 815 digital-sound chunks across every release decode completely:
499 samples at 8000 Hz and 316 at 10989 Hz (the 10989 set is DS2's
resource file and its byte-identical CD twin), all 8-bit unsigned
mono, 1386.9 seconds total, zero failures. Each payload is a
well-formed Creative Voice File with exactly one sound-data block;
two carry repeat markers. The tool behind this is tools/audio-extract
(v0.1.0), which also produced 815 WAVs and a machine-readable
inventory.
The music: XMI, RBRN, and the adaptive loop (docs/file-formats.md, XMI section; port-digs 2)
Each music chunk is an XMI: a FORM/XDIR directory wrapping a song
form of TIMB (patch requests), RBRN (branch points), and EVNT (the
events). The headline: DS1's music is adaptive at runtime. 63
branch tables ship (one per sequence kind for every track except the
two short cues 7 and 17); each table's entries match one-to-one with
Sequence Branch Index events in the son...
gff-edit-v0.6.3
gff-edit v0.6.3 (2026-10-06)
- gff-edit 0.6.3 (catch-up: 0.6.1 and 0.6.2 shipped the same
day, untagged; this entry covers all three): the chunk-kind
catalogue grew by ten corpus kinds as their docs landed, and the
format-coverage gap list reached zero. 0.6.1:DATA(the DS2
spell-system data file) andRNME(region name), plus theRDAT
description corrected to match the docs (per-region binary
config, not names). 0.6.2:MAP(the DS2 background tile grid,
byte-verified across all 60 shipped chunks),VECT(the
256-direction unit circle, decoded),CMAT(BMA-codec still
containers), andCPAL(their per-still palettes). 0.6.3:
PLYL(the dead DS2 combat playlist, unreferenced by any
binary),ALL(object-database digest tables in OBJEX.GFF,
engine-unreferenced, bestiary-joining),GREQ(per-save-slot
view state, id = slot + 1), andPREF(preferences state, 11 B
DS1 / 9 B DS2, correcting the old 14-byte claim). No parsing
changes in any of the three; the suite passes and the shipped
binary self-reports 0.6.3.
darkfix-ds2-v0.1.2
darkfix-ds2 v0.1.2 (2026-10-07)
darkfix-ds2v0.1.2: the same applier composition update
as darkfix-ds1 0.1.3 (the twoscripts/trees are deliberate
copies; this PATCH bump carries no fix content change). The
selftest grows the disjoint-compose and overlap-refuse cases,
and--unapplydeduplicates same-file journal entries so a
composed install restores byte-identically.fix.ds2.dead- triggersremains the only fix and the pinned patched hash is
unchanged.
Zip sha256: 7448e461d0485e378dc82997f85bd1509a484db994c5ea5b5c3e6691777409fa
darkfix-ds2-v0.1.1
darkfix-ds2 v0.1.1 (2026-10-07)
darkfix-ds2v0.1.1:fix.ds2.deadtriggersgrows from 27
to 37 repointed rows. The 2026-10-07 correlation dig
(docs/port-digs-2026-10-07.md 2) closed ten of the twelve rows
v0.1.0 left: the VA Headquarters tapestry look (-1922) to
GPL-163@1800, attested by MAS-51 and the same target the
sibling -1923 row already uses; two more shared-prop use rows to
their regions' attested handlers (GPL-30toGPL-45@1556per
GPL-40;GPL-64toGPL-64@1per GPL-74, the self-rearming
shape the first round restored seven times); and the seven
wizard-lab use-with rows in GPL-98 toGPL-98@1, whose entry
immediate was already correct on every dead row (their alive
twins in GPL-114 register the identical seven pairs, pair for
pair in order, to exactly that entry; use-with edits are 4
bytes, entry + chunk). The two remaining rows are closed with a
proof, not a shrug: the -900 pickup rows (Tyr thief chase) have
no handler candidate corpus-wide, so a pickup handler for that
object is not in the shipped data. The dead-trigger sweep drops
from 39 to exactly those 2; the patched file re-disassembles
350/350 chunks aligned. The applier selftest pins the new
patchedGPLDATA.GFFhash and round-trips byte-identically.
Upgrade note: the applier targets the canonical install, so a
v0.1.0-patched install must--unapply(or reinstall from GOG)
before applying v0.1.1.
Zip sha256: c2e7755576f5de587e3a79fa4019798cad4925ae01c68ef715b4cd6bf9f6293a
darkfix-ds1-v0.1.3
darkfix-ds1 v0.1.3 (2026-10-07)
darkfix-ds1v0.1.3: the spec 5 composition amendment
(Brandon's call, same day 0.1.2 shipped): several enabled fixes
may now share one target file when their edit ranges are
disjoint. The applier composes them into a single write per
file, re-checking every fingerprint in sequence (a drifted
expectstill fails the whole apply before any write), journals
the merged patched hash so--verifyand--unapplysee one
consistent file (the restore path deduplicates same-file
entries), and still refuses overlapping ranges at check time
with the offending offsets named. Consequence: the three
script repairs offix.ds1.script-repairs(0.1.2 shipped them
disabled) are now enabled by default beside
fix.ds1.deadtriggers; the default apply composes both onto
GPLDATA.GFF(seven edit sites; the selftest pins the merged
patched hash
2c851deeaafcde86d5eba118e1d62f5d7320a3c6f47cffdb719b2590a9fa315f
as the regression gate). New selftest cases: disjoint same-file
fixes apply/verify/unapply as one; overlapping ranges refuse
untouched.tools/build-release.shgate 1 is overlap-aware to
match (its selftest proves overlap refuses and disjoint
composes). Players upgrading from 0.1.2-with-002-hand-enabled:
the applier targets the canonical install, so unapply first.
Zip sha256: 7cc85f06e112f0bd13aec9b0e351ffa1b0ace3072673d5b46856924a42250988
darkfix-ds1-v0.1.2
darkfix-ds1 v0.1.2 (2026-10-07)
darkfix-ds1v0.1.2: the Phase 9 sweep triage lands, and
with it the first script repairs beyond the deadtrigger family.
Every catalogued DS1 bug (known-bugs.md 3, ~25 entries) now
carries a verdict with evidence (docs/ds1-sweep-triage-2026-10-07.md):
three FIXED, nine fix-candidates gated on chunk growth, a
runtime capture, or a content decision, and the rest closed as
engine-side or no-static-site with the proof. The new
fix.ds1.script-repairscarries three same-length repairs with
the deadtrigger safety design: the Lava Rifts hermit/ranger
loop (the ranger-leave re-arm arms the HERMIT's entry 86,
occluding the ranger's own registration; fixed by repointing to
445; the duplicate Iron Necklace is the hermit give's drop
fallback), the Linara conversation dead-end (GNUM55==2 routed
to a one-line sub with no menu; repointed to the general menu
209), and the final-battle stage-gate strand (the headline
family's one proven faulty datum: the stage gate exits without
re-arming when a stage is cleared inside its window, killing
the chain; the fix arms the driver 239 directly, at the cost of
the intended inter-stage pause). The fix ships DISABLED: spec 5
allows one enabled fix per target file and 001-deadtriggers
owns GPLDATA.GFF, so the manifest toggles (enable 002, disable
001); the toggle path is proven to apply and unapply
byte-identically and the 002-only patched hash is pinned in the
fix doc. All bytes fingerprint-verified against the canonical
install; the patched file re-disassembles 250/250 chunks
aligned. The per-file composition question is flagged for
Brandon: it needs a spec amendment, not an applier flag.
Zip sha256: 44013793daa92680f30080e455d6a9d344bd6b89569c41bd2fc34509f8f80344