Skip to content

Repository files navigation

OpenUA

An open reimplementation of SSI's Unlimited Adventures engine — the 1993 Gold Box adventure construction set — for Motorola 68k retro machines. One engine, six display backends across the Atari and Amiga lines: the Atari Falcon030, TT030, and ST/STE; the Amiga AGA (A1200/A4000), a RTG path so a classic Amiga with a graphics card runs the full 256-colour game, and a native ECS path for a bare classic Amiga. The lower-colour targets (ST/STE 16, ECS 32) run a runtime median-cut quantizer that reduces the engine's 256-colour frame to the machine's palette.

OpenUA = Open + Unlimited Adventures.

The engine is decompiled from the Macintosh 68k release of Forgotten Realms: Unlimited Adventures. Because the Mac version is already 68k machine code and the target machines are 68020/030, the CPU code carries over directly — the work is retargeting the Mac Toolbox and rebuilding the display, sound, and input paths behind a hardware-abstraction layer, so one engine serves several machines.

OpenUA is an unofficial, fan-made project, not affiliated with or endorsed by the rightsholders of Forgotten Realms, Unlimited Adventures, or the Gold Box games. It contains only original port code — no game data (see Legal).

No game data is included. FRUA and its modules are copyrighted. You supply your own original Mac (or DOS — see below) FRUA data. See data/README.md.

Status — playable beta

Binary downloads: grab the zip for your machine from the releases page — the binaries are redistributable (no game data inside; you supply your own, below).

The runtime plays a real adventure end to end. A real Atari Falcon030 has now played it — installed to hard disk, VGA monitor, through the dungeon, the area map, events and encampment — so the Falcon column below is no longer a claim about an emulator. The other five backends are still emulator-validated only (Hatari for the Atari builds, amiberry for the Amiga); treat those accordingly.

Three things the real machine found that no emulator had: the AREA map drew every wall transposed, the Falcon never restored the desktop's video mode on exit, and a VGA monitor has no 320×200 mode at all (hence video.cfg — see HARDWARE.md). That is the value of a hardware report, and more are wanted.

Target Backend Status
Atari Falcon030 VIDEL 16bpp Playable beta — the original target. Verified on real hardware (Falcon030@50, VGA, hard-disk install) as well as in Hatari. Pick the video mode with video.cfg if your monitor dislikes the automatic choice.
Atari TT030 TT-low 8bpl, 320×200 line-doubled into a 320×400 letterbox Verified in Hatari + EmuTOS: menu → load → caravan event → 3D town walk; STE-DMA sound (music + SFX).
Atari ST/STE ST-low 4bpl, quantized to 16 colours with a Timer-B raster split (per-band palette) Verified in Hatari --machine ste + EmuTOS: the menu renders in 16 colours, quantizer live, STE 4-bit palette, per-band colours via an MFP raster interrupt. A 68000 build (runs on any Atari), and a stock non-e ST is verified too (--machine st + TOS 1.04): the STE 4-bit palette encoding carries the extra bit in bit 3, so a plain ST reads a correct 3-bit approximation for free — fewer distinct colours (15 vs 23 in a walk frame), but measurably no more band-boundary artefacts. On an accelerated ST/STE run the Falcon/TT binary instead; it downgrades to this same backend but keeps 020 codegen (~12-17x on a step render). Faint band-boundary seams at 16 colours remain.
Amiga AGA (A1200/A4000) Direct copper list, AGA bank palette, hardware-sprite pointer Playable — verified in amiberry through combat: save-load, the caravan event, the town walk, the animated fireplace, and a full fight. Keyboard, mouse and audio all live. Verified on a real A1200 + Apollo IceDrake (2026-09-05): the Workbench installer, and the AHI sound backend opening and tearing down cleanly (with Paula as the fallback on a stock machine).
Amiga RTG (classic Amiga + graphics card) Picasso96 chunky 8-bit screen Verified — the full 256-colour menu renders on a live Picasso96 320×200×8 RTG screen (amiberry, accelerated A2000 + uaegfx board, Workbench 3.2). A classic non-AGA Amiga with an accelerator and an RTG card runs the game at full colour, no bitplanes.
Amiga ECS/OCS (bare classic Amiga) Native 5bpl copper, quantized to 32 colours with a per-band copper palette Verified in amiberry on a bare OCS A2000: the menu renders in 32 colours, quantizer live, per-band palette (the copper reloads all 32 registers each band boundary for free), software cursor. The granite chrome renders as clean grey stone.

One binary serves each family — one frua.prg for Falcon and TT (plus a 68000 frua.prg that also covers ST/STE); one frua for AGA and RTG (plus a FORCE_ECS build for bare ECS). The machine is detected at runtime and the matching display/sound path chosen — in both directions. The 68000 build runs on a Falcon or TT and picks their higher-colour backend; equally, the 020 Falcon/TT build runs on an ST or STE and downgrades to the 16-colour ST-low path. Only the CPU decides which binary you can run; the graphics follow the machine. That matters if you have an accelerated ST — see HARDWARE.md.

On the paletted targets (TT, ST/STE, AGA, RTG, ECS) the palette lives in hardware, so colour-cycle animation like the tavern fireplace is free (on the quantized targets that lands with the palette banding).

What works (on every target unless noted):

  • Exploration — first-person 3D dungeon view and the top-down area automap; movement by arrow keys or mouse; all eight command-bar verbs (MOVE · AREA · CAST · VIEW · ENCAMP · SEARCH · LOOK · INV).
  • Events — text, combat, treasure, stairs, transfers, shops, temples, encounters, chains, and the approach-direction and quest-flag gating that designs use.
  • Combat — turn-based, playable through to a party wipe, driven by the arrow keys.
  • Towns & services — shops (buy / sell / identify, pooled and personal funds), temples (healing services), taverns.
  • Magic — the full loop: memorize from the grimoire, rest to commit, cast; spell effects apply and are consumed.
  • Characters — character generation for every class, the Training Hall roster (add / remove / modify / view / train), equipping weapons and armour (AC and damage update and persist), and save / load of the party and game.
  • Editors — the in-engine GEO map editor, event editor, record/game-settings editor, art gallery, and monster editor, plus GDOS printing from the editor.
  • Sound — digitized SFX and the Mac four-tone-synth music, through the Falcon CODEC, the TT's STE-DMA sound, or on the Amiga AHI when it is installed (which is how a Vampire's SAGA audio is reached), Paula otherwise. A design's own soundtrack plays when it ships one — the DOS module's .XMI converts to a per-design MUSIC.SLB (tools/xmi2slb.py on the PC, or uainst / uaconv on the machine; all four arrangements and partial sets) — and the bank follows the design, so a module picked from the menu plays its own music, not only the one current at boot.

It plays the bundled sample design HEIRS TO SKULL CRAG and real commercial modules (e.g. Pool of Radiance) on their own art. The current gaps are fidelity/polish, not missing features — see docs/enhancements.md.

Getting the game data

OpenUA ships no game data — you supply your own from a legally-obtained copy of FRUA. The easiest source today is a digital re-release, both of which bundle FRUA in Forgotten Realms: The Archives – Collection Two:

Those are the DOS release, and either release gives you a complete install — the Macintosh original is not required (ADR-0017). Design and data files are byte-identical between the DOS and Mac versions, the included art converter (tools/art_convert.py, below) makes the DOS art readable, and the engine resource archive frua.rsc builds from the DOS CKIT.EXE via tools/rsrc_from_dos.py. The DOS path is the easy one: make gamedata-dos converts everything in one step, including frua.rsc, the soundtrack (the base game's and each design's own) and the sampled sound effects. The Mac path is a short manual copy plus one packing step. Step-by-step setup — which files go where, per platform — is in GAMEDATA.md; the Mac release's unpacking pipeline is in docs/mac-release.md.

Building

MACHINE selects the target family (default falcon, which also covers the TT). Each family needs its own cross toolchain.

Atari (Falcon030 / TT030)

Requires the m68k-atari-mint GCC cross toolchain with a soft-float m68020-60 multilib on PATH (override the prefix with make CROSS=… or TOOLROOT=…). Building that toolchain is documented in docs/toolchain-softfloat-020.md.

make                 # build frua.prg — soft-float; runs on Falcon030 AND TT030
make FPU=1           # FPU-required variant tuned for the TT030 (68881 hard-float)
make run             # boot the build in Hatari (Falcon mode)
make test            # host-side test suite (pytest over tools/)
make release         # packaged, flag-guarded shipping build -> dist/
make clean

The default build is soft-float so one binary serves the FPU-less Falcon030 and the 68882-equipped TT030; the display and sound path (VIDEL vs. TT shifter) is chosen at runtime from the _VDO cookie. The toolchain flags are non-negotiable (-m68020-60 -msoft-float); see CLAUDE.md.

Amiga (AGA / RTG)

Requires the Bebbo m68k-amigaos GCC toolchain (build it once per docs/toolchain-amiga.md; default prefix ~/opt/amiga).

make MACHINE=amiga               # build frua (an AmigaOS hunk executable)
make MACHINE=amiga CPU68K=68000  # 68000-clean build (for the eventual ECS target)

One frua serves AGA and RTG: an AA-chipset machine gets the direct-copper AGA backend; a non-AA machine gets the RTG (Picasso96/CyberGraphX) backend. The engine is deliberately 68000-clean by construction (the original Mac binary uses zero 68020-only instructions), so the CPU tier is purely a compiler flag — groundwork for later ECS/ST machines.

Running a game module

You provide your own FRUA data. Unpack the Mac release under data/ (see docs/mac-release.md), then stage a design and boot:

make run-game DSN=HEIRS.DSN     # stage the shared libraries + a design, boot Hatari

make gamedata DSN=<name>.DSN flattens the shared engine libraries and the chosen .DSN into data/work/gamedata/ (the GEMDOS C: mount) without disturbing any characters you created.

Resuming a save on launch (optional)

Put a single byte — a save-slot letter A..J — in a file called autoload.dat beside the game data, and the engine skips the menus on startup and drops you straight back into that save, at the cell you left it:

printf 'B' > autoload.dat     # resume slot B on launch
rm autoload.dat               # back to the normal title-menu boot

The slot is resolved against whichever design is current, so it follows the game's own start.dat. It fires once per run — leave the dungeon and you get the usual Training Hall. This is an OpenUA convenience: the original has no such thing, and without the file the boot is exactly as it always was. If the named slot does not exist, you simply get the normal menu.

Using DOS FRUA data and fan modules

FRUA's whole point is that players build their own adventures, and a large community has — hundreds of fan-made modules, none of them official SSI releases. They are archived at frua.rosedragon.org (the long-running community site). Most are authored on the PC, and their art is doubly unreadable by this Mac-derived engine — wrong byte order and a different pixel layout. tools/art_convert.py converts the art container both ways (DOS HLIB ↔ Mac GLIB), so those community modules become playable:

python3 tools/art_convert.py <module-art-files>   # HLIB <-> GLIB

The transform was derived by diffing the same module shipped in both formats (one asset set authored once, in both a PC and a Mac release), so it reproduces the real Mac bytes exactly — tests/test_art_convert.py checks that against the matched pair. Design/data files (.DAT/.GEO/…) are byte-identical between releases and need no conversion; only the art containers do. See docs/fan-module-hacks.md and docs/dos-inventory.md.

tools/ also holds the resource-fork extractors (macrsrc.py, hfs_extract.py, appledouble.py), the HLIB/GLIB extractors (hlib_extract.py, wall_extract.py), rsrcpack.py (Mac resource fork → the flat FRSC archive the engine loads), and the disassembler dis68k.py.

Architecture

The port is layered, and only the innermost platform layer knows which machine it runs on:

src/engine/  ->  compat/  ->  platform/  ->  TOS / AmigaOS
 (lifted        (Mac         (hardware
  engine)        Toolbox      abstraction:
                 shim)        VIDEL / TT-shifter / AGA-copper / RTG)
  • src/engine/ — the decompiled engine, lifted function-by-function from the Mac CODE segments. Recompilable C, with 68k asm where lifting resists.
  • compat/ — the Mac Toolbox compatibility shim (Memory, QuickDraw, Window, Event, Resource, File, Dialog, Menu, Control, Sound, TextEdit managers). The engine keeps the Mac spellings; the shim routes them to GEMDOS/GEM/VDI.
  • platform/ — the display / input / sound / debug HAL. The engine renders into one 8-bit paletted chunky buffer; each machine backend puts it on screen (Falcon platform/display_videl.c, TT platform/display_tt.c, Amiga platform/amiga/). Chunky→planar conversion, where a machine needs it, is a shared masked-swap transpose; graphics-card targets take the buffer directly.

Design rationale lives in docs/architecture.md and the append-only decision log docs/decisions.md. docs/ also holds the per-subsystem maps ("*-wall.md") and the decompilation workflow (docs/decompilation.md).

Generally applicable writeups

Two documents are written to stand on their own, for anyone doing this kind of work on any project — no knowledge of this codebase assumed, and worth reading before repeating the same experiments:

  • docs/chunky-to-planar-68k.md — converting a chunky framebuffer to bitplanes on ST/STE/TT/Amiga: the layouts, what the optimisations were actually worth (flat-run detection −36%; the BLiTTER 3.4% end-to-end, not the 3.76× the microbenchmark promised), the draw-time plane-stamping model and the three walls that cap it, and the measurement that overturned the plan.
  • docs/headless-retro-harness.md — driving Hatari and amiberry with no display so rendering changes can be regression-tested by diffing frames, plus the traps (silence that looks like success, verifying by state rather than by keys sent, pulldown menus that cannot be screenshotted while open).

Repository layout

src/         port bootstrap (src/main.c) + decompiled engine (src/engine/)
compat/      Mac Toolbox compatibility shim
platform/    hardware abstraction layer (Atari VIDEL/TT here; platform/amiga/ = AGA + RTG)
toolchain/   per-machine cross-toolchain configuration (.mk)
tools/       host-side extractors / converters / disassembler
tests/       host-side pytest suite
docs/        architecture, decisions, subsystem maps, formats
data/        original FRUA assets — you supply these (git-ignored)

License

The port's own source code, tooling, and documentation are licensed under the GNU General Public License v2 — see LICENSE.

Copyright (C) 2026 Slaapliedje

This covers only the port (the decompiled/reimplemented engine, the Toolbox shim, the HAL, and the tools). It grants no rights to Forgotten Realms: Unlimited Adventures itself, which remains copyrighted by its rightsholders and is never included here (see Legal, below). The AI-generated free cursor set under assets/cursors/ is part of the port and covered by the same license.

Legal

This repository contains only port source code and tooling. It ships no original FRUA assets, binaries, resource forks, or module data — those are copyrighted by their rightsholders and must be supplied separately from your own legally-obtained copy. The build regenerates the copyrighted replay tables from your resource fork locally; they are never committed. See data/README.md.

A default make build embeds ~31 KB of copyrighted FRUA DATA (the A5 init image), so those binaries are not redistributable. make release (equivalently make NOEMBED=1) builds a binary that carries no game data: it stubs that table and reconstructs the A5 world from the user's own frua.rsc at launch, so the shipped binary contains only the port's own code and can be shared. See docs/redistributable-binary.md. Either way, playing still requires your own legally-obtained FRUA data.

About

No description, website, or topics provided.

Resources

Stars

8 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages