From 8a421a26237af2ff28125067ca8aeb4e5eb6c22e Mon Sep 17 00:00:00 2001 From: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com> Date: Fri, 1 Oct 2021 09:05:38 +0300 Subject: [PATCH] Implemented player controls dialog. This last missing major feature brings v2 into feature parity with the original and closer to release. Ref issues #16, #17. --- SpaceCadetPinball/options.cpp | 204 ++++++++++++++++++++++------------ SpaceCadetPinball/options.h | 40 ++++--- SpaceCadetPinball/pb.cpp | 25 +++-- SpaceCadetPinball/winmain.cpp | 19 ++-- 4 files changed, 184 insertions(+), 104 deletions(-) diff --git a/SpaceCadetPinball/options.cpp b/SpaceCadetPinball/options.cpp index 8005b34..d41f691 100644 --- a/SpaceCadetPinball/options.cpp +++ b/SpaceCadetPinball/options.cpp @@ -8,44 +8,23 @@ #include "Sound.h" #include "winmain.h" -optionsStruct options::Options{}; - -short options::vk_list[28] -{ - -32703, - 0x5A, - -32720, - 0x39, - 0x402E, - 0x402F, - 0x403B, - 0x4027, - 0x405B, - 0x405D, - 0x20, - 0x0D, - 0x9, - 0x14, - 0x25, - 0x27, - 0x26, - 0x28, - 0x2D, - 0x2E, - 0x24, - 0x23, - 0x21, - 0x22, - 0x90, - 0x91, - 0x13, - -1 -}; - -std::map options::settings{}; - constexpr int options::MaxUps, options::MaxFps, options::MinUps, options::MinFps, options::DefUps, options::DefFps; +optionsStruct options::Options{}; +std::map options::settings{}; +ControlsStruct options::RebindControls{}; +bool options::ShowDialog = false; +const ControlRef* options::ControlWaitingForKey = nullptr; +const ControlRef options::Controls[6] +{ + {"Left Flipper", RebindControls.LeftFlipper}, + {"Right Flipper", RebindControls.RightFlipper}, + {"Left Table Bump", RebindControls.LeftTableBump}, + {"Right Table Bump", RebindControls.RightTableBump}, + {"Bottom Table Bump", RebindControls.BottomTableBump}, + {"Plunger", RebindControls.Plunger}, +}; + void options::init() { @@ -68,36 +47,26 @@ void options::init() Options.Sounds = 1; Options.Music = 0; Options.FullScreen = 0; - Options.LeftFlipperKeyDft = SDLK_z; - Options.RightFlipperKeyDft = SDLK_SLASH; - Options.PlungerKeyDft = SDLK_SPACE; - Options.LeftTableBumpKeyDft = SDLK_x; - Options.RightTableBumpKeyDft = SDLK_PERIOD; - Options.BottomTableBumpKeyDft = SDLK_UP; - /*pinball::get_rc_int(159, &Options.LeftFlipperKeyDft); - pinball::get_rc_int(160, &Options.RightFlipperKeyDft); - pinball::get_rc_int(161, &Options.PlungerKeyDft); - pinball::get_rc_int(162, &Options.LeftTableBumpKeyDft); - pinball::get_rc_int(163, &Options.RightTableBumpKeyDft); - pinball::get_rc_int(164, &Options.BottomTableBumpKeyDft);*/ - Options.LeftFlipperKey = Options.LeftFlipperKeyDft; - Options.RightFlipperKey = Options.RightFlipperKeyDft; - Options.PlungerKey = Options.PlungerKeyDft; - Options.LeftTableBumpKey = Options.LeftTableBumpKeyDft; - Options.RightTableBumpKey = Options.RightTableBumpKeyDft; + Options.KeyDft.LeftFlipper = SDLK_z; + Options.KeyDft.RightFlipper = SDLK_SLASH; + Options.KeyDft.Plunger = SDLK_SPACE; + Options.KeyDft.LeftTableBump = SDLK_x; + Options.KeyDft.RightTableBump = SDLK_PERIOD; + Options.KeyDft.BottomTableBump = SDLK_UP; + Options.Key = Options.KeyDft; Options.Players = 1; - Options.BottomTableBumpKey = Options.BottomTableBumpKeyDft; + Options.UniformScaling = true; Options.Sounds = get_int("Sounds", Options.Sounds); Options.Music = get_int("Music", Options.Music); Options.FullScreen = get_int("FullScreen", Options.FullScreen); Options.Players = get_int("Players", Options.Players); - Options.LeftFlipperKey = get_int("Left Flipper key", Options.LeftFlipperKey); - Options.RightFlipperKey = get_int("Right Flipper key", Options.RightFlipperKey); - Options.PlungerKey = get_int("Plunger key", Options.PlungerKey); - Options.LeftTableBumpKey = get_int("Left Table Bump key", Options.LeftTableBumpKey); - Options.RightTableBumpKey = get_int("Right Table Bump key", Options.RightTableBumpKey); - Options.BottomTableBumpKey = get_int("Bottom Table Bump key", Options.BottomTableBumpKey); + Options.Key.LeftFlipper = get_int("Left Flipper key", Options.Key.LeftFlipper); + Options.Key.RightFlipper = get_int("Right Flipper key", Options.Key.RightFlipper); + Options.Key.Plunger = get_int("Plunger key", Options.Key.Plunger); + Options.Key.LeftTableBump = get_int("Left Table Bump key", Options.Key.LeftTableBump); + Options.Key.RightTableBump = get_int("Right Table Bump key", Options.Key.RightTableBump); + Options.Key.BottomTableBump = get_int("Bottom Table Bump key", Options.Key.BottomTableBump); Options.UniformScaling = get_int("Uniform scaling", Options.UniformScaling); ImGui::GetIO().FontGlobalScale = get_float("UI Scale", 1.0f); Options.Resolution = get_int("Screen Resolution", -1); @@ -123,12 +92,12 @@ void options::uninit() set_int("Music", Options.Music); set_int("FullScreen", Options.FullScreen); set_int("Players", Options.Players); - set_int("Left Flipper key", Options.LeftFlipperKey); - set_int("Right Flipper key", Options.RightFlipperKey); - set_int("Plunger key", Options.PlungerKey); - set_int("Left Table Bump key", Options.LeftTableBumpKey); - set_int("Right Table Bump key", Options.RightTableBumpKey); - set_int("Bottom Table Bump key", Options.BottomTableBumpKey); + set_int("Left Flipper key", Options.Key.LeftFlipper); + set_int("Right Flipper key", Options.Key.RightFlipper); + set_int("Plunger key", Options.Key.Plunger); + set_int("Left Table Bump key", Options.Key.LeftTableBump); + set_int("Right Table Bump key", Options.Key.RightTableBump); + set_int("Bottom Table Bump key", Options.Key.BottomTableBump); set_int("Screen Resolution", Options.Resolution); set_int("Uniform scaling", Options.UniformScaling); set_float("UI Scale", ImGui::GetIO().FontGlobalScale); @@ -241,9 +210,108 @@ void options::toggle(Menu1 uIDCheckItem) } } -void options::keyboard() +void options::KeyDown(int key) { - //DialogBoxParamA(nullptr, "KEYMAPPER", nullptr, KeyMapDlgProc, 0); + if (ControlWaitingForKey) + { + // Skip function keys, just in case. + if (key < SDLK_F1 || key > SDLK_F12) + { + ControlWaitingForKey->Option = key; + ControlWaitingForKey = nullptr; + } + } +} + +void options::ShowControlDialog() +{ + if (!ShowDialog) + { + ControlWaitingForKey = nullptr; + RebindControls = Options.Key; + ShowDialog = true; + } +} + +void options::RenderControlDialog() +{ + if (!ShowDialog) + return; + + ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2{500, 400}); + if (ImGui::Begin("3D Pinball: Player Controls", &ShowDialog)) + { + ImGui::TextUnformatted("Instructions"); + ImGui::Separator(); + + ImGui::TextWrapped( + "To change game controls, click the control button, press the new key, and then choose OK."); + ImGui::TextWrapped( + "To restore 3D Pinball to its original settings, choose Default, and then choose OK."); + ImGui::TextWrapped("Original warns against binding the same key to multiple controls, but does not forbid it."); + ImGui::Spacing(); + + ImGui::TextUnformatted("Control Options"); + ImGui::Separator(); + + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{5, 10}); + if (ImGui::BeginTable("Controls", 2, ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) + { + for (auto& ctrl : Controls) + { + ImGui::TableNextColumn(); + if (ImGui::BeginTable("Control", 2, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableNextColumn(); + ImGui::TextWrapped("%s", ctrl.Name); + + ImGui::TableNextColumn(); + if (ControlWaitingForKey == &ctrl) + { + ImGui::Button("Press the key", ImVec2(-1, 0)); + } + else + { + auto keyName = SDL_GetKeyName(ctrl.Option); + if (!keyName[0]) + keyName = "Unknown key"; + if (ImGui::Button(keyName, ImVec2(-1, 0))) + { + ControlWaitingForKey = &ctrl; + } + } + ImGui::EndTable(); + } + } + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + ImGui::Spacing(); + + if (ImGui::Button("OK")) + { + Options.Key = RebindControls; + ShowDialog = false; + } + + ImGui::SameLine(); + if (ImGui::Button("Cancel")) + { + ShowDialog = false; + } + + ImGui::SameLine(); + if (ImGui::Button("Default")) + { + RebindControls = Options.KeyDft; + ControlWaitingForKey = nullptr; + } + } + ImGui::End(); + ImGui::PopStyleVar(); + + if (!ShowDialog) + ControlWaitingForKey = nullptr; } void options::MyUserData_ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line) diff --git a/SpaceCadetPinball/options.h b/SpaceCadetPinball/options.h index d3fab42..004ad11 100644 --- a/SpaceCadetPinball/options.h +++ b/SpaceCadetPinball/options.h @@ -29,24 +29,24 @@ enum class Menu1:int WindowLinearFilter = 601, }; +struct ControlsStruct +{ + int LeftFlipper; + int RightFlipper; + int Plunger; + int LeftTableBump; + int RightTableBump; + int BottomTableBump; +}; + struct optionsStruct { + ControlsStruct Key; + ControlsStruct KeyDft; int Sounds; int Music; int FullScreen; int Players; - int LeftFlipperKey; - int RightFlipperKey; - int PlungerKey; - int LeftTableBumpKey; - int RightTableBumpKey; - int BottomTableBumpKey; - int LeftFlipperKeyDft; - int RightFlipperKeyDft; - int PlungerKeyDft; - int LeftTableBumpKeyDft; - int RightTableBumpKeyDft; - int BottomTableBumpKeyDft; int Resolution; bool UniformScaling; bool LinearFiltering; @@ -55,6 +55,12 @@ struct optionsStruct bool ShowMenu; }; +struct ControlRef +{ + const char* Name; + int& Option; +}; + class options { @@ -73,11 +79,15 @@ public: static float get_float(LPCSTR lpValueName, float defaultValue); static void set_float(LPCSTR lpValueName, float data); static void toggle(Menu1 uIDCheckItem); - - static void keyboard(); + static void KeyDown(int key); + static void ShowControlDialog(); + static void RenderControlDialog(); private: - static short vk_list[28]; static std::map settings; + static ControlsStruct RebindControls; + static bool ShowDialog; + static const ControlRef Controls[6]; + static const ControlRef* ControlWaitingForKey; static void MyUserData_ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); static void* MyUserData_ReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index bf90f99..4c9bfda 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -365,27 +365,27 @@ void pb::keyup(int key) { if (game_mode == 1 && !winmain::single_step && !demo_mode) { - if (key == options::Options.LeftFlipperKey) + if (key == options::Options.Key.LeftFlipper) { MainTable->Message(1001, time_now); } - else if (key == options::Options.RightFlipperKey) + else if (key == options::Options.Key.RightFlipper) { MainTable->Message(1003, time_now); } - else if (key == options::Options.PlungerKey) + else if (key == options::Options.Key.Plunger) { MainTable->Message(1005, time_now); } - else if (key == options::Options.LeftTableBumpKey) + else if (key == options::Options.Key.LeftTableBump) { nudge::un_nudge_right(0, nullptr); } - else if (key == options::Options.RightTableBumpKey) + else if (key == options::Options.Key.RightTableBump) { nudge::un_nudge_left(0, nullptr); } - else if (key == options::Options.BottomTableBumpKey) + else if (key == options::Options.Key.BottomTableBump) { nudge::un_nudge_up(0, nullptr); } @@ -394,6 +394,7 @@ void pb::keyup(int key) void pb::keydown(int key) { + options::KeyDown(key); if (winmain::single_step || demo_mode) return; if (game_mode != 1) @@ -402,35 +403,35 @@ void pb::keydown(int key) return; } control::pbctrl_bdoor_controller(key); - if (key == options::Options.LeftFlipperKey) + if (key == options::Options.Key.LeftFlipper) { MainTable->Message(1000, time_now); return; } - if (key == options::Options.RightFlipperKey) + if (key == options::Options.Key.RightFlipper) { MainTable->Message(1002, time_now); } else { - if (key == options::Options.PlungerKey) + if (key == options::Options.Key.Plunger) { MainTable->Message(1004, time_now); return; } - if (key == options::Options.LeftTableBumpKey) + if (key == options::Options.Key.LeftTableBump) { if (!MainTable->TiltLockFlag) nudge::nudge_right(); return; } - if (key == options::Options.RightTableBumpKey) + if (key == options::Options.Key.RightTableBump) { if (!MainTable->TiltLockFlag) nudge::nudge_left(); return; } - if (key == options::Options.BottomTableBumpKey) + if (key == options::Options.Key.BottomTableBump) { if (!MainTable->TiltLockFlag) nudge::nudge_up(); diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index 7084243..189724e 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -324,8 +324,8 @@ void winmain::RenderUi() } ImGui::PopStyleColor(1); ImGui::PopID(); - ImGui::End(); } + ImGui::End(); ImGui::PopStyleVar(); return; } @@ -424,7 +424,7 @@ void winmain::RenderUi() { if (!single_step) pause(); - options::keyboard(); + options::ShowControlDialog(); } if (ImGui::BeginMenu("Table Resolution")) { @@ -524,6 +524,7 @@ void winmain::RenderUi() high_score::RenderHighScoreDialog(); if (ShowSpriteViewer) render::SpriteViewer(&ShowSpriteViewer); + options::RenderControlDialog(); } int winmain::event_handler(const SDL_Event* event) @@ -598,7 +599,7 @@ int winmain::event_handler(const SDL_Event* event) case SDLK_F8: if (!single_step) pause(); - options::keyboard(); + options::ShowControlDialog(); break; case SDLK_F9: options::toggle(Menu1::Show_Menu); @@ -644,14 +645,14 @@ int winmain::event_handler(const SDL_Event* event) SDL_SetWindowGrab(MainWindow, SDL_TRUE); } else - pb::keydown(options::Options.LeftFlipperKey); + pb::keydown(options::Options.Key.LeftFlipper); break; case SDL_BUTTON_RIGHT: if (!pb::cheat_mode) - pb::keydown(options::Options.RightFlipperKey); + pb::keydown(options::Options.Key.RightFlipper); break; case SDL_BUTTON_MIDDLE: - pb::keydown(options::Options.PlungerKey); + pb::keydown(options::Options.Key.Plunger); break; default: break; @@ -668,14 +669,14 @@ int winmain::event_handler(const SDL_Event* event) SDL_SetWindowGrab(MainWindow, SDL_FALSE); } if (!pb::cheat_mode) - pb::keyup(options::Options.LeftFlipperKey); + pb::keyup(options::Options.Key.LeftFlipper); break; case SDL_BUTTON_RIGHT: if (!pb::cheat_mode) - pb::keyup(options::Options.RightFlipperKey); + pb::keyup(options::Options.Key.RightFlipper); break; case SDL_BUTTON_MIDDLE: - pb::keyup(options::Options.PlungerKey); + pb::keyup(options::Options.Key.Plunger); break; default: break;