diff --git a/libultraship/libultraship/InputEditor.cpp b/libultraship/libultraship/InputEditor.cpp index 156eafae3..5122e3d62 100644 --- a/libultraship/libultraship/InputEditor.cpp +++ b/libultraship/libultraship/InputEditor.cpp @@ -20,12 +20,12 @@ namespace Ship { return controlDeck->GetPhysicalDeviceFromVirtualSlot(slot); } - void InputEditor::DrawButton(const char* label, int32_t n64Btn) { - const std::shared_ptr backend = GetControllerPerSlot(CurrentPort); + void InputEditor::DrawButton(const char* label, int32_t n64Btn, int32_t currentPort, int32_t* btnReading) { + const std::shared_ptr backend = GetControllerPerSlot(currentPort); float size = 40; - bool readingMode = BtnReading == n64Btn; - bool disabled = (BtnReading != -1 && !readingMode) || !backend->Connected() || backend->GetGuid() == "Auto"; + bool readingMode = *btnReading == n64Btn; + bool disabled = (*btnReading != -1 && !readingMode) || !backend->Connected() || backend->GetGuid() == "Auto"; ImVec2 len = ImGui::CalcTextSize(label); ImVec2 pos = ImGui::GetCursorPos(); ImGui::SetCursorPosY(pos.y + len.y / 4); @@ -43,18 +43,18 @@ namespace Ship { const int32_t btn = backend->ReadRawPress(); if(btn != -1) { - backend->SetButtonMapping(CurrentPort, n64Btn, btn); - BtnReading = -1; + backend->SetButtonMapping(currentPort, n64Btn, btn); + *btnReading = -1; // avoid immediately triggering another button during gamepad nav ImGui::SetKeyboardFocusHere(0); } } - const std::string BtnName = backend->GetButtonName(CurrentPort, n64Btn); + const std::string BtnName = backend->GetButtonName(currentPort, n64Btn); if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName.c_str(), n64Btn).c_str())) { - BtnReading = n64Btn; + *btnReading = n64Btn; backend->ClearRawPress(); } @@ -64,6 +64,30 @@ namespace Ship { } } + void InputEditor::DrawControllerSelect(int32_t currentPort) { + auto controlDeck = Ship::Window::GetInstance()->GetControlDeck(); + std::string ControllerName = controlDeck->GetPhysicalDeviceFromVirtualSlot(currentPort)->GetControllerName(); + + if (ImGui::BeginCombo("##ControllerEntries", ControllerName.c_str())) { + for (uint8_t i = 0; i < controlDeck->GetNumPhysicalDevices(); i++) { + std::string DeviceName = controlDeck->GetPhysicalDevice(i)->GetControllerName(); + if (DeviceName != "Keyboard" && DeviceName != "Auto") { + DeviceName += "##" + std::to_string(i); + } + if (ImGui::Selectable(DeviceName.c_str(), i == controlDeck->GetVirtualDevice(currentPort))) { + controlDeck->SetPhysicalDevice(currentPort, i); + } + } + ImGui::EndCombo(); + } + + ImGui::SameLine(); + + if (ImGui::Button("Refresh")) { + controlDeck->ScanPhysicalDevices(); + } + } + void InputEditor::DrawVirtualStick(const char* label, ImVec2 stick) { ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y)); ImGui::BeginChild(label, ImVec2(68, 75), false); @@ -85,38 +109,19 @@ namespace Ship { } void InputEditor::DrawControllerSchema() { - auto controlDeck = Ship::Window::GetInstance()->GetControlDeck(); - auto Backend = controlDeck->GetPhysicalDeviceFromVirtualSlot(CurrentPort); + auto Backend = Ship::Window::GetInstance()->GetControlDeck()->GetPhysicalDeviceFromVirtualSlot(CurrentPort); auto profile = Backend->getProfile(CurrentPort); - bool IsKeyboard = Backend->GetGuid() == "Keyboard" || Backend->GetGuid() == "Auto" || !Backend->Connected(); - std::string ControllerName = Backend->GetControllerName(); - - if (ImGui::BeginCombo("##ControllerEntries", ControllerName.c_str())) { - for (uint8_t i = 0; i < controlDeck->GetNumPhysicalDevices(); i++) { - std::string DeviceName = controlDeck->GetPhysicalDevice(i)->GetControllerName(); - if (DeviceName != "Keyboard" && DeviceName != "Auto") { - DeviceName += "##"+std::to_string(i); - } - if (ImGui::Selectable(DeviceName.c_str(), i == controlDeck->GetVirtualDevice(CurrentPort))) { - controlDeck->SetPhysicalDevice(CurrentPort, i); - } - } - ImGui::EndCombo(); - } - - ImGui::SameLine(); - - if(ImGui::Button("Refresh")) { - controlDeck->ScanPhysicalDevices(); - } - + bool IsKeyboard = Backend->GetGuid() == "Keyboard" || Backend->GetGuid() == "Auto" || !Backend->Connected(); + + DrawControllerSelect(CurrentPort); + SohImGui::BeginGroupPanel("Buttons", ImVec2(150, 20)); - DrawButton("A", BTN_A); - DrawButton("B", BTN_B); - DrawButton("L", BTN_L); - DrawButton("R", BTN_R); - DrawButton("Z", BTN_Z); - DrawButton("START", BTN_START); + DrawButton("A", BTN_A, CurrentPort, &BtnReading); + DrawButton("B", BTN_B, CurrentPort, &BtnReading); + DrawButton("L", BTN_L, CurrentPort, &BtnReading); + DrawButton("R", BTN_R, CurrentPort, &BtnReading); + DrawButton("Z", BTN_Z, CurrentPort, &BtnReading); + DrawButton("START", BTN_START, CurrentPort, &BtnReading); SEPARATION(); #ifdef __SWITCH__ SohImGui::EndGroupPanel(IsKeyboard ? 7.0f : 56.0f); @@ -125,10 +130,10 @@ namespace Ship { #endif ImGui::SameLine(); SohImGui::BeginGroupPanel("Digital Pad", ImVec2(150, 20)); - DrawButton("Up", BTN_DUP); - DrawButton("Down", BTN_DDOWN); - DrawButton("Left", BTN_DLEFT); - DrawButton("Right", BTN_DRIGHT); + DrawButton("Up", BTN_DUP, CurrentPort, &BtnReading); + DrawButton("Down", BTN_DDOWN, CurrentPort, &BtnReading); + DrawButton("Left", BTN_DLEFT, CurrentPort, &BtnReading); + DrawButton("Right", BTN_DRIGHT, CurrentPort, &BtnReading); SEPARATION(); #ifdef __SWITCH__ SohImGui::EndGroupPanel(IsKeyboard ? 53.0f : 122.0f); @@ -137,10 +142,10 @@ namespace Ship { #endif ImGui::SameLine(); SohImGui::BeginGroupPanel("Analog Stick", ImVec2(150, 20)); - DrawButton("Up", BTN_STICKUP); - DrawButton("Down", BTN_STICKDOWN); - DrawButton("Left", BTN_STICKLEFT); - DrawButton("Right", BTN_STICKRIGHT); + DrawButton("Up", BTN_STICKUP, CurrentPort, &BtnReading); + DrawButton("Down", BTN_STICKDOWN, CurrentPort, &BtnReading); + DrawButton("Left", BTN_STICKLEFT, CurrentPort, &BtnReading); + DrawButton("Right", BTN_STICKRIGHT, CurrentPort, &BtnReading); if (!IsKeyboard) { ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8); @@ -181,10 +186,10 @@ namespace Ship { if (!IsKeyboard) { ImGui::SameLine(); SohImGui::BeginGroupPanel("Right Stick", ImVec2(150, 20)); - DrawButton("Up", BTN_VSTICKUP); - DrawButton("Down", BTN_VSTICKDOWN); - DrawButton("Left", BTN_VSTICKLEFT); - DrawButton("Right", BTN_VSTICKRIGHT); + DrawButton("Up", BTN_VSTICKUP, CurrentPort, &BtnReading); + DrawButton("Down", BTN_VSTICKDOWN, CurrentPort, &BtnReading); + DrawButton("Left", BTN_VSTICKLEFT, CurrentPort, &BtnReading); + DrawButton("Right", BTN_VSTICKRIGHT, CurrentPort, &BtnReading); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8); // 2 is the SDL value for right stick X axis @@ -282,10 +287,10 @@ namespace Ship { const ImVec2 cursor = ImGui::GetCursorPos(); SohImGui::BeginGroupPanel("C-Buttons", ImVec2(158, 20)); - DrawButton("Up", BTN_CUP); - DrawButton("Down", BTN_CDOWN); - DrawButton("Left", BTN_CLEFT); - DrawButton("Right", BTN_CRIGHT); + DrawButton("Up", BTN_CUP, CurrentPort, &BtnReading); + DrawButton("Down", BTN_CDOWN, CurrentPort, &BtnReading); + DrawButton("Left", BTN_CLEFT, CurrentPort, &BtnReading); + DrawButton("Right", BTN_CRIGHT, CurrentPort, &BtnReading); ImGui::Dummy(ImVec2(0, 5)); SohImGui::EndGroupPanel(); diff --git a/libultraship/libultraship/InputEditor.h b/libultraship/libultraship/InputEditor.h index 50b059e2d..23944814c 100644 --- a/libultraship/libultraship/InputEditor.h +++ b/libultraship/libultraship/InputEditor.h @@ -11,7 +11,8 @@ namespace Ship { bool Opened = false; public: void Init(); - void DrawButton(const char* label, int32_t n64Btn); + void DrawButton(const char* label, int32_t n64Btn, int32_t currentPort, int32_t* btnReading); + void DrawControllerSelect(int32_t currentPort); void DrawVirtualStick(const char* label, ImVec2 stick); void DrawControllerSchema(); void DrawHud(); diff --git a/libultraship/libultraship/KeyboardController.cpp b/libultraship/libultraship/KeyboardController.cpp index 88fb0f897..18225918f 100644 --- a/libultraship/libultraship/KeyboardController.cpp +++ b/libultraship/libultraship/KeyboardController.cpp @@ -74,7 +74,6 @@ namespace Ship { return strlen(name) == 0 ? "Unknown" : name; } - void KeyboardController::CreateDefaultBinding(int32_t virtualSlot) { auto profile = getProfile(virtualSlot); profile->Mappings[0x14D] = BTN_CRIGHT; @@ -95,6 +94,8 @@ namespace Ship { profile->Mappings[0x01E] = BTN_STICKLEFT; profile->Mappings[0x01F] = BTN_STICKDOWN; profile->Mappings[0x011] = BTN_STICKUP; + profile->Mappings[0x02A] = BTN_MODIFIER1; + profile->Mappings[0x036] = BTN_MODIFIER2; } const std::string KeyboardController::GetControllerName() { diff --git a/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/controller.h b/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/controller.h index fbcbae674..a72bab37f 100644 --- a/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/controller.h +++ b/libultraship/libultraship/Lib/Fast3D/U64/PR/ultra64/controller.h @@ -87,6 +87,8 @@ #define BTN_CUP 0x0008 #define BTN_R 0x0010 #define BTN_L 0x0020 +#define BTN_MODIFIER1 0x0040 +#define BTN_MODIFIER2 0x0080 #define BTN_DRIGHT 0x0100 #define BTN_DLEFT 0x0200 #define BTN_DDOWN 0x0400 diff --git a/libultraship/libultraship/SDLController.cpp b/libultraship/libultraship/SDLController.cpp index bc4500de1..075831bab 100644 --- a/libultraship/libultraship/SDLController.cpp +++ b/libultraship/libultraship/SDLController.cpp @@ -448,6 +448,8 @@ namespace Ship { profile->Mappings[SDL_CONTROLLER_BUTTON_START] = BTN_START; profile->Mappings[SDL_CONTROLLER_BUTTON_B] = BTN_B; profile->Mappings[SDL_CONTROLLER_BUTTON_A] = BTN_A; + profile->Mappings[SDL_CONTROLLER_BUTTON_LEFTSTICK] = BTN_MODIFIER1; + profile->Mappings[SDL_CONTROLLER_BUTTON_RIGHTSTICK] = BTN_MODIFIER2; for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) { profile->AxisDeadzones[i] = 16.0f; diff --git a/libultraship/libultraship/UltraController.h b/libultraship/libultraship/UltraController.h index cac606126..ca65f5dc4 100644 --- a/libultraship/libultraship/UltraController.h +++ b/libultraship/libultraship/UltraController.h @@ -89,6 +89,8 @@ #define BTN_CUP 0x00008 #define BTN_R 0x00010 #define BTN_L 0x00020 +#define BTN_MODIFIER1 0x00040 +#define BTN_MODIFIER2 0x00080 #define BTN_DRIGHT 0x00100 #define BTN_DLEFT 0x00200 #define BTN_DDOWN 0x00400 diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index e2eccab8b..e37d395d7 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -48,19 +48,12 @@ namespace GameControlEditor { } } - void DrawHelpIcon(const std::string& helptext, bool sameline = true, int Pos = 0) { + void DrawHelpIcon(const std::string& helptext) { // place the ? button to the most of the right side of the cell it is using. + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 22); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 15); ImGui::SmallButton("?"); - - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("%s", helptext.c_str()); - } - - if (sameline) { - //I do not use ImGui::SameLine(); because it make some element vanish. - ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 22); - } + UIWidgets::Tooltip(helptext.c_str()); } typedef uint32_t N64ButtonMask; @@ -222,27 +215,36 @@ namespace GameControlEditor { ImGui::EndTable(); } + // CurrentPort is indexed started at 1 here due to the Generic tab, instead of 0 like in InputEditor + // Therefore CurrentPort - 1 must always be used inside this function instead of CurrentPort + void DrawCustomButtons() { + SohImGui::GetInputEditor()->DrawControllerSelect(CurrentPort - 1); + + SohImGui::GetInputEditor()->DrawButton("Modifier 1", BTN_MODIFIER1, CurrentPort - 1, &BtnReading); + SohImGui::GetInputEditor()->DrawButton("Modifier 2", BTN_MODIFIER2, CurrentPort - 1, &BtnReading); + } + void DrawCameraControlPanel() { - if (!ImGui::CollapsingHeader("Camera Controls")) { + if (!ImGui::CollapsingHeader("Camera Controls")) { return; } ImVec2 cursor = ImGui::GetCursorPos(); ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5)); UIWidgets::PaddedEnhancementCheckbox("Invert Camera X Axis", "gInvertXAxis"); - UIWidgets::Tooltip("Inverts the Camera X Axis in:\n-Free camera\n-C-Up view\n-Weapon Aiming"); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); + DrawHelpIcon("Inverts the Camera X Axis in:\n-Free camera\n-C-Up view\n-Weapon Aiming"); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); UIWidgets::PaddedEnhancementCheckbox("Invert Camera Y Axis", "gInvertYAxis"); - UIWidgets::Tooltip("Inverts the Camera Y Axis in:\n-Free camera\n-C-Up view\n-Weapon Aiming"); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); + DrawHelpIcon("Inverts the Camera Y Axis in:\n-Free camera\n-C-Up view\n-Weapon Aiming"); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); UIWidgets::PaddedEnhancementCheckbox("Right Stick Aiming", "gRightStickAiming"); - UIWidgets::Tooltip("Allows for aiming with the rights stick when:\n-Aiming in the C-Up view\n-Aiming with weapons"); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); + DrawHelpIcon("Allows for aiming with the right stick when:\n-Aiming in the C-Up view\n-Aiming with weapons"); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); UIWidgets::PaddedEnhancementCheckbox("Disable Auto-Centering in First Person View", "gDisableAutoCenterView"); - UIWidgets::Tooltip("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming"); - } - - void DrawUI(bool& open) { + DrawHelpIcon("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming"); + } + + void DrawUI(bool& open) { if (!open) { CVar_SetS32("gGameControlEditorEnabled", false); return; @@ -250,8 +252,27 @@ namespace GameControlEditor { ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver); if (ImGui::Begin("Game Controls Configuration", &open)) { - DrawOcarinaControlPanel(); - DrawCameraControlPanel(); + ImGui::BeginTabBar("##CustomControllers"); + if (ImGui::BeginTabItem("Generic")) { + CurrentPort = 0; + ImGui::EndTabItem(); + } + + for (int i = 1; i <= 4; i++) { + if (ImGui::BeginTabItem(StringHelper::Sprintf("Port %d", i).c_str())) { + CurrentPort = i; + ImGui::EndTabItem(); + } + } + + ImGui::EndTabBar(); + + if (CurrentPort == 0) { + DrawOcarinaControlPanel(); + DrawCameraControlPanel(); + } else { + DrawCustomButtons(); + } } ImGui::End(); } diff --git a/soh/soh/Enhancements/controls/GameControlEditor.h b/soh/soh/Enhancements/controls/GameControlEditor.h index 68237e28c..6db983f52 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.h +++ b/soh/soh/Enhancements/controls/GameControlEditor.h @@ -1,5 +1,7 @@ #pragma once namespace GameControlEditor { + static int CurrentPort = 0; + static int BtnReading = -1; void Init(); } diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp index 2549651bd..fe82ef4eb 100644 --- a/soh/soh/GameMenuBar.cpp +++ b/soh/soh/GameMenuBar.cpp @@ -725,6 +725,12 @@ namespace GameMenuBar { UIWidgets::Tooltip("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97"); UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL", true, false); UIWidgets::Tooltip("Speak to Navi with L but enter first-person camera with C-Up"); + UIWidgets::PaddedEnhancementCheckbox("Enable walk speed modifiers", "gEnableWalkModify", true, false); + UIWidgets::Tooltip("Hold the assigned button to change the maximum walking speed\nTo change the assigned button, click Customize Game Controls"); + if (CVar_GetS32("gEnableWalkModify", 0)) { + UIWidgets::EnhancementSliderFloat("Modifier 1: %d %%", "##WalkMod1", "gWalkModifierOne", 0.0f, 5.0f, "", 1.0f, true); + UIWidgets::EnhancementSliderFloat("Modifier 2: %d %%", "##WalkMod2", "gWalkModifierTwo", 0.0f, 5.0f, "", 1.0f, true); + } ImGui::EndMenu(); } diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 3441ac4d5..eb09b50db 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -6031,8 +6031,12 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) { } } - if (CVar_GetS32("gMMBunnyHood", 0) != 0 && this->currentMask == PLAYER_MASK_BUNNY) { + if (CVar_GetS32("gMMBunnyHood", 0) && this->currentMask == PLAYER_MASK_BUNNY) { maxSpeed *= 1.5f; + } else if (CVar_GetS32("gEnableWalkModify", 0) && CHECK_BTN_ALL(sControlInput->cur.button, BTN_MODIFIER1)) { + maxSpeed *= CVar_GetFloat("gWalkModifierOne", 1.0f); + } else if (CVar_GetS32("gEnableWalkModify", 0) && CHECK_BTN_ALL(sControlInput->cur.button, BTN_MODIFIER2)) { + maxSpeed *= CVar_GetFloat("gWalkModifierTwo", 1.0f); } this->linearVelocity = CLAMP(this->linearVelocity, -maxSpeed, maxSpeed); @@ -7650,8 +7654,12 @@ void func_80842180(Player* this, GlobalContext* globalCtx) { } } - if (CVar_GetS32("gMMBunnyHood", 0) != 0 && this->currentMask == PLAYER_MASK_BUNNY) { + if (CVar_GetS32("gMMBunnyHood", 0) && this->currentMask == PLAYER_MASK_BUNNY) { sp2C *= 1.5f; + } else if (CVar_GetS32("gEnableWalkModify", 0) && CHECK_BTN_ALL(sControlInput->cur.button, BTN_MODIFIER1)) { + sp2C *= CVar_GetFloat("gWalkModifierOne", 1.0f); + } else if (CVar_GetS32("gEnableWalkModify", 0) && CHECK_BTN_ALL(sControlInput->cur.button, BTN_MODIFIER2)) { + sp2C *= CVar_GetFloat("gWalkModifierTwo", 1.0f); } func_8083DF68(this, sp2C, sp2A);