A clean-room C# port of Heart of the Alien (Sega CD, 1994), the canonical sequel to Eric Chahi's Another World (also known as Out of This World). The original was a custom-bytecode engine running on Sega CD hardware; this port reimplements that engine in C# with SDL2 for the host window/audio.
The port is faithful to M-HT's open-source C reference (M-HT/hota, itself based on Gil Megidish's hota-redux) and verified pixel-accurate against it on the password screen (SSIM 0.999).
Frames from the opening cinematic (INTRO1.BIN), captured headless via
--play-animation=INTRO1.BIN --capture-every=1 so they reflect the
actual rendered output of this port:
![]() |
![]() |
![]() |
![]() |
(All four are post-fix; before the PlaySequence cumulative-delta bug
was found, the dragon frame above had only the wing outlines — see the
commit log for details.)
| Subsystem | Status |
|---|---|
| VM dispatcher (97 of ~98 opcodes) | ✓ — only op_12 (AW-only) is stubbed |
| Engine outer loop + cooperative tasks | ✓ |
| Variable bus + per-task aux banks | ✓ |
| Screen system (4 buffers + page-flip) | ✓ |
| Sprite system (list + colored-run-length renderer) | ✓ |
| Palette (Sega-CD RGB444 → RGB888 bit-replicated) | ✓ |
| LZSS backdrop decompression | ✓ byte-exact fixtures |
| Animation player (delta-frame decoder + 8 brush patterns) | ✓ INTRO1/2 + MID2 + END1 play through |
| Input handling (gamepad + record/replay scripts) | ✓ |
| Audio (SFX + MP3 music via SDL2_mixer) | ✓ |
| Quicksave (byte-exact 6150-byte snapshot) | ✓ |
| Chapter transitions | ✓ |
| SDL2 live window (resizable + integer-scale letterbox + F11 fullscreen) | ✓ |
| Scale2x / Scale3x edge-preserving upscale filters | ✓ via --filter=N |
| Verify-boot harness (pixel-diff vs M-HT) | ✓ SSIM 0.999 |
282 unit/integration tests; all green. No C source compiles in this project — SDL2, SDL2_mixer, and libSkiaSharp are the only native dependencies, all loaded at runtime.
- .NET 10 SDK
- SDL2 + SDL2_mixer native libraries
- The HOTA ISO (commercial asset — not included)
- Optional: the MP3/OGG music tracks named per the M-HT convention
(
Heart Of The Alien (U) NN.mp3)
Install SDL2 + SDL2_mixer:
# macOS (Apple Silicon — must match .NET arch)
brew install sdl2 sdl2_mixer
# macOS (Intel)
brew install sdl2 sdl2_mixer
# Debian/Ubuntu
sudo apt install libsdl2-2.0-0 libsdl2-mixer-2.0-0
# Windows
# Place SDL2.dll + SDL2_mixer.dll alongside the .exe (or on PATH).Place the ISO at data/hota.iso (symlinked or copied; gitignored).
Optional MP3 tracks go in the same directory as the ISO by default
(override with --music-dir=).
dotnet build hota/Hota.csprojdotnet run --project hota/Hota.csproj -- --play --iso=data/hota.isoThis plays the four intro cinematics (Escape to skip) then drops you on
the password screen. Navigate to "OK" and press Z to start chapter 1 —
no password needed. Other chapters require codes from the original game
manual (search online for "Heart of the Alien passwords"; valid letters
are B C D F G H J K L R T X).
Run silent: --no-sound. Skip intro: --skip-intro. Jump to a specific
room (debug): --room=N. Custom music dir: --music-dir=.... Integer
window scale: --scale=3. Edge-preserving upscale: --filter=2 (Scale2x)
or --filter=3 (Scale3x) — must be ≤ scale; the filtered image is then
nearest-stretched to the window.
| Key | Action |
|---|---|
| Arrow keys | Directional pad |
| Z / Space | Action A (confirm) |
| X | Action B |
| C / Enter | Action C |
| F5 | Quicksave |
| F8 | Quickload |
| F11 | Toggle borderless fullscreen |
| P / N | Pause / single-step (debugging) |
| D | Toggle on-screen debug HUD |
[ ] = |
Speed slower / faster / reset |
| Tab | 10× fast-forward toggle |
| Esc | Quit (or skip intro during cinematics) |
The window is resizable; rendering is integer-scale letterboxed (centered, with black bars on the off-axis) so the aspect ratio and pixel sharpness stay intact at any size.
For automated testing / asset inspection without opening a window:
| Mode | Result |
|---|---|
--render-backdrop --room=N --entry=K --palette=P |
LZSS-decode + render any backdrop to PNG |
--play-animation=INTRO1.BIN |
Play a cinematic, capture every Nth frame |
--run-room=N |
Run task 0 of room N once, write the resulting screen PNG |
--capture-dir=PATH --input-script=... |
Engine-loop frame capture (used by make verify-boot) |
--probe-native |
Print native-lib paths + versions and exit (no ISO needed) |
All capture modes default to writing under hota/captures/<timestamp>-<mode>/
so repeat invocations don't overwrite each other.
Every flag accepted by hota. --help prints the same content; this is
the source of truth.
| Flag | Purpose |
|---|---|
--play |
Live interactive window. Mode requires --iso=PATH. |
--capture-dir=PATH |
Engine-loop frame capture (used by the visual_diff harness). |
--render-backdrop |
LZSS-decode a single room backdrop straight to PNG, no VM run. |
--run-room=N |
Load room N, run task 0 once, present screen 0 as PNG. |
--play-animation=FILE |
Play a .BIN cinematic (e.g. INTRO1.BIN), capture frames. |
--probe-native |
Print SDL2 / SDL2_mixer / SkiaSharp load paths + versions and exit. |
| Flag | Default | Purpose |
|---|---|---|
--iso=PATH |
(required for non-probe modes) | Path to hota.iso. |
--room=N |
7 for --capture-dir; required for --render-backdrop |
Room index 1..8 to load. |
--entry=K |
0 |
Backdrop entry within the room (for --render-backdrop). |
--palette=P |
0 |
Palette index into GAME2.BIN. |
--out=PATH |
(auto-named) | Literal output PNG path — overrides the default name. |
--out-dir=DIR |
hota/captures/<timestamp>-<mode>/ |
Output directory; the file is auto-named inside it. |
--capture-every=N |
30 (capture-dir) / 1 (play-animation) |
Write only every Nth frame. |
--exit-after-frame=N |
-1 (no limit) |
Stop the engine after the Nth captured frame. |
--headless |
off | Run capture mode without opening any window. |
--input-script=PATH |
none | Replay a recorded keypress bytestream into the engine. |
--file-offset=N |
0 |
Offset within the animation .BIN (used for chapter cuts in M-HT). |
--trace-frame=N |
none | While playing one animation, emit a per-brush trace for frame N to trace_frame_NNNNNN.txt. |
| Flag | Default | Purpose |
|---|---|---|
--scale=N |
2 |
Integer window upscale (window = 304×192 × N). |
--filter=N |
1 |
Edge-preserving upscaler: 1=none, 2=Scale2x, 3=Scale3x. Must be ≤ scale. |
--music-dir=PATH |
the ISO's directory | Where to look for .mp3 / .ogg music tracks. |
--skip-intro |
off | Skip the four INTRO*.BIN cinematics and start at the password screen. |
--no-sound |
off | Disable realtime audio (no SDL2_mixer). |
*.mp3 and *.ogg files in the music directory are auto-discovered by
the last run of digits in the filename. Examples that all map to
"track 31":
Heart Of The Alien (U) 31.mp3hota_31.mp3track-31.ogg
.ogg wins over .mp3 for the same number. Files without a trailing
digit run are ignored. If no music dir is found or the trailing-digit
parse misses a file, audio init still succeeds — that track just no-ops.
Pixel-diffs M-HT's output against ours frame-by-frame using SSIM:
make -C hota/tools/visual_diff verify-bootProduces 3-up diff PNGs + a JSON summary under
hota/captures/<timestamp>-boot/.
hota/ ← the port itself
Memory/ ← LinearMemory (1 MB flat + 0xF900 header pointers)
Vm/ ← dispatcher, opcodes, EngineLoop, InputState, QuickSave
Video/ ← Screen, sprites, palette, animation decoder, presenter
Audio/ ← SfxSample decoding, AudioSubsystem, IAudioBackend
Assets/ ← ISO loader, LZSS, RoomLoader, Game2Bin
Platform/ ← SDL2 bindings, window, input pump, SDL_mixer backend
Program.cs ← entry point (--play / --render-backdrop / etc.)
tests/ ← xUnit
tools/ ← visual_diff harness + asset-extractor
captures/ ← per-run output (gitignored)
references/
hota-mht/ ← M-HT's C port (canonical reference)
hota-redux/ ← Gil Megidish's BeOS port (older, less complete)
docs/port/ ← phase docs, audit findings, verification harness notes
- Standalone: this is a from-scratch C# port — no shared runtime
code with the Another World C# port (
AnotherWorldCS). Where the two engines share opcodes, individual methods were imported with// SOURCE: AnotherWorldCS/…provenance headers and are then free to diverge. - Render model: HOTA dropped AW's polygon-vector rendering entirely.
Both backdrops (LZSS-packed 4bpp raster) and sprites (colored-run-length
encoded) are bitmap-based. Display uses nearest-neighbor by default;
Scale2x/Scale3x are available via
--filter=Nfor edge-preserving upscale that keeps the pixel-art aesthetic. - Cooperative VM: 64 tasks, 256 global vars + 32 per-task aux vars, ~98 opcodes. Each task runs to a yield (op_06) per frame.
- Animation player: M-HT's
unpack_animation_delta(bitstream-LZ) +anim_interesting(8 brush patterns) ported verbatim. Cinematic .BIN files load into LinearMemory at a fixed offset; per-frame palette reads from the file header.
See hota/CLAUDE.md for in-depth port conventions and docs/port/audit-findings.md for issues caught in the reference C source.
- Some gameplay: VM opcodes are all present, but real-world gameplay
scenarios (rooms 1–6) haven't been exhaustively bug-hunted. If the game
hangs or misbehaves in-game, the most likely culprits are subtle
state-machine mismatches in
op_24/op_70/op_2b(the dispatch trees with five+ branches). - op_24 collision-against-scene is ported but light on real-data validation — synthetic tests cover the five sub-tests but the byte- packed record encoding in real bytecode hasn't been exercised end-to-end.
This C# port — author: John KNIPPER (code@jkn.me). Built collaboratively with Claude Opus 4.7 (1M context) over a multi- session port effort; see commit log for the per-slice breakdown.
This port stands on the shoulders of several open-source reverse
engineering efforts. Every C# file with a // SOURCE: header is a
translation or adaptation of code from one of these projects:
-
M-HT/hota — Heart of The Alien Redux by M-HT, a modernized SDL2-based C port of the engine. M-HT was the primary reference for every behavioral subsystem (VM dispatcher, animation decoder, sprite renderer, audio dispatch, the Scale2x/3x filters) and the oracle for the pixel-diff verification harness. License: GPL-2.0-or-later.
-
hota-redux by Gil Megidish — the original BeOS-era reverse engineering effort that the M-HT fork derives from. Some opcode handlers and the bitstream LZ decoder were cross-referenced against this. License: GPL-2.0-or-later.
-
AnotherWorldCS by jonx — the C# port of Eric Chahi's Another World engine. Individual methods (the eleven VM opcodes that HOTA shares with AW, the big-endian readers, and the broad shape of the VM dispatcher) were imported with
// SOURCE: AnotherWorldCS/…provenance headers; consult the upstream repo at the link above for the originals. -
Scale2x/Scale3x — the AdvanceMAME edge-preserving upscale algorithm by Andrea Mazzoleni, with M-HT's compact derivation by Pete Shinners further adapted by Gil Megidish. Ported verbatim to C# in hota/Video/Scale2x.cs and Scale3x.cs.
- SDL2 and SDL2_mixer — used via P/Invoke for window/input/audio. License: Zlib.
- SkiaSharp — used for the debug HUD overlay text. License: MIT (wrapping Google's Skia).
- Heart of the Alien original game © 1994 Interplay / Virgin Interactive, designed by Eric Chahi. This port contains no commercial assets — you must provide your own ISO and any optional CD-audio rips.
The C# source files in hota/ are derived from GPL-2.0-or-later upstream
projects (M-HT and hota-redux). To remain license-compatible with the
upstream work it derives from, this port should be distributed under
GPL-2.0-or-later. No LICENSE file is committed yet — pick a slot in
your release process to decide and drop one in.



