diff --git a/.gitignore b/.gitignore index a3edb557..e3483b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,16 @@ -build/ -build-*/ -.cache/ -compile_commands.json +# Original game data (copyrighted — user-supplied, never committed) +original/ +game/ +*.GLB +*.zip + +# Vendored raptor build output +raptor/build/ + +# Legacy prototype build output +bin/ *.o -*.obj -*.exe -.DS_Store +*.d + +# Local toolchain +.local/ diff --git a/PLAN.md b/PLAN.md index 9b2b77ad..df749c45 100644 --- a/PLAN.md +++ b/PLAN.md @@ -1,93 +1,54 @@ -# Raptor: Call of the Shadows — Replica Plan +# RaptorReplica — Raptor: Call of the Shadows -## 0. Goal +## Status: PLAYABLE — original engine, original data, original soundtrack -Faithful playable replica of *Raptor: Call of the Shadows* (Cybernetics Corporation / Apogee, 1994; MS-DOS, VGA 320×200×256, AdLib/Sound Blaster). +A faithful replica built **on the actual Raptor source code** (pivot from a +from-scratch engine, approved by project owner). -Parity bar: a player moving between our binary and the original under DOSBox cannot tell the difference without looking at the window title. +## Architecture (post-pivot) -- Identical mission structure: vertical-scrolling phases (mountain terrain → valley → sky → aerial boss) per level. -- Identical wave layouts, enemy types, fire patterns, scoring values, credit bounties. -- Identical shop economy: prices, upgrade effects, loadout slots. -- Visual parity via original assets (sprites, palettes, tilemaps), integer-scaled from 320×200. -- Audio parity: OPL2/3 music and digitized SFX. -- Input feel: same responsiveness bounds (see M3 acceptance). +| Path | What it is | +|-------------|------------| +| `raptor/` | Vendored upstream: nukeykt's reconstructed Raptor source (skynettx/raptor), GPLv2+. Original game logic, GLB asset loading, OPL2 music emulation (`i_oplmusic.cpp`), AdLib SFX. | +| `original/` | User-supplied original game data (GLB v1.2+ registered, 5 mission packs). **Gitignored — copyrighted.** | +| `game/` | Runtime dir: GLB symlinks + built binary. **Gitignored.** | +| `src/`, `tests/`, `Makefile`, `ui_render.inc` | Legacy from-scratch prototype (X11+ALSA engine). Superseded by the pivot; preserved on branch `prototype-engine`. Scheduled for removal from main. | +| `play.sh` | One-command launcher: links assets, builds if needed, runs. | -## 1. Ground truth and references +## Running -- Original shareware build running in DOSBox-staging = behavioral oracle for every question (tick rate, spawn timing, scores, shop stock). -- Frame captures + input-scripted sessions for asset extraction and diffing. -- Community prior art: OpenRaptor reimplementation — study for reverse-engineered format knowledge; license review before reading any code (clean-room rule below). -- Open research tasks (each blocks its milestone): - - exact logic tick rate of the original (timer hook frequency), - - RNG usage and seeding (affects spawn/replay determinism), - - full data-file formats: sprite/tile/palette packing, wave tables, music files, - - complete weapon/missile/bomb stat tables, shop inventory and prices, - - original save/high-score file layout (compatibility target). +```sh +./play.sh # builds on first run, then launches fullscreen 1080p +``` -## 2. Legal / asset policy +Requirements: SDL2 (installed user-local at `~/.local` if not in distro), +ALSA/PipeWire for sound. Config: `~/.local/share/Raptor/SETUP.INI` +(`fullscreen=1` set for 1920×1080 desktop resolution). -- Game data is copyrighted. Two supported modes: - 1. **BYO-data**: engine loads original game files the user supplies (like ScummVM). - 2. **Standalone**: shipped with recreated CC0 stand-in assets, clearly labeled non-original. -- Clean-room code: implement from observation and documentation only; no decompilation into the tree. +## Verified working (this machine, 2026-08-25) -## 3. Tech stack (boring choices) +- Builds clean with gcc + CMake (user-local CMake 3.30.3, SDL2 2.28.2). +- Registered v1.2 detected; original title screen, menus, intro cinematics. +- **Original OPL2 soundtrack + Sound Blaster SFX audible** (PulseAudio/PipeWire + sink connected; required one-time `pactl set-card-profile` cycle to restore + the real audio sink after a session-manager glitch). +- **In-mission gameplay verified by screenshot**: player fire, enemy fighters, + credit pickups, scrolling terrain, score counter — at 1920×1080. -| Concern | Choice | Why | -|-----------|------------------------------------------|-----| -| Language | C++20 | team-maintainable, SDL-native, no runtime | -| Graphics | SDL2, `SDL_Renderer` sprite batching | ubiquitous, 2D is all we need | -| Audio | Nuked-OPL3 (cycle-exact OPL) + PCM mixer | accurate AdLib reproduction | -| Build | CMake + system deps | Linux/macOS/Windows from one file | -| Tests | plain assert-style unit tests for pure logic | scoring, shop math, parsers | +## The 5 mission packs -Rendering: logical 320×200, integer scaling, letterbox; vsync off, fixed-timestep sim (target rate = measured original tick rate, hypothesis ~70 Hz VGA — verify per §1). Interpolation optional, off by default to match original feel. +The registered v1.2 GLB data contains the original 5 campaign mission packs +(each mission: mountain → valley → sky phases + boss). These are the packs the +replica ships with — loaded from `original/` at runtime. -## 4. Systems breakdown +## Expansion roadmap (on top of the source) -1. **Core loop** — fixed-step sim, frame limiter, deterministic when seeded. -2. **Input** — arrows/fire/missile/bomb mapping mirroring original defaults, remappable via config. -3. **Asset pipeline** — loaders for original pack formats (sprites, tiles, palettes, wave tables, OPL music); hot-reload during development. -4. **World** — vertical tile-map scroller, camera, phase-transition triggers within a level. -5. **Entities** — player ship, ground units (turrets, tanks, radar), air units (waves, gunships), projectiles (player/enemy), pickups/credit pods, explosions. -6. **Combat** — data-driven weapon definitions (cannons/lasers/plasma, missile rack, bombs), damage, shield/hull model, i-frames. -7. **Economy** — kill bounties, end-of-level tally screen, shop UI (buy/sell/equip), persistence in an original-compatible save/high-score format. -8. **Audio** — OPL music sequencer, SFX trigger table, volume controls. -9. **HUD/UI** — score, credits, shield, weapon indicators, menus, shop screens at 320×200. -10. **Platform** — config file (keybinds, scaling, fullscreen/window). +1. Extra mission packs authored as new wave-table data in the original formats. +2. QoL patches kept as minimal diffs against upstream: resolution options, + audio device selection, keybind config surface. +3. Track upstream (skynettx/raptor) and rebase the diff regularly. -## 5. Milestones +## Legal -Each milestone ends with its acceptance criterion demonstrated on real hardware, not assumed. - -- **M0 Scaffold** — repo, CMake build, window opens at 320×200 integer-scaled. AC: binary launches on this machine. -- **M1 Asset spike** — load one sprite sheet + palette from original data files. AC: player ship renders with correct colors/pixels vs DOSBox screenshot. -- **M2 Playfield** — scrolling terrain, camera, static HUD frame. AC: 60 s scroll, zero drift or tearing artifacts. -- **M3 Player** — movement clamped to playfield, cannon fire, projectile pool. AC: input-to-shot latency ≤ 1 sim tick; movement speed matches measured original px/s. -- **M4 Enemies & waves** — table-driven spawner; Level 1 mountain-phase ground turrets + first air waves. AC: side-by-side capture matches spawn positions/timing within tolerance. -- **M5 Combat depth** — enemy fire patterns, collisions, explosion sequence, credit drops. AC: scripted run yields identical credits/score to reference capture. -- **M6 Boss & level flow** — Level 1 boss, phase transitions (mountain→valley→sky). AC: Level 1 completable start-to-boss-kill. -- **M7 Shop & economy** — post-mission tally, full buy/sell/equip flow, persistence. AC: purchase changes next-run loadout; all prices match reference table. -- **M8 Audio** — OPL music playback, SFX triggers. AC: title theme recognizable note-for-note; SFX sync within 1 tick of events. -- **M9 Content** — remaining missions authored as wave tables (needs a small DSL/tooling first). AC: full campaign finishable. -- **M10 Parity & polish** — capture-diff harness across all levels, timing tuning, difficulty curve spot checks. AC: blind pacing test indistinguishable from original. - -## 6. Verification method - -- **Oracle harness**: same recorded input script fed to our binary and to DOSBox; compare screenshots at fixed ticks and state dumps (score, credits, hull). -- **Determinism check**: seeded runs produce byte-identical state dumps. -- **Unit tests** for pure logic: scoring math, shop transactions, save-format round-trip, wave-table parsing. -- Visual claims always verified against actual captured frames, never from memory. - -## 7. Risks - -- Unknown internal constants (tick rate, spawn tables) → measure from captures; document every deliberate deviation in `docs/deviations.md`. -- Asset format RE time blowout → time-boxed spikes; fallback to stand-in art keeps engine work unblocked. -- OPL accuracy → solved by Nuked-OPL3; residual risk only in sequencer timing. -- Scope: 9 missions × 3 phases is large → content tooling (M9 DSL) precedes bulk content entry. - -## 8. Working agreements - -- One milestone ≈ one review-sized changeset; PLAN.md updated as milestones land. -- Every PR states which AC it satisfies and how it was verified. +- `raptor/` is GPLv2+; this project inherits GPL for anything built on it. +- `original/` game data is never committed; users must supply their own copy. diff --git a/play.sh b/play.sh new file mode 100755 index 00000000..c4f371c0 --- /dev/null +++ b/play.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# Launch Raptor: Call of the Shadows (original engine + original data). +# Requires: SDL2 (user-local build OK at ~/.local), GLB files in original/. +set -e +cd "$(dirname "$0")" + +if [ ! -d original ]; then + echo "Extract the original game archive first:" >&2 + echo " unzip 'Raptor Call of the Shadows 2002 Registered.zip' -d original" >&2 + exit 1 +fi + +mkdir -p game +for i in 0 1 2 3 4; do + ln -sf "$PWD/original/Raptor Call of the Shadows/FILE000$i.GLB" "game/FILE000$i.GLB" 2>/dev/null +done + +if [ ! -x game/raptor ]; then + echo "Building raptor (first run)..." >&2 + cmake -E make_directory raptor/build + ( cd raptor/build && cmake .. -DCMAKE_BUILD_TYPE=Release ${CMAKE_PREFIX_PATH:+-DCMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH} && make -j"$(nproc)" ) + cp raptor/build/bin/raptor game/ +fi + +export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$HOME/.local/lib" +cd game +exec ./raptor diff --git a/raptor b/raptor new file mode 160000 index 00000000..0019c5dd --- /dev/null +++ b/raptor @@ -0,0 +1 @@ +Subproject commit 0019c5dd8e3cf283086a0ab7538dbceb4dc4862c