# macrosoft3dpinball `3D Pinball for Windows – Space Cadet` on macOS. Two halves: - The vendored decompilation (below) — the faithful original. - `godot/` — a Godot 4.7 pinball testbed whose real job is A/B-ing 3D physics backends (Box3D vs Jolt vs GodotPhysics) on CCD, hinge-motor flippers, and joint limits. See `godot/README.md` for the probe harness and current findings (Box3D never tunnels with CCD off but has an inverted hinge-motor sign vs Jolt). Vendored copy of [k4zmu2a/SpaceCadetPinball](https://github.com/k4zmu2a/SpaceCadetPinball) (MIT) at upstream commit `cb9b7b8`, not a submodule — patch it in place, pull upstream by re-vendoring. ## Build (Apple Silicon) ```bash cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=arm64 \ -DCMAKE_PREFIX_PATH="$(brew --prefix sdl2);$(brew --prefix sdl2_mixer)" cmake --build build -j8 ``` Binary lands in `bin/SpaceCadetPinball`. Needs `brew install sdl2 sdl2_mixer`. Do **not** use upstream `build-mac-app.sh` — it downloads SDL2 `.framework` DMGs and builds a signed universal `.app`+`.dmg`. Unnecessary here; brew SDL2 is already installed. ## Gotchas - `CMakeLists.txt` line ~27 upstream hard-set `CMAKE_OSX_ARCHITECTURES "arm64;x86_64"`, which silently overrode the `-D` flag the README tells you to pass. Universal linking then fails because brew SDL2 is arm64-only. Patched to only set the default when not given on the command line. Re-apply this when re-vendoring upstream. - Homebrew resolves `sdl2` to `sdl2-compat` (SDL2 API on top of SDL3). Links and runs fine. - Deployment target is 10.11, so the link emits "built for newer version 26.0" warnings against the brew dylibs. Harmless. ## Game data (not in this repo) The engine ships no assets. It needs the original data files, which are Microsoft's and are **not redistributable** — supply them from your own media (Windows XP or earlier install disc for `PINBALL.DAT`; the retail `Full Tilt! Pinball` CD for `CADET.DAT`). `.DAT`/`.MID` are gitignored so they never land in a commit. Drop them in any of these; first match wins in the order `CADET.DAT`, `PINBALL.DAT`, `DEMO.DAT`: - the working directory, or `bin/` next to the binary - `~/Library/Application Support/SpaceCadetPinball/` ← preferred, keeps the repo clean Without them the binary exits with "Could not load game data" and lists these paths. ## The other two Full Tilt tables (Dragon's Keep, Pirate's Cove) The retail CD carries `DRAGON.DAT` and `PIRATES.DAT` alongside `CADET.DAT`. **They do not play, and making them play is a months-long reverse-engineering project per table — not a loader fix.** Investigated 2026-07-28; evidence, so nobody re-derives it: - The container format is shared (`PARTOUT(4.0)RESOURCE`) and all three tables use the same five component type ids (200, 201, 202, 300, 400). So the DAT *parses* fine. That is the easy half. - Only ~35 of Dragon's 278 named components and ~36 of Pirate's 355 match Cadet's names. The 88-entry `control::score_components` table in `control.cpp` binds behaviour to those names, and `control.cpp` is 4600 lines of Cadet-specific rules (missions, ranks, wormholes, Gravity Well). Each table needs its own equivalent written from scratch. - Both tables use float attributes the engine has no semantics for: `409`, `1306`, `1406`, `1600`–`1604` (plus `604`, `704`–`706` for Dragon, `1405` for Pirate). These are hard errors, not missing-value errors — e.g. `loader::kicker` accepts only 401–406 and calls `error(10, 20)` on anything else. Dragon's kickers carry `409`, meaning unknown. - Upstream will not do it. Maintainer k4zmu2a, issue #148: the effort is "comparable to doing the whole process all over again, once per table", and issue #20: "I most likely will not be adding support for DRAGON and PIRATE tables." Cadet was reversed with the aid of the *public PDB symbols* shipped for XP's `pinball.exe`; no equivalent symbols exist for the Full Tilt table binaries. Four issues have requested it (#20, #148, #160, #256); none has ever produced a PR. If someone does take it on, `tools/datdump.py` dumps and diffs DAT structure, and [DatPartoutExplorer](https://github.com/belaw/DatPartoutExplorer) has a `Resource Identifiers.txt` mapping attribute ids to object types — including entries flagged as unused in Cadet, which is the obvious first place to look up what `1600`–`1604` mean.