A port of Daniel Monteiro's MS-DOS dungeon crawler Dungeons of Noudar 3D (BSD 2-Clause) to the Sega 32X, built with Chilly Willy's Sega devkit (the toolchain shipped by viciious/32XDK, the same one Doom 32X Resurrection uses).
The compiled ROM is rom/noudar32x.32x — 512 KB, ready to run in any
32X emulator (PicoDrive, Ares, BlastEm-nightly, Gens/GS...) or on real
hardware from a flash cart. A gameplay capture recorded from the automated
test harness sits at the workspace root as noudar32x-gameplay.mp4.
The full original game, reimplemented in C on the 32X:
- all 8 maps, parsed from the original 40×40 ASCII level files, with the original tile property sheets driving wall/floor/ceiling/masked textures
- the original turn-based rules: damage = attack − defense, monsters act once per player turn and chase along the dominant axis, monks drop the Holy Health when wounded, cocoons hatch into the invulnerable premature Master Demon, spirit generators, ropes and reenforced doors that flood-fill sections of the level open ("You hear mechanisms in action")
- the original items: Sword of sorrow, Crossbow of damnation (3 bolts a
shot, hitscan), Shield of restoration (supercharges the crossbow for +10
damage at 5 power), the Quiver, the Holy Health — and holy soil
*that recharges holy items - level exits (
9doorways), chapter interstitials, the game-over epilogue and the ending — hero faith and inventory carry across levels - all original art: the 32×32 textures and monster sprites, the logo, the Valdés Leal paintings, the 8×8 font, chapter texts
A raycaster written for the 32X rather than a translation of the original's
polygon rasterizer (see src/render.c):
- 128×80 internal 8bpp buffer in SDRAM, expanded 2×2 with 32-bit writes to a 256×160 viewport — 30 fps sustained on the master SH-2
- one DDA per column with the SH-2 hardware divider (39-cycle divides); textured floors and ceilings per cell, animated lava, scrolling cloud sky where the map has no ceiling
- bars / arches / magic seals / slots are masked billboards collected during the ray walk; monsters, items and blood splats are depth-sorted billboards clipped against the column z-buffer
- one global 64-colour palette replicated as 4 CRAM shade banks — a pixel
is
(shade << 6) | colour, so distance fog costs zero per-pixel work — plus full-palette swaps for the damage/heal flashes - grid movement is interpolated (⅛ cell, 1/32 turn per frame) so the turn-based game scrolls smoothly like a 90s "free look" crawler
| Button | Action |
|---|---|
| D-pad ↑ / ↓ | step forward / backward (a turn) |
| D-pad ← / → | turn 90° (free) |
| C + ← / → | strafe (a turn) |
| B | use selected item: swing sword / fire crossbow / drink (a turn) |
| A | cycle inventory |
| Start | pick up item underfoot / advance menus |
Walking into an enemy also swings the sword.
./setup.sh # toolchain -> /opt/toolchains/sega, PicoDrive test core
make # -> rom/noudar32x.32x
make test # host rule tests + 12 point-to-point tests on the real ROMRegenerate src/assets.c from the original assets in res/ with
make assets (needs python3 + Pillow).
| Path | Role |
|---|---|
src/game.c/.h |
the game rules, a C reimplementation of noudar-core |
src/render.c |
raycaster: walls, flats, sky, billboards, 2× blit |
src/hud.c, src/menu.c |
status panel, log, title/chapter/ending screens |
src/main.c |
state machine, input, test beacon (COMM2 + SDRAM struct) |
src/hw_32x.c, src/32x.h |
VDP init, line tables, flip, pads |
src/fixed.c/.h |
16.16 fixed point, SH-2 hardware-divider divides |
src/sh2_crt0.s, md/ |
devkit boot code: ROM header, SH-2/68000 startup |
src/assets.c/.h |
generated — palette, textures, font, maps, texts |
tools/gen_assets.py |
asset pipeline (quantize, shade banks, prp parser) |
tools/romfix.py |
pads the ROM, writes the MD header checksum |
tests/game_host.c |
32 host-side assertions on the game rules |
tests/host_render.c |
desktop oracle: renders the real game off-console |
tests/harness.c, tests/run_tests.py |
headless PicoDrive point-to-point suite |
make test runs two layers:
- Host tests —
game.ccompiled natively with ASan/UBSan; asserts spawns, blocking, rope/door flood-fills, monk drops, cocoon hatching, crossbow ammo math, supercharged shots, pickups, level completion, state carry-over and hero death (32 checks). - ROM tests — the real
.32xinside headless PicoDrive; asserts the header/checksum, boot, no-black-screen on three different screens, the title→chapter→play state machine, movement/turn/strafe/turn-economy, a scripted fight that kills the Fallen Hero, smooth-scroll animation, ≥20 fps in the dungeon and HUD chrome — via both framebuffer pixels and a live game-state beacon in SDRAM (12 tests).
The original game — code and assets — is © 2016 Daniel Monteiro, BSD
2-Clause (see LICENSE-noudar.md); this port keeps that licence for the
reimplemented rules and the converted assets in res//src/assets.c.
Boot code (sh2_crt0.s, md/*.s) comes from Chilly Willy's freely
distributed 32X devkit samples.