Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This project uses version tags that match the mod version in `everest.yaml`, whi
### Fixed

- Ignore Click Teleport clicks while the game is paused, including the click that unpauses it, so a click on the pause menu never moves Madeline or toggles Cursor Zoom. Cursor Tools, Cursor Zoom, Entity Inspector and Free Camera mouse control also stand down while Menu Mouse is driving a menu.
- Right-clicking SRT Slot Previous/Next, Timescale Decrease/Increase, Frame Stepper Step Once, Open Debug Map, the FPS Bypass row, and FPS Bypass Smooth Camera now edits and clears the real hotkey, including one saved from Everest's old keyboard and controller screens. The Grab Mode popup gets a **Cycle** button for the grab-mode cycling hotkey.

## Akron Beta 84

Expand Down
17 changes: 17 additions & 0 deletions Source/Overlay/akron-overlay-bindable-actions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ private static IEnumerable<BindableAction> BuildPopupBindableActions(Level level
yield return new BindableAction(PopupActionKey("Grab Mode", "Hold"), "Grab Mode / Hold", () => SetConfiguredGrabMode(GrabModes.Hold));
yield return new BindableAction(PopupActionKey("Grab Mode", "Toggle"), "Grab Mode / Toggle", () => SetConfiguredGrabMode(GrabModes.Toggle));
yield return new BindableAction(PopupActionKey("Grab Mode", "Invert"), "Grab Mode / Invert", () => SetConfiguredGrabMode(GrabModes.Invert));
// Cycle and Smooth Camera bind to native ButtonBindings (ResolveDefaultButtonBinding),
// so the hotkey handlers fire them; these entries list them in the Keybinds tab.
yield return new BindableAction(PopupActionKey("Grab Mode", "Cycle"), "Grab Mode / Cycle", AkronActions.CycleGrabMode);
yield return new BindableAction(PopupActionKey("FPS Bypass", "Smooth Camera"), "FPS Bypass / Smooth Camera",
() => AkronModule.Settings.FrameBypassCameraSmoothing = NextCameraSmoothing(AkronModule.Settings.FrameBypassCameraSmoothing));

yield return new BindableAction(PopupActionKey("Noclip", "Toggle"), "Noclip / Enabled", () => {
bool next = !AkronModule.Settings.Noclip;
Expand Down Expand Up @@ -764,6 +769,18 @@ private static ButtonBinding ResolveDefaultButtonBinding(AkronModuleSettings set
"popup/StartPos/Load Slot 7" => settings.LoadStartPosSlot7,
"popup/StartPos/Load Slot 8" => settings.LoadStartPosSlot8,
"popup/StartPos/Load Slot 9" => settings.LoadStartPosSlot9,
// These native binds had no other in-game editor once Everest's generated
// keyboard/controller screens left the mod options, so their overlay controls
// edit the real binding instead of adding a separate overlay one.
"popup/SRT Slot/Previous" => settings.PreviousSlot,
"popup/SRT Slot/Next" => settings.NextSlot,
"popup/Timescale/Decrease" => settings.DecreaseTimescale,
"popup/Timescale/Increase" => settings.IncreaseTimescale,
"popup/Frame Stepper/Step Once" => settings.StepFrame,
"popup/Grab Mode/Cycle" => settings.CycleGrabMode,
Comment thread
Microck marked this conversation as resolved.
"Global/FPS Bypass" => settings.ToggleFrameBypass,
"popup/FPS Bypass/Smooth Camera" => settings.CycleFrameBypassCameraSmoothing,
"Creator/Open Debug Map" => settings.OpenDebugMap,
Comment thread
Microck marked this conversation as resolved.
"Player/Noclip" => null,
"Player/Hazard Accuracy" => null,
"Player/Click Teleport" => settings.ClickTeleportCursor,
Expand Down
1 change: 1 addition & 0 deletions Source/Overlay/akron-overlay-bypass-popups.cs
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ private void DrawFpsBypassPopupControls(string popupId)
{
AkronModule.Settings.FrameBypassCameraSmoothing = NextCameraSmoothing(AkronModule.Settings.FrameBypassCameraSmoothing);
}
DrawPopupActionBindingContext("FPS Bypass", "Smooth Camera", "FPS Bypass / Smooth Camera");
DrawPopupTooltip("Fancy is highest quality, Fast is cheaper but can jitter backgrounds, Off leaves the camera pixel-locked.");

if (ImGui.Button("Objects: " + AkronModule.Settings.FrameBypassObjectSmoothing + "##" + popupId))
Expand Down
5 changes: 5 additions & 0 deletions Source/Overlay/akron-overlay-gameplay-popups.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ private void DrawGrabModePopupControls(string popupId) {
DrawGrabModeChoice("Hold", GrabModes.Hold, popupId);
DrawGrabModeChoice("Toggle", GrabModes.Toggle, popupId);
DrawGrabModeChoice("Invert", GrabModes.Invert, popupId);
if (ImGui.Button("Cycle##" + popupId)) {
AkronActions.CycleGrabMode();
}
DrawPopupActionBindingContext("Grab Mode", "Cycle", "Grab Mode / Cycle");
DrawPopupTooltip("Step to the next grab mode. Right-click to bind a key that does the same.");
ImGui.TextUnformatted("Configured: " + AkronModule.Settings.GrabModeOverrideMode);
ImGui.TextUnformatted("Active: " + Settings.Instance.GrabMode);
}
Expand Down
5 changes: 4 additions & 1 deletion Source/Overlay/akron-overlay-keybind-entries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ private static IEnumerable<KeybindOverviewSpec> BuildTopLevelCustomKeybindOvervi

foreach (OverlayEntry entry in BuildEntriesForTab(tabName, level)) {
string actionKey = string.IsNullOrWhiteSpace(entry.ActionKeyOverride) ? BuildActionKey(tabName, entry.Label) : entry.ActionKeyOverride;
if (HasMenuBinding(actionKey)) {
// Rows like FPS Bypass and Open Debug Map can carry a native bind instead of
// an overlay one. GetVisibleTabs/BuildEntriesForTab only list rows the player
// can see, so FPS Bypass still hides without Motion Smoothing.
if (HasVisibleBinding(actionKey)) {
yield return new KeybindOverviewSpec(entry.Label, actionKey, entry.SearchTerms);
}
}
Expand Down
1 change: 1 addition & 0 deletions docs/feature-guide/player.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Rows with a triangle expose the controls listed below.
| Grab Mode | Hold | Vanilla grab behavior: hold the grab key to grab. | Normal clear |
| Grab Mode | Toggle | Press grab once to hold, then press again to release. | Normal clear |
| Grab Mode | Invert | Hold grab to release instead of to grab. | Normal clear |
| Grab Mode | Cycle | Step to the next grab mode. Right-click it to bind the grab-mode cycling hotkey. | Normal clear |
| Ground Refills | Dash refill | Allow ground contact to restore dash charges while Ground Refills is enabled. | Cheat |
| Ground Refills | Stamina refill | Allow ground contact to restore stamina while Ground Refills is enabled. | Cheat |
| Hazard Accuracy | Invalid limit | Optional invalid-contact warning threshold. Zero disables the warning. | Cheat |
Expand Down
2 changes: 2 additions & 0 deletions docs/getting-started/hotkeys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Actions marked `-` have no default binding on that input type. Open Menu starts

**Save State**, **Load State**, **Previous Slot**, and **Next Slot** drive Speedrun Tool's savestate slot from 1-9; the Keybinds tab shows the first two as **Speedrun Tool Capture State** and **Speedrun Tool Restore State**. **Set StartPos**, **Load StartPos**, **Clear StartPos**, and **Load StartPos Slot 1-9** control Akron's StartPos.

Previous/Next Slot, Timescale down/up, Frame Stepper step, Open Debug Map and Grab Mode cycling are bound from their overlay controls: SRT Slot, Timescale and Frame Stepper popups, the Open Debug Map row, and the Grab Mode popup's **Cycle** button. Toggle Frame Bypass is bound on the FPS Bypass row, and Cycle Frame Bypass Camera Smoothing on its popup's **Smooth Camera** button.

**Toggle Frame Bypass** and **Cycle Frame Bypass Camera Smoothing** work only when Motion Smoothing is loaded. Camera-smoothing cycling also requires frame bypass to be active.

## Configure a bind
Expand Down
29 changes: 29 additions & 0 deletions tests/module-settings-tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6847,6 +6847,35 @@ public void DefaultBindingSetterRejectsMenuOnlyActions()
Assert.False(InvokeTrySetDefaultButtonBinding(settings, "Global/Logging", AkronModuleSettings.CreateEmptyButtonBinding()));
}

// Binds with no other in-game editor since Everest's config screens left the mod
// options: their overlay control must resolve to the native binding the hotkey
// handlers read, so Bind and Clear edit it instead of adding a separate overlay bind.
// Checks instance identity only: CI's reference-only Celeste.dll cannot run
// ButtonBinding.Keys.
[Theory]
[InlineData("popup/SRT Slot/Previous", nameof(AkronModuleSettings.PreviousSlot))]
[InlineData("popup/SRT Slot/Next", nameof(AkronModuleSettings.NextSlot))]
[InlineData("popup/Timescale/Decrease", nameof(AkronModuleSettings.DecreaseTimescale))]
[InlineData("popup/Timescale/Increase", nameof(AkronModuleSettings.IncreaseTimescale))]
[InlineData("popup/Frame Stepper/Step Once", nameof(AkronModuleSettings.StepFrame))]
[InlineData("popup/Grab Mode/Cycle", nameof(AkronModuleSettings.CycleGrabMode))]
[InlineData("Global/FPS Bypass", nameof(AkronModuleSettings.ToggleFrameBypass))]
[InlineData("popup/FPS Bypass/Smooth Camera", nameof(AkronModuleSettings.CycleFrameBypassCameraSmoothing))]
[InlineData("Creator/Open Debug Map", nameof(AkronModuleSettings.OpenDebugMap))]
public void OverlayBindsEditTheNativeBindTheirHotkeyReads(string actionKey, string settingName)
{
AkronModuleSettings settings = new AkronModuleSettings();
AkronModuleSettings.EnsureCurrentKeybindDefaults(settings);
MethodInfo? resolve = typeof(AkronOverlay).GetMethod("ResolveDefaultButtonBinding", BindingFlags.NonPublic | BindingFlags.Static);
Assert.NotNull(resolve);

object? resolved = resolve!.Invoke(null, new object[] { settings, actionKey });

object? native = typeof(AkronModuleSettings).GetProperty(settingName)!.GetValue(settings);
Assert.NotNull(native);
Assert.Same(native, resolved);
}

private static List<string> BuildOverlayEntryLabels(string tab)
{
MethodInfo? method = typeof(AkronOverlay).GetMethod("BuildDisplayEntriesForTab", BindingFlags.NonPublic | BindingFlags.Static);
Expand Down
Loading