Skip to content

jonx/HotaCS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Heart of the Alien — C# port

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).

Screenshots

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:

cliff approach dragon flight
winged creature ruined city

(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.)

Status

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.

Quick start

Prerequisites

  • .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=).

Build

dotnet build hota/Hota.csproj

Play

dotnet run --project hota/Hota.csproj -- --play --iso=data/hota.iso

This 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.

Controls

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.

Headless modes

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.

Full CLI reference

Every flag accepted by hota. --help prints the same content; this is the source of truth.

Mode selectors (pick one)

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.

Shared across modes

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.

--play only

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).

Music files

*.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.mp3
  • hota_31.mp3
  • track-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.

Verification harness

Pixel-diffs M-HT's output against ours frame-by-frame using SSIM:

make -C hota/tools/visual_diff verify-boot

Produces 3-up diff PNGs + a JSON summary under hota/captures/<timestamp>-boot/.

Repository layout

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

Architecture 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=N for 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.

Known gaps

  • 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.

License & credits

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.

Upstream projects — thanks

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/hotaHeart 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.

Native runtime dependencies — thanks

  • 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).

Original game

  • 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.

License of this port

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.

About

A clean-room C# port of Heart of the Alien, https://en.wikipedia.org/wiki/Heart_of_the_Alien, (Sega CD, 1994), the canonical sequel to Eric Chahi's Another World (also known as Out of This World).

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors