diff options
| author | Garrett Cox <garrettjcox@gmail.com> | 2026-01-17 13:08:33 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-17 13:08:33 -0600 |
| commit | 5cbb0fc3e7eeabd976b2d0e049e3eead89cbfa42 (patch) | |
| tree | cbdc0d359b725ff9a9693da4c7cc44e5b34270ba | |
| parent | 214872e7f38185e2208d480cb6055dc304dcde6c (diff) | |
Tweaks to speed modifier cheat (#1464)
- Moved to cheats menu (removed from controller menu)
- Added BtnSelector UIWidget
- On controller menu pressed inputs will now darken to indicate they are pressed
- Simplified Movement speed cheat, combined swim & walk speed and just made it one modifier instead of two
| -rw-r--r-- | mm/2s2h/BenGui/BenInputEditorWindow.cpp | 84 | ||||
| -rw-r--r-- | mm/2s2h/BenGui/BenMenu.cpp | 22 | ||||
| -rw-r--r-- | mm/2s2h/BenGui/Menu.cpp | 7 | ||||
| -rw-r--r-- | mm/2s2h/BenGui/MenuTypes.h | 1 | ||||
| -rw-r--r-- | mm/2s2h/BenGui/UIWidgets.cpp | 90 | ||||
| -rw-r--r-- | mm/2s2h/BenGui/UIWidgets.hpp | 2 | ||||
| -rw-r--r-- | mm/2s2h/Enhancements/Player/LinkSpeedModifier.cpp | 94 |
7 files changed, 177 insertions, 123 deletions
diff --git a/mm/2s2h/BenGui/BenInputEditorWindow.cpp b/mm/2s2h/BenGui/BenInputEditorWindow.cpp index 422c858fb..5281c4061 100644 --- a/mm/2s2h/BenGui/BenInputEditorWindow.cpp +++ b/mm/2s2h/BenGui/BenInputEditorWindow.cpp @@ -15,6 +15,8 @@ using namespace UIWidgets; +static s32 heldInputs = 0; + BenInputEditorWindow::~BenInputEditorWindow() { } @@ -447,6 +449,9 @@ void BenInputEditorWindow::DrawButtonLine(const char* buttonName, uint8_t port, ImVec4 color = CHIP_COLOR_N64_GREY) { ImGui::NewLine(); ImGui::SameLine(SCALE_IMGUI_SIZE(32.0f)); + if (heldInputs & bitmask) { + color.w = 0.5f; + } DrawInputChip(buttonName, color); ImGui::SameLine(SCALE_IMGUI_SIZE(86.0f)); for (auto id : mBitmaskToMappingIds[port][bitmask]) { @@ -1201,65 +1206,6 @@ void BenInputEditorWindow::DrawGyroSection(uint8_t port) { } } -void BenInputEditorWindow::DrawModifierButtonsSection(uint8_t port) { - DrawButtonLine("M1", port, BTN_CUSTOM_MODIFIER1); - DrawButtonLine("M2", port, BTN_CUSTOM_MODIFIER2); - - ImGui::BeginDisabled(CVarGetInteger("gSettings.DisableChanges", 0)); - CVarCheckbox("Enable Speed Modifiers", "gSettings.SpeedModifier.Enable", - CheckboxOptions() - .Color(THEME_COLOR) - .Tooltip("Hold the assigned button to change the maximum walking or swimming speed.")); - if (CVarGetInteger("gSettings.SpeedModifier.Enable", 0)) { - UIWidgets::Spacer(5); - Ship::GuiWindow::BeginGroupPanel("Speed Modifier", ImGui::GetContentRegionAvail()); - CVarCheckbox("Toggle modifier instead of holding", "gSettings.SpeedModifier.Toggle", - CheckboxOptions().Color(THEME_COLOR)); - Ship::GuiWindow::BeginGroupPanel("Walk Modifier", ImGui::GetContentRegionAvail()); - CVarCheckbox("Enable Walk Speed Modifier", "gSettings.SpeedModifier.WalkEnable", - CheckboxOptions().Color(THEME_COLOR)); - CVarSliderFloat("Walk Modifier 1: %.0f %%", "gSettings.SpeedModifier.WalkMapping1", - FloatSliderOptions() - .Color(THEME_COLOR) - .IsPercentage() - .Min(0.0f) - .Max(15.0f) - .DefaultValue(1.0f) - .ShowAdjustmentButtons(true)); - CVarSliderFloat("Walk Modifier 2: %.0f %%", "gSettings.SpeedModifier.WalkMapping2", - FloatSliderOptions() - .Color(THEME_COLOR) - .IsPercentage() - .Min(0.0f) - .Max(15.0f) - .DefaultValue(1.0f) - .ShowAdjustmentButtons(true)); - Ship::GuiWindow::EndGroupPanel(0); - Ship::GuiWindow::BeginGroupPanel("Swim Modifier", ImGui::GetContentRegionAvail()); - CVarCheckbox("Enable Swim Speed Modifier", "gSettings.SpeedModifier.SwimEnable", - CheckboxOptions().Color(THEME_COLOR)); - CVarSliderFloat("Swim Modifier 1: %.0f %%", "gSettings.SpeedModifier.SwimMapping1", - FloatSliderOptions() - .Color(THEME_COLOR) - .IsPercentage() - .Min(0.0f) - .Max(8.75f) - .DefaultValue(1.0f) - .ShowAdjustmentButtons(true)); - CVarSliderFloat("Swim Modifier 2: %.0f %%", "gSettings.SpeedModifier.SwimMapping2", - FloatSliderOptions() - .Color(THEME_COLOR) - .IsPercentage() - .Min(0.0f) - .Max(8.75f) - .DefaultValue(1.0f) - .ShowAdjustmentButtons(true)); - Ship::GuiWindow::EndGroupPanel(0); - Ship::GuiWindow::EndGroupPanel(0); - } - ImGui::EndDisabled(); -} - const ImGuiTableFlags PANEL_TABLE_FLAGS = ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV; const ImGuiTableColumnFlags PANEL_TABLE_COLUMN_FLAGS = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoSort; @@ -1440,6 +1386,13 @@ void BenInputEditorWindow::DrawPortTabContents(uint8_t portIndex) { DrawButtonLine(StringHelper::Sprintf("%s##DPad", ICON_FA_ARROW_RIGHT).c_str(), portIndex, BTN_DRIGHT); } + if (ImGui::CollapsingHeader("Modifier Buttons", NULL, ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::TextWrapped("These can be bound to physical buttons and be selected for use in various\nenhancements, " + "but otherwise have no use on their own."); + DrawButtonLine("M1", portIndex, BTN_CUSTOM_MODIFIER1); + DrawButtonLine("M2", portIndex, BTN_CUSTOM_MODIFIER2); + } + if (ImGui::CollapsingHeader("Analog Stick", NULL, ImGuiTreeNodeFlags_DefaultOpen)) { DrawStickSection(portIndex, Ship::LEFT); } @@ -1460,10 +1413,6 @@ void BenInputEditorWindow::DrawPortTabContents(uint8_t portIndex) { DrawLEDSection(portIndex); } - if (ImGui::CollapsingHeader("Modifier Buttons")) { - DrawModifierButtonsSection(portIndex); - } - ImGui::PopStyleColor(); ImGui::PopStyleColor(); ImGui::PopStyleColor(); @@ -1561,3 +1510,12 @@ void BenInputEditorWindow::OffsetMappingPopup() { pos.x += HORIZONTAL_OFFSET; ImGui::SetNextWindowPos(pos); } + +static RegisterShipInitFunc initFunc( + []() { + COND_HOOK(OnGameStateMainStart, true, []() { + Input* input = CONTROLLER1(gGameState); + heldInputs = input->cur.button; + }); + }, + {}); diff --git a/mm/2s2h/BenGui/BenMenu.cpp b/mm/2s2h/BenGui/BenMenu.cpp index 0cabb5b35..58e57a6a4 100644 --- a/mm/2s2h/BenGui/BenMenu.cpp +++ b/mm/2s2h/BenGui/BenMenu.cpp @@ -114,6 +114,13 @@ static const std::vector<const char*> timeStopOptions = { "Temples + Mini Dungeons", // TIME_STOP_TEMPLES_DUNGEONS }; +static const std::vector<const char*> speedModifierModeOptions = { + "Off", + "On", + "Hold Buttons", + "Toggle Buttons", +}; + static const std::vector<const char*> notificationPosition = { "Top Left", "Top Right", "Bottom Left", "Bottom Right", "Hidden", }; @@ -880,7 +887,7 @@ void BenMenu::AddEnhancements() { .Max(3.0f)); path = { "Enhancements", "Cheats", SECTION_COLUMN_1 }; - AddSidebarEntry("Enhancements", "Cheats", 3); + AddSidebarEntry("Enhancements", "Cheats", 2); AddWidget(path, "Infinite Health", WIDGET_CVAR_CHECKBOX) .CVar("gCheats.InfiniteHealth") .Options(CheckboxOptions().Tooltip("Always have full Hearts.")); @@ -934,6 +941,19 @@ void BenMenu::AddEnhancements() { "Houses, Pirate's Fortress, Beneath the Well, Ancient Castle of Ikana, and Secret Shrine.") .ComboVec(&timeStopOptions)); + path.column = SECTION_COLUMN_2; + AddWidget(path, "Speed Modifier", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Speed Modifier Mode", WIDGET_CVAR_COMBOBOX) + .CVar("gCheats.SpeedModifier.Mode") + .Options(ComboboxOptions().ComboVec(&speedModifierModeOptions).LabelPosition(LabelPosition::None)); + AddWidget(path, "Multiplier:", WIDGET_CVAR_SLIDER_FLOAT) + .CVar("gCheats.SpeedModifier.Value") + .PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger("gCheats.SpeedModifier.Mode", 0); }) + .Options(FloatSliderOptions().Format("%.1fx").Min(0.0f).Max(6.0f).DefaultValue(1.0f)); + AddWidget(path, "Button Combination:", WIDGET_CVAR_BTN_SELECTOR) + .CVar("gCheats.SpeedModifier.Btn") + .PreFunc([](WidgetInfo& info) { info.isHidden = CVarGetInteger("gCheats.SpeedModifier.Mode", 0) < 2; }); + //// Gameplay Enhancements path = { "Enhancements", "Gameplay", SECTION_COLUMN_1 }; AddSidebarEntry("Enhancements", "Gameplay", 3); diff --git a/mm/2s2h/BenGui/Menu.cpp b/mm/2s2h/BenGui/Menu.cpp index 510888b37..9b35cadfa 100644 --- a/mm/2s2h/BenGui/Menu.cpp +++ b/mm/2s2h/BenGui/Menu.cpp @@ -441,6 +441,13 @@ void Menu::MenuDrawItem(WidgetInfo& widget, uint32_t width, UIWidgets::Colors me } } } break; + case WIDGET_CVAR_BTN_SELECTOR: { + if (UIWidgets::CVarBtnSelector(widget.name.c_str(), widget.cVar)) { + if (widget.callback != nullptr) { + widget.callback(widget); + } + } + } break; case WIDGET_BUTTON: { auto options = std::static_pointer_cast<UIWidgets::ButtonOptions>(widget.options); options->color = menuThemeIndex; diff --git a/mm/2s2h/BenGui/MenuTypes.h b/mm/2s2h/BenGui/MenuTypes.h index e8a152d2c..b3d52eda2 100644 --- a/mm/2s2h/BenGui/MenuTypes.h +++ b/mm/2s2h/BenGui/MenuTypes.h @@ -50,6 +50,7 @@ typedef enum { WIDGET_CVAR_COMBOBOX, WIDGET_CVAR_SLIDER_INT, WIDGET_CVAR_SLIDER_FLOAT, + WIDGET_CVAR_BTN_SELECTOR, WIDGET_BUTTON, WIDGET_COLOR_24, // color picker without alpha WIDGET_COLOR_32, // color picker with alpha diff --git a/mm/2s2h/BenGui/UIWidgets.cpp b/mm/2s2h/BenGui/UIWidgets.cpp index 61efce012..f9139d66f 100644 --- a/mm/2s2h/BenGui/UIWidgets.cpp +++ b/mm/2s2h/BenGui/UIWidgets.cpp @@ -6,6 +6,7 @@ #include <unordered_map> #include "2s2h/ShipUtils.h" #include <spdlog/fmt/fmt.h> +#include "2s2h/BenPort.h" namespace UIWidgets { @@ -1314,6 +1315,95 @@ void DrawFlagTableArray8Mask(const FlagTable& flagTable, uint16_t row, uint8_t& } ImGui::PopID(); } + +std::map<std::string, int32_t> buttonMap = { + { "A", BTN_A }, + { "B", BTN_B }, + { "Z", BTN_Z }, + { "START", BTN_START }, + { "D-Up", BTN_DUP }, + { "D-Down", BTN_DDOWN }, + { "D-Left", BTN_DLEFT }, + { "D-Right", BTN_DRIGHT }, + { "L", BTN_L }, + { "R", BTN_R }, + { "C-Up", BTN_CUP }, + { "C-Down", BTN_CDOWN }, + { "C-Left", BTN_CLEFT }, + { "C-Right", BTN_CRIGHT }, + { "Modifier 1", BTN_CUSTOM_MODIFIER1 }, + { "Modifier 2", BTN_CUSTOM_MODIFIER2 }, +}; +bool BtnSelector(const char* label, int32_t* value) { + bool dirty = false; + ImGui::PushID(label); + ImGui::BeginGroup(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("%s", label); + ImGui::BeginDisabled(false); + PushStyleCombobox(UIWidgets::Colors::DarkGray); + ImGui::BeginGroup(); + int32_t currentValue = *value; + int index = 0; + for (const auto& [buttonName, buttonMask] : buttonMap) { + if (currentValue & buttonMask) { + ImGui::PushID(buttonName.c_str()); + if (index++ > 0) { + ImGui::Text("+"); + ImGui::SameLine(); + } + if (UIWidgets::Button(buttonName.c_str(), UIWidgets::ButtonOptions() + .Tooltip("Remove this button from the combination") + .Color(UIWidgets::Colors::Gray) + .Size(UIWidgets::Sizes::Inline))) { + currentValue &= ~buttonMask; + dirty = true; + } + ImGui::PopID(); + ImGui::SameLine(); + } + } + if (UIWidgets::Button("+", UIWidgets::ButtonOptions({ { .tooltip = "Add a button to the combination" } }) + .Size(UIWidgets::Sizes::Inline))) { + ImGui::OpenPopup("Add Button"); + } + if (ImGui::BeginPopup("Add Button")) { + UIWidgets::PushStyleMenuItem(); + for (const auto& [buttonName, buttonMask] : buttonMap) { + if (!(currentValue & buttonMask)) { + if (ImGui::MenuItem(buttonName.c_str())) { + currentValue |= buttonMask; + dirty = true; + } + } + } + UIWidgets::PopStyleMenuItem(); + ImGui::EndPopup(); + } + ImGui::EndGroup(); + PopStyleCombobox(); + ImGui::EndDisabled(); + ImGui::EndGroup(); + ImGui::PopID(); + + if (dirty) { + *value = currentValue; + } + return dirty; +} + +bool CVarBtnSelector(const char* label, const char* cvarName) { + bool dirty = false; + int32_t value = CVarGetInteger(cvarName, 0); + if (BtnSelector(label, &value)) { + CVarSetInteger(cvarName, value); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); + ShipInit::Init(cvarName); + dirty = true; + } + return dirty; +} + } // namespace UIWidgets ImVec4 GetRandomValue() { diff --git a/mm/2s2h/BenGui/UIWidgets.hpp b/mm/2s2h/BenGui/UIWidgets.hpp index 6ee668026..0dccf4ea9 100644 --- a/mm/2s2h/BenGui/UIWidgets.hpp +++ b/mm/2s2h/BenGui/UIWidgets.hpp @@ -1159,6 +1159,8 @@ void DrawFlagArray16(const std::string& name, uint16_t& flags, Colors color = Co void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t& flags); void DrawFlagTableArray8(const FlagTable& flagTable, uint16_t row, uint8_t& flags); void DrawFlagTableArray8Mask(const FlagTable& flagTable, uint16_t row, uint8_t& flags); +bool BtnSelector(const char* label, int32_t* value); +bool CVarBtnSelector(const char* label, const char* cvarName); } // namespace UIWidgets ImVec4 GetRandomValue(); diff --git a/mm/2s2h/Enhancements/Player/LinkSpeedModifier.cpp b/mm/2s2h/Enhancements/Player/LinkSpeedModifier.cpp index 142c43c24..3a06cb43c 100644 --- a/mm/2s2h/Enhancements/Player/LinkSpeedModifier.cpp +++ b/mm/2s2h/Enhancements/Player/LinkSpeedModifier.cpp @@ -8,87 +8,63 @@ extern "C" { extern Input* sPlayerControlInput; } -#define CVAR_SPEED_MODIFIER_NAME "gSettings.SpeedModifier.Enable" -#define CVAR_SPEED_MODIFIER_TOGGLE "gSettings.SpeedModifier.Toggle" -#define CVAR_WALK_MODIFIER_NAME "gSettings.SpeedModifier.WalkEnable" -#define CVAR_SWIM_MODIFIER_NAME "gSettings.SpeedModifier.SwimEnable" -#define CVAR_SPEED CVarGetInteger(CVAR_SPEED_MODIFIER_NAME, 0) -#define CVAR_SPEED_TOGGLE CVarGetInteger(CVAR_SPEED_MODIFIER_TOGGLE, 0) -#define CVAR_WALK CVarGetInteger(CVAR_WALK_MODIFIER_NAME, 0) -#define CVAR_SWIM CVarGetInteger(CVAR_SWIM_MODIFIER_NAME, 0) +#define CVAR_SPEED_MODIFIER_MODE_NAME "gCheats.SpeedModifier.Mode" +#define CVAR_SPEED_MODIFIER_TOGGLE_NAME "gCheats.SpeedModifier.Toggle" +#define CVAR_SPEED_MODIFIER_VALUE_NAME "gCheats.SpeedModifier.Value" +#define CVAR_SPEED_MODIFIER_BTN_NAME "gCheats.SpeedModifier.Btn" +#define CVAR_SPEED_MODIFIER_MODE CVarGetInteger(CVAR_SPEED_MODIFIER_MODE_NAME, 0) +#define CVAR_SPEED_MODIFIER_TOGGLE CVarGetInteger(CVAR_SPEED_MODIFIER_TOGGLE_NAME, 0) +#define CVAR_SPEED_MODIFIER_VALUE CVarGetFloat(CVAR_SPEED_MODIFIER_VALUE_NAME, 1.0f) +#define CVAR_SPEED_MODIFIER_BTN CVarGetInteger(CVAR_SPEED_MODIFIER_BTN_NAME, 0) -bool speedToggle1; -bool speedToggle2; +bool btnHeldOrToggled = false; void RegisterLinkSpeedModifier() { + // Reset in case they disabled while toggled + btnHeldOrToggled = false; - COND_VB_SHOULD(VB_SPEED_MODIFIER_WALK, CVAR_WALK && CVAR_SPEED, { + COND_VB_SHOULD(VB_SPEED_MODIFIER_WALK, CVAR_SPEED_MODIFIER_MODE, { f32* speedTarget = va_arg(args, f32*); - if (CVAR_SPEED_TOGGLE) { - if (speedToggle1) { - *speedTarget *= CVarGetFloat("gSettings.SpeedModifier.WalkMapping1", 1.0f); - } else if (speedToggle2) { - *speedTarget *= CVarGetFloat("gSettings.SpeedModifier.WalkMapping2", 1.0f); - } - } else { - if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_CUSTOM_MODIFIER1)) { - *speedTarget *= CVarGetFloat("gSettings.SpeedModifier.WalkMapping1", 1.0f); - } else if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_CUSTOM_MODIFIER2)) { - *speedTarget *= CVarGetFloat("gSettings.SpeedModifier.WalkMapping2", 1.0f); - } + if (CVAR_SPEED_MODIFIER_MODE == 1 || btnHeldOrToggled) { + *speedTarget *= CVAR_SPEED_MODIFIER_VALUE; } }); - COND_VB_SHOULD(VB_SPEED_MODIFIER_SWIM, CVAR_SWIM && CVAR_SPEED, { - *should = false; + COND_VB_SHOULD(VB_SPEED_MODIFIER_SWIM, CVAR_SPEED_MODIFIER_MODE, { f32* incrStep = va_arg(args, f32*); f32* maxSpeed = va_arg(args, f32*); f32* speed = va_arg(args, f32*); f32* speedTarget = va_arg(args, f32*); f32 swimMod = 1.0f; - if (CVAR_SPEED_TOGGLE) { - if (speedToggle1) { - swimMod *= CVarGetFloat("gSettings.SpeedModifier.SwimMapping1", 1.0f); - } else if (speedToggle2) { - swimMod *= CVarGetFloat("gSettings.SpeedModifier.SwimMapping2", 1.0f); - } - - // sControlInput is NULL to prevent inputs while surfacing after obtaining an underwater item so we want - // to ignore it for that case - } else if (sPlayerControlInput != NULL) { - if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_CUSTOM_MODIFIER1)) { - swimMod *= CVarGetFloat("gSettings.SpeedModifier.SwimMapping1", 1.0f); - } else if (CHECK_BTN_ALL(sPlayerControlInput->cur.button, BTN_CUSTOM_MODIFIER2)) { - swimMod *= CVarGetFloat("gSettings.SpeedModifier.SwimMapping2", 1.0f); - } + // sControlInput is NULL to prevent inputs while surfacing after obtaining an underwater item so we want + // to ignore it for that case + if (sPlayerControlInput == NULL) { + return; } - *maxSpeed *= swimMod; - - Math_AsymStepToF(speed, *speedTarget * 0.8f * swimMod, *incrStep, (fabsf(*speed) * 0.02f) + 0.05f); + if (CVAR_SPEED_MODIFIER_MODE == 1 || btnHeldOrToggled) { + swimMod *= CVAR_SPEED_MODIFIER_VALUE; + *maxSpeed *= swimMod; + Math_AsymStepToF(speed, *speedTarget * 0.8f * swimMod, *incrStep, (fabsf(*speed) * 0.02f) + 0.05f); + *should = false; + } }); - COND_HOOK(OnPassPlayerInputs, CVAR_SPEED && (CVAR_WALK || CVAR_SWIM), [](Input* input) { - if (CVAR_SPEED_TOGGLE) { - - if (CHECK_BTN_ALL(input->press.button, BTN_CUSTOM_MODIFIER1)) { - speedToggle1 = !speedToggle1; - speedToggle2 = false; + COND_HOOK(OnPassPlayerInputs, CVAR_SPEED_MODIFIER_MODE >= 2, [](Input* input) { + if (CVAR_SPEED_MODIFIER_MODE == 2) { + if (CHECK_BTN_ALL(input->cur.button, CVAR_SPEED_MODIFIER_BTN)) { + btnHeldOrToggled = true; + } else { + btnHeldOrToggled = false; } - if (CHECK_BTN_ALL(input->press.button, BTN_CUSTOM_MODIFIER2)) { - speedToggle2 = !speedToggle2; - speedToggle1 = false; + } else { + if (CHECK_BTN_ALL(input->press.button, CVAR_SPEED_MODIFIER_BTN)) { + btnHeldOrToggled = !btnHeldOrToggled; } } }); - - COND_HOOK(OnConsoleLogoUpdate, CVAR_SPEED && (CVAR_WALK || CVAR_SWIM), []() { - speedToggle1 = false; - speedToggle2 = false; - }); } -static RegisterShipInitFunc initFunc(RegisterLinkSpeedModifier, { CVAR_SPEED_MODIFIER_NAME, CVAR_SPEED_MODIFIER_TOGGLE, - CVAR_WALK_MODIFIER_NAME, CVAR_SWIM_MODIFIER_NAME });
\ No newline at end of file +static RegisterShipInitFunc initFunc(RegisterLinkSpeedModifier, { CVAR_SPEED_MODIFIER_MODE_NAME });
\ No newline at end of file |
