{"id":18550673,"url":"https://github.com/openrakis/cryogenic","last_synced_at":"2026-04-06T14:03:25.253Z","repository":{"id":42716196,"uuid":"459725389","full_name":"OpenRakis/Cryogenic","owner":"OpenRakis","description":"An open-source reimplementation of Cryo's DUNE game (WIP)","archived":false,"fork":false,"pushed_at":"2025-03-13T20:51:41.000Z","size":5136,"stargazers_count":35,"open_issues_count":6,"forks_count":1,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-24T12:47:31.687Z","etag":null,"topics":["assembly-x86","dotnet","dune","msdos","reverse-engineering","spice86"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenRakis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-15T19:43:37.000Z","updated_at":"2025-03-22T22:41:20.000Z","dependencies_parsed_at":"2023-10-02T23:50:10.312Z","dependency_job_id":"88556777-1fd5-4593-8b8a-6f40e43f5c07","html_url":"https://github.com/OpenRakis/Cryogenic","commit_stats":{"total_commits":100,"total_committers":3,"mean_commits":"33.333333333333336","dds":"0.31999999999999995","last_synced_commit":"86f483c2b745714aeede06f5c072a582cc8916ce"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenRakis%2FCryogenic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenRakis%2FCryogenic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenRakis%2FCryogenic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenRakis%2FCryogenic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenRakis","download_url":"https://codeload.github.com/OpenRakis/Cryogenic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248123499,"owners_count":21051481,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assembly-x86","dotnet","dune","msdos","reverse-engineering","spice86"],"created_at":"2024-11-06T21:05:26.655Z","updated_at":"2026-04-04T11:12:53.495Z","avatar_url":"https://github.com/OpenRakis.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Linux](https://img.shields.io/badge/-Linux-grey?logo=linux)\n![OSX](https://img.shields.io/badge/-OSX-black?logo=apple)\n![Windows](https://img.shields.io/badge/-Windows-red?logo=windows)\n\n# Cryogenic\n\n[![PR Validation](https://github.com/OpenRakis/Cryogenic/actions/workflows/pr-validation.yml/badge.svg)](https://github.com/OpenRakis/Cryogenic/actions/workflows/pr-validation.yml)\n[![Release](https://github.com/OpenRakis/Cryogenic/actions/workflows/release.yml/badge.svg)](https://github.com/OpenRakis/Cryogenic/actions/workflows/release.yml)\n[![Deploy Pages](https://github.com/OpenRakis/Cryogenic/actions/workflows/static.yml/badge.svg)](https://github.com/OpenRakis/Cryogenic/actions/workflows/static.yml)\n[![CodeQL](https://github.com/OpenRakis/Cryogenic/actions/workflows/pr-validation.yml/badge.svg?event=push)](https://github.com/OpenRakis/Cryogenic/security/code-scanning)\n[![License](https://img.shields.io/github/license/OpenRakis/Cryogenic)](LICENSE)\n[![Latest Release](https://img.shields.io/github/v/release/OpenRakis/Cryogenic)](https://github.com/OpenRakis/Cryogenic/releases/latest)\n[![.NET Version](https://img.shields.io/badge/.NET-10.0-512BD4?logo=dotnet)](https://dotnet.microsoft.com/)\n\nC# re-implementation of Cryo's Dune (CD Version, 1992) running on [Spice86](https://github.com/OpenRakis/Spice86).\n\n**[Project page](https://openrakis.github.io/Cryogenic/)**\n\n---\n\n## Table of Contents\n\n- [What This Is](#what-this-is)\n- [Current State](#current-state)\n- [How It Works](#how-it-works)\n- [Code Structure](#code-structure)\n- [Prerequisites](#prerequisites)\n- [Build and Run](#build-and-run)\n- [Screenshots](#screenshots)\n- [Contributing](#contributing)\n- [Resources](#resources)\n- [License](#license)\n\n---\n\n## What This Is\n\nCryogenic replaces x86 assembly routines in the DOS executable `DNCDPRG.EXE` with C# methods. [Spice86](https://github.com/OpenRakis/Spice86) runs the original binary and redirects execution to the C# overrides at registered addresses. Assembly and C# code share the same emulated memory, so overrides can be introduced one function at a time without breaking the rest of the program.\n\n### Supported Executable\n\nSHA256 of the required `DNCDPRG.EXE` (Dune CD version 3.7):\n\n```\n5f30aeb84d67cf2e053a83c09c2890f010f2e25ee877ebec58ea15c5b30cfff9\n```\n\nThe game files (`DNCDPRG.EXE`, `DUNE.DAT`) are copyrighted and must be obtained separately.\n\n---\n\n## Current State\n\nThe game is fully playable with sound and music through hybrid ASM/.NET execution.\n\nOngoing work converts additional assembly routines into C#. Each converted routine is registered as an override and tested by running the game.\n\n---\n\n## How It Works\n\n1. `Program.cs` configures command-line arguments and calls `Spice86.Program.RunWithOverrides\u003cDuneCdOverrideSupplier\u003e` with the expected SHA256 checksum.\n2. `DuneCdOverrideSupplier` instantiates `Overrides.Overrides`, which calls `DefineOverrides()`.\n3. `DefineOverrides()` registers C# methods at specific segment:offset addresses using `DefineFunction` (replaces CALL targets) and `DoOnTopOfInstruction` (inline hooks).\n4. At runtime, when the emulated CPU reaches a registered address, Spice86 executes the C# method instead of the original assembly. The method returns via `NearRet()` or `FarRet()` matching the original instruction.\n5. Game state is read and written through typed accessor classes (`globalsOnDs`, `globalsOnCsSegment0x2538`) that map directly to the emulated memory at the DS and CS segment bases.\n\n### Memory Segments\n\nThe `Overrides` class declares five segment fields used when registering overrides:\n\n| Field | Value | Contents | Overrides registered |\n|-------|-------|----------|---------------------|\n| `cs1` | `0x1000` | Main game code (`DNCDPRG.EXE` loaded here) | ~80 functions across most override files |\n| `cs2` | `0xD000` | DNVGA — VGA graphics driver | 32 functions in `VgaDriverCode.cs`, 1 in `StaticDefinitions.cs` |\n| `cs3` | `0xE000` | DNPCS2 / DNSBP — PCM audio driver | None (declared but unused in current overrides) |\n| `cs4` | `0xE000` | Reserved for MIDI driver memory-dump hooks | 2 inline hooks for memory dumps at offsets 0x02DC and 0x03EE |\n| `cs5` | `0x0800` | Interrupt handlers (custom segment replacing default 0xF000) | None (declared for address reference) |\n\n`cs3` and `cs4` share address `0xE000`. In `DriverLoadToolbox`, PCM drivers (DNPCS2, DNSBP) load at `DRIVER2_SEGMENT = 0xE000`, and music drivers (DNMID) load at `DRIVER3_SEGMENT = 0xF000`. The MT-32 overrides in `MT32DriverCode.cs` use hardcoded `0xF000` (3 functions), not any `cs` field.\n\n### Driver Remapping\n\n`DriverLoadToolbox` temporarily removes the memory allocator's segment limit so drivers load at fixed addresses:\n\n| Driver | Name | Remapped to | Purpose |\n|--------|------|-------------|---------|\n| DNVGA | VGA graphics | `0xD000` | Display, blitting, palette, mouse cursor |\n| DNPCS2 | PC Speaker variant 2 | `0xE000` | PCM sound effects |\n| DNSBP | Sound Blaster Pro | `0xE000` | PCM sound effects |\n| DNMID | MIDI | `0xF000` | Music playback (MT-32, AdLib) |\n\nDrivers DN386, DNADL, DNADP, DNADG, DNSDB are not remapped. After each driver loads, `ResetAllocator` restores the original allocator state. The remapping hooks are injected at CS1:E57B (`RemapDrivers`) and CS1:E593 (`ResetAllocator`). Driver function tables are auto-detected at CS1:E589 (`ReadDriverFunctionTable`).\n\n---\n\n## Code Structure\n\n```\nsrc/Cryogenic/\n├── Program.cs                     Entry point; configures args, launches Spice86\n├── DuneCdOverrideSupplier.cs      Implements IOverrideSupplier; creates Overrides instance\n├── DriverLoadToolbox.cs           Remaps driver segments to 0xD000/0xE000/0xF000\n├── Overrides/\n│   ├── Overrides.cs               Defines segment fields (cs1–cs5), registers all overrides\n│   ├── VgaDriverCode.cs           23 VGA functions: mode setting, blitting, palette, mouse cursor\n│   ├── MenuCode.cs                14 menu-type constants, 2 menu state overrides\n│   ├── DialoguesCode.cs           3 dialogue functions: counter, init, hex-digit conversion\n│   ├── MapCode.cs                 5 map/cursor functions and click-handler address constants\n│   ├── DisplayCode.cs             11 framebuffer and font selection functions\n│   ├── VideoCode.cs               3 HNM video playback functions\n│   ├── HnmCode.cs                 1 HNM file I/O function (disk read into buffer)\n│   ├── TimeCode.cs                2 day/night cycle and hour-of-day functions\n│   ├── TimerCode.cs               1 PIT 8254 timer configuration function\n│   ├── ScriptedSceneCode.cs       2 cutscene sequence data functions\n│   ├── DatastructuresCode.cs      2 memory structure functions (index-to-pointer, sprite lookup)\n│   ├── InitCode.cs                1 VGA state initialization function\n│   ├── MT32DriverCode.cs          3 Roland MT-32 MIDI driver functions at segment 0xF000\n│   ├── UnknownCode.cs             20 partially understood functions (bit ops, memcpy, state flags)\n│   └── StaticDefinitions.cs       137+ symbolic names for unoverridden functions (tracing only)\n├── Globals/                       Typed accessors added manually (Extra* files)\n└── Generated/                     Auto-generated memory accessors (do not edit)\n```\n\n### Override Files in Detail\n\n**VgaDriverCode.cs** — Replaces functions in the DNVGA driver loaded at segment 0xD000. Covers VGA mode setting (`VgaFunc00SetMode`), framebuffer blitting (`VgaFunc05Blit`), rectangle copy (`VgaFunc12CopyRectangle`), pixel write (`VgaFunc21SetPixel`), palette loading (`LoadPaletteInVgaDac`), mouse cursor draw/restore (`VgaFunc03DrawMouseCursor`, `VgaFunc04RestoreImageUnderMouseCursor`), buffer fill (`VgaFunc08FillWithZeroFor64000AtES`), texture generation (`VgaFunc36GenerateTextureOutBP`), map block copy (`CopyMapBlock`), and VGA retrace synchronization (`WaitForRetrace`).\n\n**MenuCode.cs** — Defines 14 menu-type constants as hex offsets (e.g. `MENU_TYPE_DIALOGUE = 0x1F7E`, `MENU_TYPE_GLOBE = 0x204A`, `MENU_TYPE_BOOK = 0x2032`). Contains two overrides: one for menu animation state transitions at CS1:D316 and one for setting the current menu type at CS1:D41B.\n\n**DialoguesCode.cs** — Three functions: incrementing a dialogue counter at DS:47A8 (CS1:A1E8), initializing dialogue state including video index and face-zoom timing (CS1:C85B), and converting the low nibble of AL to an ASCII hex digit (CS1:A8B1).\n\n**MapCode.cs** — Defines click-handler addresses for five map modes (flat map, globe, in-game, troop movement, ornithopter). Five functions set the active click handler, initialize map cursor type, and perform an 8-byte memory copy from DS:46E3.\n\n**DisplayCode.cs** — Manages three framebuffers (front at DBD6, back at DC32, text at DBD8). Includes three font-selection functions (intro, menu, book) that set character-set addresses, plus coordinate lookup, buffer clear, and register push/pop helpers.\n\n**VideoCode.cs** — Three functions for HNM video playback: resource flag lookup from a table at DS:33A3, playback index synchronization, and completion check via the finished-flag at DBE7.\n\n**HnmCode.cs** — One function that reads HNM video data from disk through the DOS file manager, updating read offset and buffer pointers.\n\n**TimeCode.cs** — Extracts the current hour from the lower 4 bits of the game elapsed-time word at DS:0002. Calculates the next sunlight-visible day.\n\n**TimerCode.cs** — Writes a 16-bit counter value to PIT channel 0 (ports 0x43/0x40) with control byte 0x36. Called primarily on game exit.\n\n**ScriptedSceneCode.cs** — Reads 16-bit commands from the scene sequence data at DS:4854 and advances the sequence pointer.\n\n**DatastructuresCode.cs** — Converts an index table to a pointer table by adding a base offset. Retrieves sprite-sheet resource pointers by index from the table at DS:DBB0.\n\n**MT32DriverCode.cs** — Three functions at segment 0xF000 for Roland MT-32 output: a primary entry point, a MIDI byte-write to port 0x330, and an unused stub.\n\n**UnknownCode.cs** — 20 functions with observed behavior but unclear purpose. Includes bit-test operations on DBC8, multi-register shifts, 8-byte memory copies, state-flag setters, a 10-byte structure builder, a 0x5C-byte fill at DS:47F8, and three no-ops.\n\n**StaticDefinitions.cs** — Registers 137+ symbolic function names (e.g. `play_intro`, `open_dune_dat`, `allocator_init`) at their addresses for Spice86's trace output. These are not overridden; they provide readable names in execution logs.\n\n---\n\n## Prerequisites\n\n1. [.NET 10 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/10.0)\n2. `DNCDPRG.EXE` and `DUNE.DAT` from Dune CD version 3.7 (copyrighted; obtain separately)\n\nVerify the executable checksum:\n\n```bash\n# Linux/Mac\nsha256sum DNCDPRG.EXE\n\n# PowerShell\nGet-FileHash DNCDPRG.EXE -Algorithm SHA256\n```\n\n---\n\n## Build and Run\n\n### Build\n\n```bash\ngit clone https://github.com/OpenRakis/Cryogenic\ncd Cryogenic/src\ndotnet build\n```\n\n### Run (no audio)\n\nPlace `DUNE.DAT` and `DNCDPRG.EXE` in the same directory, then:\n\n```bash\ncd Cryogenic/src\ndotnet run --Exe /path/to/DNCDPRG.EXE --UseCodeOverride true -p 4096\n```\n\n`--UseCodeOverride true` is required. Without it, no C# overrides execute.\n\n### Run with audio\n\nOPL3 music and Sound Blaster PCM:\n\n```bash\ncd Cryogenic/src/Cryogenic\ndotnet publish\nbin/Release/net10.0/publish/Cryogenic --Exe /path/to/DNCDPRG.EXE --Cycles 8000 --UseCodeOverride true -p 4096 -a \"ADP330 SBP2227\"\n```\n\n---\n\n## Screenshots\n\n\u003cdiv align=\"center\"\u003e\n\n![Orni](doc/cryodune_orni.png)\n*Orni*\n\n![Chani dialogue](doc/cryodune_chani.png)\n*Chani dialogue*\n\n![Spice shipment screen](doc/cryodune_send_spice.png)\n*Spice shipment screen*\n\n![Harkonnen scene](doc/cryodune_harkonen.png)\n*Harkonnen scene*\n\n![Harkonnen scene](doc/cryodune_map.png)\n*Dune map*\n\n\u003c/div\u003e\n\n---\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for setup instructions, coding conventions, and the override implementation workflow.\n\nContribution areas:\n\n- **Reverse engineering** — analyze assembly, implement C# overrides, register them in `DefineOverrides()`\n- **Documentation** — add XML doc comments, document data structures, explain function behavior\n- **Testing** — run the game, compare behavior against the original, report differences\n- **Code quality** — refactor existing overrides, improve naming, remove duplication\n\n---\n\n## Resources\n\n- [Project page](https://openrakis.github.io/Cryogenic/)\n- [GitHub repository](https://github.com/OpenRakis/Cryogenic)\n- [Spice86](https://github.com/OpenRakis/Spice86) — the emulator and reverse-engineering toolkit used by this project\n- [Releases](https://github.com/OpenRakis/Cryogenic/releases)\n- [Dune (1992) on Wikipedia](https://en.wikipedia.org/wiki/Dune_(video_game))\n\n---\n\n## License\n\nApache License 2.0. See [LICENSE](LICENSE).\n\nCopyright 2021–2024 Kevin Ferrare and contributors.\n\nDune is copyright Cryo Interactive Entertainment. This project is not affiliated with or endorsed by Cryo Interactive Entertainment or any rights holders.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenrakis%2Fcryogenic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenrakis%2Fcryogenic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenrakis%2Fcryogenic/lists"}