diff --git a/CMakeLists.txt b/CMakeLists.txt index d729de1..a7bf214 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.0) project(SpaceCadetPinball) set(CMAKE_CXX_STANDARD 11) @@ -191,10 +191,13 @@ set_source_files_properties( SpaceCadetPinball/imgui_impl_sdl.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS 1 ) -target_precompile_headers(SpaceCadetPinball - PUBLIC - SpaceCadetPinball/pch.h -) + +if(${CMAKE_VERSION} VERSION_GREATER "3.16.0" OR ${CMAKE_VERSION} VERSION_EQUAL "3.16.0") + target_precompile_headers(SpaceCadetPinball + PUBLIC + SpaceCadetPinball/pch.h + ) +endif() target_link_libraries(SpaceCadetPinball ${SDL2_LIBRARY} ${SDL2_MIXER_LIBRARY}) diff --git a/README.md b/README.md index 35676df..a0dda1c 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,88 @@ -# SpaceCadetPinball -**Summary:** Reverse engineering of `3D Pinball for Windows – Space Cadet`, a game bundled with Windows. + -**How to play:** Place compiled executable into a folder containing original game resources (not included).\ +# SpaceCadetPinball + +## Summary + +Reverse engineering of `3D Pinball for Windows – Space Cadet`, a game bundled with Windows. + +## How to play + +Place compiled executable into a folder containing original game resources (not included).\ Supports data files from Windows and Full Tilt versions of the game. -**Known source ports:** -| Platform | Author | URL | -| --- | --- | --- | -| PS Vita | Axiom | | -| Emscripten | alula |
Play online: https://alula.github.io/SpaceCadetPinball | -| Nintendo Switch | averne | https://github.com/averne/SpaceCadetPinball-NX | -| webOS TV | mariotaku | https://github.com/webosbrew/SpaceCadetPinball | -| Android (WIP) | Iscle | https://github.com/Iscle/SpaceCadetPinball | +## Known source ports + +| Platform | Author | URL | +| --------------- | --------- | ---------------------------------------------------------------------------------------------------------- | +| PS Vita | Axiom | | +| Emscripten | alula |
Play online: | +| Nintendo Switch | averne | | +| webOS TV | mariotaku | | +| Android (WIP) | Iscle | https://github.com/Iscle/SpaceCadetPinball | Platforms covered by this project: desktop Windows, Linux and macOS. -\ -\ -\ -\ -\ -\ -**Source:** - * `pinball.exe` from `Windows XP` (SHA-1 `2A5B525E0F631BB6107639E2A69DF15986FB0D05`) and its public PDB - * `CADET.EXE` 32bit version from `Full Tilt! Pinball` (SHA-1 `3F7B5699074B83FD713657CD94671F2156DBEDC4`) -**Tools used:** `Ghidra`, `Ida`, `Visual Studio` +
+
+
+
+
+
-**What was done:** - * All structures were populated, globals and locals named. - * All subs were decompiled, C pseudo code was converted to compilable C++. Loose (namespace?) subs were assigned to classes. +## Source -**Compiling:** +* `pinball.exe` from `Windows XP` (SHA-1 `2A5B525E0F631BB6107639E2A69DF15986FB0D05`) and its public PDB +* `CADET.EXE` 32bit version from `Full Tilt! Pinball` (SHA-1 `3F7B5699074B83FD713657CD94671F2156DBEDC4`) + +## Tools used + +`Ghidra`, `Ida`, `Visual Studio` + +## What was done + +* All structures were populated, globals and locals named. +* All subs were decompiled, C pseudo code was converted to compilable C++. Loose (namespace?) subs were assigned to classes. + +## Compiling + +Project uses `C++11` and depends on `SDL2` libs. + +### On Windows -Project uses `C++11` and depends on `SDL2` libs.\ -On Windows:\ Download and unpack devel packages for `SDL2` and `SDL2_mixer`.\ -Set paths to them in CMakeLists.txt, see suggested placement in /Libs.\ -Compile with Visual Studio; tested with 2019. +Set paths to them in `CMakeLists.txt`, see suggested placement in `/Libs`.\ +Compile with Visual Studio; tested with 2019. + +### On Linux -On Linux:\ Install devel packages for `SDL2` and `SDL2_mixer`.\ Compile with CMake; tested with GCC 10, Clang 11.\ -To cross-compile for Windows, install a 64-bit version of mingw and its `SDL2` and `SDL2_mixer` distributions, then use the `mingwcc.cmake` toolchain. +To cross-compile for Windows, install a 64-bit version of mingw and its `SDL2` and `SDL2_mixer` distributions, then use the `mingwcc.cmake` toolchain. + +### On macOS + +* **Homebrew**: Install the `SDL2`, `SDL2_mixer` homebrew packages. +* **MacPorts**: Install the `libSDL2`, `libSDL2_mixer` macports packages. + +Compile with CMake. Ensure that `CMAKE_OSX_ARCHITECTURES` variable is set for either `x86_64` Apple Intel or `arm64` for Apple Silicon. -On macOS:\ -**Homebrew**: Install the `SDL2`, `SDL2_mixer` homebrew packages.\ -**MacPorts**: Install the `libSDL2`, `libSDL2_mixer` macports packages.\ -Compile with CMake. Ensure that `CMAKE_OSX_ARCHITECTURES` variable is set for either `x86_64` Apple Intel or `arm64` for Apple Silicon.\ Tested with: macOS Big Sur (Intel) with Xcode 13 & macOS Montery Beta (Apple Silicon) with Xcode 13. -**Plans:** - * ~~Decompile original game~~ - * ~~Resizable window, scaled graphics~~ - * ~~Loader for high-res sprites from CADET.DAT~~ - * Misc features of Full Tilt: 3 music tracks, multiball, centered textboxes, etc. - * Cross-platform port - * Using SDL2, SDL2_mixer, ImGui - * Maybe: Android port - * Maybe x2: support for other two tables - * Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched +## Plans + +* ~~Decompile original game~~ +* ~~Resizable window, scaled graphics~~ +* ~~Loader for high-res sprites from CADET.DAT~~ +* Misc features of Full Tilt: 3 music tracks, multiball, centered textboxes, etc. +* Cross-platform port + * Using SDL2, SDL2_mixer, ImGui + * Maybe: Android port +* Maybe x2: support for other two tables + * Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched + +## On 64-bit bug that killed the game -**On 64-bit bug that killed the game:**\ I did not find it, decompiled game worked in x64 mode on the first try.\ It was either lost in decompilation or introduced in x64 port/not present in x86 build.\ Based on public description of the bug (no ball collision), I guess that the bug was in `TEdgeManager::TestGridBox` diff --git a/SpaceCadetPinball/Sound.cpp b/SpaceCadetPinball/Sound.cpp index 902c042..d492459 100644 --- a/SpaceCadetPinball/Sound.cpp +++ b/SpaceCadetPinball/Sound.cpp @@ -8,7 +8,11 @@ int* Sound::TimeStamps = nullptr; bool Sound::Init(int channels, bool enableFlag) { +#if SDL_MIXER_VERSION_ATLEAST(2, 0, 3) Mix_Init(MIX_INIT_MID); +#else + Mix_Init(MIX_INIT_FLUIDSYNTH); +#endif auto result = Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024); SetChannels(channels); Enable(enableFlag); diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index f8951e8..eb154a2 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -741,6 +741,69 @@ int winmain::event_handler(const SDL_Event* event) default: ; } break; + case SDL_JOYDEVICEADDED: + if (SDL_IsGameController(event->jdevice.which)) + { + SDL_GameControllerOpen(event->jdevice.which); + } + break; + case SDL_JOYDEVICEREMOVED: + { + SDL_GameController *controller = SDL_GameControllerFromInstanceID(event->jdevice.which); + if (controller) + { + SDL_GameControllerClose(controller); + } + } + break; + case SDL_CONTROLLERBUTTONDOWN: + switch (event->cbutton.button) + { + case SDL_CONTROLLER_BUTTON_A: + pb::keydown(Options.Key.Plunger); + break; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + pb::keydown(Options.Key.LeftFlipper); + break; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + pb::keydown(Options.Key.RightFlipper); + break; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + pb::keydown(Options.Key.LeftTableBump); + break; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + pb::keydown(Options.Key.RightTableBump); + break; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + pb::keydown(Options.Key.BottomTableBump); + break; + default: ; + } + break; + case SDL_CONTROLLERBUTTONUP: + switch (event->cbutton.button) + { + case SDL_CONTROLLER_BUTTON_A: + pb::keyup(Options.Key.Plunger); + break; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + pb::keyup(Options.Key.LeftFlipper); + break; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + pb::keyup(Options.Key.RightFlipper); + break; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + pb::keyup(Options.Key.LeftTableBump); + break; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + pb::keyup(Options.Key.RightTableBump); + break; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + pb::keyup(Options.Key.BottomTableBump); + break; + default: ; + } + break; default: ; }