Play the complete game in your browser
Read the source-code and reverse-engineering overview
A complete reverse engineering and preservation project for Zeliard (Game Arts, 1987; Sierra On-Line, 1990), the classic action RPG/platformer. The repository contains a bit-perfect MASM reconstruction of the DOS game, mechanics documentation, format and archive tooling, behavioral test oracles, and a complete C/WebAssembly port playable from beginning to end in a modern browser.
Play the complete game — no installation or DOS emulator required.
The web edition is a behaviorally faithful reimplementation rather than a DOS emulator wrapper. Its portable C engine compiles to WebAssembly, with a TypeScript browser host providing display, audio, input, gamepad, and save-file integration. It runs the full adventure through the ending and uses resources reconstructed from the canonical MASM source tree.
- Complete browser port — fully playable from the opening cinematic to the ending
- Portable C/WebAssembly engine with a TypeScript/Vite browser shell
- Original-compatible 256-byte
.USRsaves import and export between DOS and web editions - Oracle-driven compatibility suite covering gameplay, rendering, input, transitions, and audio
- 60 ASM source files — all compile bit-perfect to original binaries
- All three SAR archives (zelres1/2/3.sar) rebuild bit-perfect from source
- Zero raw-hex memory operands without symbolic EQU names (
find_missing_equs.pyreports 0 MISSING + 0 UNUSED) - Zero unannotated bare-db lines across all 60 files
- TCRF save-format unification applied —
keys_normal,hero_level,tears_of_esmesanti_count, etc. match the canonical Zeliard wiki layout
cd 3_Assembly/masm
python build_masm.py --verifyCompiles all 60 canonical MASM source files, copies data, packs zelres1/2/3.sar, and verifies bit-perfect output. Required success output:
zelres1.sar: BIT-PERFECT (256,952 bytes)
zelres2.sar: BIT-PERFECT (345,218 bytes)
zelres3.sar: BIT-PERFECT (342,434 bytes)
For single-file iteration: python verify1.py <relpath> (sub-second
per file) before running the full SAR rebuild.
Original unmodified DOS game files.
zeliad.exe— main loader (2,544 B)game.bin,gmmcga.bin,gmcga.bin,gmega.bin,gmhgc.bin,gmtga.bin,stdply.bin,stick.bin— driver/engine binarieszelres1.sar(256 KB, 40 chunks)zelres2.sar(345 KB, 58 chunks)zelres3.sar(342 KB, 96 chunks)
SAR archive tools, extracted chunks, and the .grp image viewer.
Tools/extract_sar.py— extracts all chunks using size-field headersTools/pack_sar.py— repacks chunks into SAR archivesTools/decompress_sar.py— decompresses chunk payload (fill_buffer)Tools/grp_viewer.py— interactive viewer for .grp sprite/image dataExtractedChunks/zelres{1,2,3}_extracted/— raw extracted chunks
The MASM 5.1 tree is the authoritative reconstruction, the active reverse-engineering source, and the sole behavioral reference for the web port. Release builds reproduce the original binaries and all three SAR archives bit-for-bit; debug builds and function tests provide instrumented behavior oracles without changing the canonical release output.
working/
core/ zeliad.asm, game.asm
drivers/ gmcga, gmega, gmhgc, gmmcga, gmtga, stdply, stick
zelres1/code/ 12 ASM files (100OPDMO + 5 GD drivers + 106TOWN + 5 GT drivers)
zelres1/data/ 28 data files (.grp, .msd, font.bin)
zelres2/code/ 19 ASM files (200FIGHT, 201SELCT, 5 GF drivers, MOLE, YMPD,
CKPD, 8 NPC programs, 250ENDMO)
zelres2/data/ 38 data files (.grp, .msd, .mdt)
zelres3/code/ 20 ASM files (300ROKAD demo, 301-308 EAI1-EAI8,
309-319 boss/sub-boss handlers)
zelres3/data/ 76 data files (.grp, .msd, .mdt — 31 maps + 45 sprites)
bin/ release output identical to 1_OriginalGame/
bin_debug/ instrumented behavior-oracle builds
functest/ MASM-backed behavior and equivalence probes
File naming convention (8.3, DOSBox-compatible): X##PPPPP.ext
X= resource archive (1, 2, or 3)##= chunk index (00-95)PPPPP= 5-char purpose abbreviation (matches the originalresource_name_tablein 200FIGHT.asm where known — e.g.309CRABfor the Cangrejo boss = Spanish "crab")
| Tool | Purpose |
|---|---|
build_masm.py --verify |
Parallel full build, SAR repack, and bit-perfect verification |
build_masm.py --debug |
Build the instrumented behavior-oracle binaries |
verify1.py <relpath> |
Fast verification of one reconstructed source file |
functest/run.py --ci |
Run MASM behavior probes with PASS/FAIL/INCONCLUSIVE verdicts |
functest/proc_equivalence/ |
Controlled procedure-level equivalence and behavior tests |
The TASM 2.01 tree remains bit-perfect as a historical compatibility build. It
is not the active reconstruction and is not a source of truth for porting
decisions. New reverse-engineering work, symbol changes, debug instrumentation,
and behavior probes belong in 3_Assembly/masm/.
Reference materials — game manual (PDF), maps (BMP), MIDI music,
sprites, playthrough notes. Includes MdtViewer/ (Avalonia UI for
.MDT dungeon maps).
Complete, start-to-finish playable browser port. A portable C engine implements the game while the TypeScript/Vite shell supplies the web platform, audio, display, input, gamepad, save-file, automated-playthrough, and deployment layers.
Modern sequel and content-creation work. Design/ defines the product and feel
targets, Spikes/ preserves disposable feasibility evidence, and Game/ is the
pinned Godot 4.7.2 production project shared by the runtime and Zeliard Creator.
The sequel uses newly authored resources rather than legacy Zeliard assets or
formats. See 7_Zeliard2/Game/README.md to open,
validate, test, and export the production scaffold.
References inside game binaries: [archive_index] [chunk_1indexed] 'FILENAME.EXT' 0x00
To locate a file in a SAR:
offset = (chunk_1indexed - 1) * 4data_start = dword at sar[offset]length = dword at sar[data_start](only for SAR-loaded chunks; DOS-loaded files like game.bin/stick.bin have no length header)content = sar[data_start+4 .. data_start+4+length]
SAR-loaded chunks are also fill_buffer-compressed when loaded with
AL=2; raw chunks (AL=3) skip decompression. See
2_SAR/Tools/decompress_sar.py and the canonical loader in
3_Assembly/masm/working/core/game.asm.
| Range | Contents |
|---|---|
| 00-11 | Code: opening cinematic (100OPDMO), 5 GD-drivers (GDEGA/CGA/HGC/TGA/MCA), town engine (106TOWN), 5 GT-drivers (GTEGA/CGA/HGC/TGA/MCA) |
| 12-39 | Data: font.bin, opening images (nec/hou/dmaou/ttl1-3/hime/oui/sei/yuu1-4/yuup/oup/maop), waku.grp window frame, zopn.msd / zend.msd music |
| Range | Contents |
|---|---|
| 00-06 | Core gameplay: 200FIGHT (cavern engine), 201SELCT (inventory), 5 GF-drivers |
| 07 | 207MOLE — generic graphics-init module |
| 08-17 | Town NPC programs: YMPD, CKPD, KINGPRO, OMOYPRO (+ end-demo trigger), ARMRPRO, BANKPRO, CHURPRO, DRUGPRO, INNAPRO, KENJPRO (Sage) |
| 18-35 | Gameplay sprite sets (.grp / .bin) |
| 36-45 | Town maps: CMAP, MRMP, STMP, BSMP, HLMP, TMMP, DRMP, LLMP, PRMP, ESMP (.mdt) |
| 46-49 | Music: MGT1, MGT2, UGM1, UGM2 (.msd) |
| 50 | 250ENDMO — ending cinematic module |
| 51-57 | Extended sprite data (.grp) |
| Range | Contents |
|---|---|
| 00 | 300ROKAD — demo/attract mode |
| 01-08 | Enemy AI per world: EAI1-EAI8 (Muralla, Satono, Bosque, Helada, Tumba, Dorado, Llama, Pureza) |
| 09-19 | Boss code: CRAB (Cangrejo), TAKO (Pulpo), TORI (Pollo), ZELA, MEDA, LEGA, ZEL2, DRGN (Dragon), AKMA, MAO1, MAO2 |
| 20-50 | Dungeon maps: MP10-MPA0 (.mdt, loaded at game_seg:0xC000) |
| 51-84 | Boss/NPC/environment sprites: FMAN, ROKA, DMAN, DCHR, ENCNT, ENP1-N, MPP1-B, sprites (.grp) |
| 85-95 | Music: MUS1-MUS8, MBOS, MFAN, MMAO (.msd) |
Files loaded at game_seg:0xC000. 9-word pointer table at start:
| Offset | Field | Notes |
|---|---|---|
| 0x00 | unknown | |
| 0x02 | width | Dungeon width in tiles (height always 64) |
| 0x04 | v_platforms | 3B each, 0xFFFF stop |
| 0x06 | objects | Air streams — 3B each, 0xFFFF stop |
| 0x08 | h_platforms | 7B each, 0xFFFF stop |
| 0x0A | doors | 12B each, 0xFFFF stop |
| 0x0C | items | Pickup records, 0xFFFF stop |
| 0x0E | name | Cavern name renderer |
| 0x10 | monsters | 16B each (some enemies use 2 records), 0xFFFF stop |
- Symbol sweeps — codebase-wide rename passes (player-record / gvar
/ driver-dispatch / hardcoded-operand). Each rename verified by
verify1.py+build_masm.py --verify. See.claude/skills/symbol-sweep/SKILL.mdfor the recipe. - Tier-3 probes — Unicorn-based proc-equivalence tests
(
functest/proc_equivalence/). Used to resolve PLACEHOLDER_NAME procs by replaying them under controlled inputs and verifying the observable side-effects match a hypothesis. - TCRF save-format unification (2026-05-05) — reconciled stdply.inc canonical names against the TCRF wiki layout; canonical names are SSOT, earlier misnomers retained as deprecated alias EQUs with a comment explaining why they were wrong.
- Title: Zeliard
- Developer: Game Arts
- Publisher: Sierra On-Line (English), Game Arts (Japanese)
- Year: 1987 (PC-98/Japan), 1990 (DOS/English)
- Genre: Action RPG / platformer
Original game © 1987, 1990 Game Arts / © 1990 Sierra On-Line.
This repository contains only assembly reconstructions and tooling —
no original game assets ship with the source. Build artifacts in
1_OriginalGame/ come from the user's legally-owned copy of the game.