diff --git a/Directory.Build.props b/Directory.Build.props
index 4f6bc10..498ea91 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -8,7 +8,7 @@
true
- 0.3.4
+ 0.3.5
dev
All Of Us, XtraCube, Angxl
diff --git a/MiraAPI.Example/ExampleEventHandlers.cs b/MiraAPI.Example/ExampleEventHandlers.cs
index 94f90ed..20c0def 100644
--- a/MiraAPI.Example/ExampleEventHandlers.cs
+++ b/MiraAPI.Example/ExampleEventHandlers.cs
@@ -1,4 +1,5 @@
-using System.Linq;
+using System.Globalization;
+using System.Linq;
using MiraAPI.Events;
using MiraAPI.Events.Mira;
using MiraAPI.Events.Vanilla.Gameplay;
@@ -17,7 +18,7 @@ public static class ExampleEventHandlers
{
public static void Initialize()
{
- // You can register event handlers with the MiraEventManager class.
+ // You can register event handlers with the MiraEventManager class
var handle = MiraEventManager.RegisterEventHandler(@event =>
{
Logger.Info($"{@event.Source.Data.PlayerName} is about to kill {@event.Target.Data.PlayerName}");
@@ -37,6 +38,21 @@ public static class ExampleEventHandlers
MiraEventManager.UnregisterEventHandler(handle);
}
+ // If you want to check vanilla buttons, use something like this!
+ [RegisterEvent]
+ public static void VanillaButtonClickHandler(VanillaButtonClickEvent @event)
+ {
+ Logger.Info($"{@event.Button.buttonLabelText.text} is being used!");
+ if (@event.PlayerTarget != null)
+ {
+ Logger.Info($"{@event.PlayerTarget.Data.PlayerName} is being targeted!");
+ }
+ else if (@event.VentTarget != null)
+ {
+ Logger.Info($"Vent with id {@event.VentTarget.Id.ToString(CultureInfo.InvariantCulture)} is being targeted!");
+ }
+ }
+
// If you want to add extra votes to a player, do something like this.
[RegisterEvent]
public static void StartMeetingEvent(StartMeetingEvent _)
diff --git a/MiraAPI/Events/Vanilla/Gameplay/VanillaButtonCancelledEvent.cs b/MiraAPI/Events/Vanilla/Gameplay/VanillaButtonCancelledEvent.cs
new file mode 100644
index 0000000..4265a3a
--- /dev/null
+++ b/MiraAPI/Events/Vanilla/Gameplay/VanillaButtonCancelledEvent.cs
@@ -0,0 +1,44 @@
+using MiraAPI.Hud;
+
+namespace MiraAPI.Events.Vanilla.Gameplay;
+
+///
+/// Invoked when a Vanilla Button click is cancelled. Do not use for custom buttons.
+///
+/// The Vanilla Button type.
+public sealed class VanillaButtonCancelledEvent : MiraEvent where T : AbilityButton
+{
+ ///
+ /// Gets Vanilla Button whose click was cancelled.
+ ///
+ public T Button { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Mira Button whose click was cancelled.
+ public VanillaButtonCancelledEvent(T button)
+ {
+ Button = button;
+ }
+}
+
+///
+/// Invoked when a Vanilla Button click is cancelled. Do not use for custom buttons.
+///
+public sealed class VanillaButtonCancelledEvent : MiraEvent
+{
+ ///
+ /// Gets Vanilla Button whose click was cancelled.
+ ///
+ public AbilityButton Button { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Vanilla Button whose click was cancelled.
+ public VanillaButtonCancelledEvent(AbilityButton button)
+ {
+ Button = button;
+ }
+}
diff --git a/MiraAPI/Events/Vanilla/Gameplay/VanillaButtonClickEvent.cs b/MiraAPI/Events/Vanilla/Gameplay/VanillaButtonClickEvent.cs
new file mode 100644
index 0000000..3da499b
--- /dev/null
+++ b/MiraAPI/Events/Vanilla/Gameplay/VanillaButtonClickEvent.cs
@@ -0,0 +1,65 @@
+using MiraAPI.Hud;
+
+namespace MiraAPI.Events.Vanilla.Gameplay;
+
+///
+/// Button click event for Vanilla Buttons only. Do not use for custom buttons.
+///
+/// The Vanilla Button type.
+public sealed class VanillaButtonClickEvent : MiraCancelableEvent where T : AbilityButton
+{
+ ///
+ /// Gets Vanilla Button that was clicked.
+ ///
+ public T Button { get; }
+
+ ///
+ /// Gets the generic click event that is invoked before this button-specific event.
+ ///
+ public VanillaButtonClickEvent GenericClickEvent { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Mira Button that was clicked.
+ /// The generic click event invoked before button-specific events.
+ public VanillaButtonClickEvent(T button, VanillaButtonClickEvent genericClickEvent)
+ {
+ GenericClickEvent = genericClickEvent;
+ Button = button;
+ }
+}
+
+///
+/// Button click event for Vanilla Buttons only. Do not use for custom buttons.
+///
+public sealed class VanillaButtonClickEvent : MiraCancelableEvent
+{
+ ///
+ /// Gets Vanilla Button that was clicked.
+ ///
+ public AbilityButton Button { get; }
+
+ ///
+ /// Gets the target player, if any, of the Vanilla Button that was clicked.
+ ///
+ public PlayerControl? PlayerTarget { get; }
+
+ ///
+ /// Gets the target vent, if any, of the Vanilla Button that was clicked.
+ ///
+ public Vent? VentTarget { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Vanilla Button that was clicked.
+ /// The Player target, if any.
+ /// The Vent target, if any.
+ public VanillaButtonClickEvent(AbilityButton button, PlayerControl? playerTarget = null, Vent? ventTarget = null)
+ {
+ Button = button;
+ PlayerTarget = playerTarget;
+ VentTarget = ventTarget;
+ }
+}
diff --git a/MiraAPI/Keybinds/BaseKeybind.cs b/MiraAPI/Keybinds/BaseKeybind.cs
index e4e6ac8..525ffef 100644
--- a/MiraAPI/Keybinds/BaseKeybind.cs
+++ b/MiraAPI/Keybinds/BaseKeybind.cs
@@ -69,4 +69,4 @@ public class BaseKeybind
{
Handler -= action;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Keybinds/MiraKeybind.cs b/MiraAPI/Keybinds/MiraKeybind.cs
index 52d64a1..0ce47ea 100644
--- a/MiraAPI/Keybinds/MiraKeybind.cs
+++ b/MiraAPI/Keybinds/MiraKeybind.cs
@@ -9,7 +9,7 @@ namespace MiraAPI.Keybinds;
public class MiraKeybind : BaseKeybind
{
///
- /// Gets name of the keybind
+ /// Gets name of the keybind.
///
public string Name { get; }
diff --git a/MiraAPI/MiraApiSettings.cs b/MiraAPI/MiraApiSettings.cs
index 397caa6..0543cf9 100644
--- a/MiraAPI/MiraApiSettings.cs
+++ b/MiraAPI/MiraApiSettings.cs
@@ -1,12 +1,14 @@
using BepInEx.Configuration;
using MiraAPI.LocalSettings;
using MiraAPI.LocalSettings.Attributes;
+using MiraAPI.Patches;
+using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
namespace MiraAPI;
///
-/// Mira API Config File Handler
+/// Mira API Config File Handler.
///
public class MiraApiSettings(ConfigFile config) : LocalSettingsTab(config)
{
@@ -21,22 +23,67 @@ public class MiraApiSettings(ConfigFile config) : LocalSettingsTab(config)
HideIconOnHover = false,
};
+ ///
+ /// Gets or sets the value stored for scaling buttons properly.
+ ///
+ public static float OldButtonScaleFactor { get; set; }
+
+ ///
+ public override void Open()
+ {
+ base.Open();
+ OldButtonScaleFactor = ButtonUIFactorSlider.Value;
+ }
+
+ ///
+ public override void OnOptionChanged(ConfigEntryBase configEntry)
+ {
+ base.OnOptionChanged(configEntry);
+ if (configEntry == ButtonUIFactorSlider)
+ {
+ if (HudManager.InstanceExists)
+ {
+ HudManagerPatches.ResizeUI(1f / OldButtonScaleFactor);
+ HudManagerPatches.ResizeUI(ButtonUIFactorSlider.Value);
+ }
+ OldButtonScaleFactor = ButtonUIFactorSlider.Value;
+ }
+ }
+
///
/// Gets whether the modifiers hud should be on the left side of the screen (under roles/task tab). Recommended for streamers.
///
[LocalToggleSetting]
- public ConfigEntry ModifiersHudLeftSide { get; private set; } = config.Bind("Displays", "Show Modifiers HUD on Left Side", false);
+ public ConfigEntry ModifiersHudLeftSide { get; private set; } = config.Bind("Visuals/UI", "Show Modifiers HUD on Left Side", false);
///
/// Gets whether to show keybinds on buttons.
///
[LocalToggleSetting]
- public ConfigEntry ShowKeybinds { get; private set; } = config.Bind("Keybinds", "Show Keybinds on Buttons", true);
- // This would be placed in the keybinds menu, but it crashes for Epic Games users. - Atony
+ public ConfigEntry ShowKeybinds { get; private set; } = config.Bind("Visuals/UI", "Show Keybinds on Buttons", true);
+
+ ///
+ /// Gets the scale of the buttons.
+ ///
+ [LocalSliderSetting(min: 0.5f, max: 1.5f, suffixType: MiraNumberSuffixes.Multiplier, formatString: "0.00", displayValue: true)]
+ public ConfigEntry ButtonUIFactorSlider { get; private set; } =
+ config.Bind("Visuals/UI", "Button Scale Factor", 0.75f);
///
/// Gets whether to apply cosmetic changes to the TaskAdder.
///
[LocalToggleSetting]
public ConfigEntry PrettyTaskAdder { get; private set; } = config.Bind("Freeplay", "Pretty Task Laptop", true);
+
+ ///
+ /// Gets whether to show the red flash from sabotages.
+ ///
+ [LocalToggleSetting]
+ public ConfigEntry EnableSabotageFlashes { get; private set; } = config.Bind("Accessibility", "Enable Sabotage Flashes", true);
+
+ ///
+ /// Gets whether to enable the sabotage sound effects or not.
+ ///
+ [LocalToggleSetting]
+ public ConfigEntry EnableSabotageBlares { get; private set; } = config.Bind("Accessibility", "Enable Sabotage Blare", true);
}
diff --git a/MiraAPI/Patches/Accessibility/HudManagerFlashPatches.cs b/MiraAPI/Patches/Accessibility/HudManagerFlashPatches.cs
new file mode 100644
index 0000000..e3d3ab4
--- /dev/null
+++ b/MiraAPI/Patches/Accessibility/HudManagerFlashPatches.cs
@@ -0,0 +1,63 @@
+using System.Collections;
+using BepInEx.Unity.IL2CPP.Utils.Collections;
+using HarmonyLib;
+using MiraAPI.LocalSettings;
+using UnityEngine;
+
+namespace MiraAPI.Patches.Accessibility;
+[HarmonyPatch]
+public static class HudManagerFlashPatches
+{
+ [HarmonyPatch(typeof(HudManager), nameof(HudManager.StartReactorFlash))]
+ [HarmonyPrefix]
+ public static bool ReactorFlashPrefix(HudManager __instance)
+ {
+ if (__instance.ReactorFlash == null)
+ {
+ __instance.ReactorFlash = __instance.StartCoroutine(CoReactorFlash().WrapToIl2Cpp());
+ }
+
+ return false;
+ }
+ [HarmonyPatch(typeof(HudManager), nameof(HudManager.StartOxyFlash))]
+ [HarmonyPrefix]
+ public static bool OxygenFlashPrefix(HudManager __instance)
+ {
+ if (__instance.OxyFlash == null)
+ {
+ __instance.OxyFlash = __instance.StartCoroutine(CoReactorFlash().WrapToIl2Cpp());
+ }
+
+ return false;
+ }
+ public static IEnumerator CoReactorFlash()
+ {
+ if (!HudManager.InstanceExists)
+ {
+ yield break;
+ }
+ var hudManager = HudManager.Instance;
+ WaitForSeconds wait = new WaitForSeconds(1f);
+ bool light = false;
+
+ hudManager.FullScreen.color = new Color(1f, 0f, 0f, 0.37254903f);
+ while (true)
+ {
+ var settins = LocalSettingsTabSingleton.Instance;
+ hudManager.FullScreen.gameObject.SetActive(settins.EnableSabotageFlashes.Value && !hudManager.FullScreen.gameObject.activeSelf);
+ if (settins.EnableSabotageBlares.Value)
+ {
+ SoundManager.Instance.PlaySound(ShipStatus.Instance.SabotageSound, false, 1f, null);
+ }
+ if (hudManager.lightFlashHandle == null)
+ {
+ hudManager.lightFlashHandle = DestroyableSingleton.Instance.AllocateLight();
+ hudManager.lightFlashHandle.color = new Color(1f, 0f, 0f, 1f);
+ hudManager.lightFlashHandle.intensity = 1f;
+ }
+ light = !light;
+ hudManager.lightFlashHandle.color.SetAlpha(light ? 1f : 0f);
+ yield return wait;
+ }
+ }
+}
diff --git a/MiraAPI/Patches/Events/VanillaButtonPatches.cs b/MiraAPI/Patches/Events/VanillaButtonPatches.cs
new file mode 100644
index 0000000..278de09
--- /dev/null
+++ b/MiraAPI/Patches/Events/VanillaButtonPatches.cs
@@ -0,0 +1,75 @@
+using System.Linq;
+using AmongUs.GameOptions;
+using HarmonyLib;
+using MiraAPI.Events;
+using MiraAPI.Events.Vanilla.Gameplay;
+using MiraAPI.Events.Vanilla.Usables;
+
+namespace MiraAPI.Patches.Events;
+
+///
+/// Patches to invoke vent related MiraEvents.
+///
+[HarmonyPatch]
+public static class VanillaButtonPatches
+{
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(AbilityButton), nameof(AbilityButton.DoClick))]
+ public static bool DoClickPrefix(AbilityButton __instance)
+ {
+ // Invoke the generic button click event.
+ PlayerControl? playerTarget = null;
+ Vent? ventTarget = null;
+ var role = PlayerControl.LocalPlayer.Data.Role;
+ if (role.Role is RoleTypes.Tracker)
+ {
+ playerTarget = role.Cast().currentTarget;
+ }
+ else if (role.Role is RoleTypes.GuardianAngel)
+ {
+ playerTarget = role.Cast().currentTarget;
+ }
+ else if (role.Role is RoleTypes.Engineer)
+ {
+ ventTarget = role.Cast().currentTarget;
+ }
+ var genericEvent = new VanillaButtonClickEvent(__instance, playerTarget, ventTarget);
+ MiraEventManager.InvokeEvent(genericEvent);
+ if (genericEvent.IsCancelled)
+ {
+ MiraEventManager.InvokeEvent(new VanillaButtonCancelledEvent(__instance));
+ }
+
+ if (!genericEvent.IsCancelled)
+ {
+ return true;
+ }
+
+ return false;
+ }
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(SecondaryAbilityButton), nameof(SecondaryAbilityButton.DoClick))]
+ public static bool SecondaryDoClickPrefix(AbilityButton __instance)
+ {
+ // Invoke the generic button click event.
+ PlayerControl? playerTarget = null;
+ var role = PlayerControl.LocalPlayer.Data.Role;
+ if (role.Role is RoleTypes.Detective)
+ {
+ playerTarget = role.Cast().currentTarget;
+ }
+ var genericEvent = new VanillaButtonClickEvent(__instance, playerTarget);
+ MiraEventManager.InvokeEvent(genericEvent);
+ if (genericEvent.IsCancelled)
+ {
+ MiraEventManager.InvokeEvent(new VanillaButtonCancelledEvent(__instance));
+ }
+
+ if (!genericEvent.IsCancelled)
+ {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs
index e95b72c..c5340b2 100644
--- a/MiraAPI/Patches/HudManagerPatches.cs
+++ b/MiraAPI/Patches/HudManagerPatches.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System.Collections;
+using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using MiraAPI.Hud;
@@ -29,6 +30,84 @@ public static class HudManagerPatches
internal static List ModdedKeybindIcons = new();
+ public static IEnumerator CoResizeUI()
+ {
+ while (!HudManager.Instance)
+ {
+ yield return null;
+ }
+
+ yield return new WaitForSeconds(0.01f);
+ ResizeUI(LocalSettingsTabSingleton.Instance.ButtonUIFactorSlider.Value);
+ }
+
+ public static void ResizeUI(float scaleFactor)
+ {
+ var baseButtons = HudManager.Instance.transform.FindChild("Buttons");
+ if (baseButtons != null)
+ {
+ foreach (var aspect in baseButtons.GetComponentsInChildren(true))
+ {
+ if (aspect.gameObject == null)
+ {
+ continue;
+ }
+
+ if (aspect.gameObject.transform.parent.name == "TopRight")
+ {
+ continue;
+ }
+
+ if (aspect.gameObject.transform.parent.transform.parent.name == "TopRight")
+ {
+ continue;
+ }
+
+ aspect.gameObject.SetActive(!aspect.isActiveAndEnabled);
+ aspect.DistanceFromEdge *= new Vector2(scaleFactor, scaleFactor);
+ aspect.gameObject.SetActive(!aspect.isActiveAndEnabled);
+ }
+ }
+
+ foreach (var button in HudManager.Instance.GetComponentsInChildren(true))
+ {
+ if (button.gameObject == null)
+ {
+ continue;
+ }
+
+ button.gameObject.SetActive(!button.isActiveAndEnabled);
+ button.gameObject.transform.localScale *= scaleFactor;
+ button.gameObject.SetActive(!button.isActiveAndEnabled);
+ }
+
+ if (baseButtons != null)
+ {
+ foreach (var arrange in baseButtons.GetComponentsInChildren(true))
+ {
+ if (!arrange.gameObject || !arrange.transform)
+ {
+ continue;
+ }
+
+ arrange.gameObject.SetActive(!arrange.isActiveAndEnabled);
+ arrange.CellSize = new Vector2(scaleFactor, scaleFactor);
+ arrange.gameObject.SetActive(!arrange.isActiveAndEnabled);
+ if (arrange.isActiveAndEnabled && arrange.gameObject.transform.childCount != 0)
+ {
+ try
+ {
+ arrange.ArrangeChilds();
+ }
+ catch
+ {
+ // Error($"Error arranging child objects in GridArrange: {e}");
+ }
+ }
+ }
+ }
+ }
+
/*
///
/// Trigger hudstart on current custom gamemode
@@ -149,6 +228,7 @@ public static class HudManagerPatches
var comp = buttonObj.GetComponent();
KeybindManager.VanillaKeybinds[comp.GetType()].Button = comp;
}
+ Coroutines.Start(CoResizeUI());
}
///
diff --git a/MiraAPI/Patches/Roles/LogicRoleSelectionHnsPatch.cs b/MiraAPI/Patches/Roles/LogicRoleSelectionHnsPatch.cs
index 4a9547b..c3ed277 100644
--- a/MiraAPI/Patches/Roles/LogicRoleSelectionHnsPatch.cs
+++ b/MiraAPI/Patches/Roles/LogicRoleSelectionHnsPatch.cs
@@ -39,7 +39,7 @@ public static class LogicRoleSelectionHnsPatch
foreach (RoleManager.RoleAssignmentData roleAssignmentData in guaranteedRoles.Select((x) =>
new RoleManager.RoleAssignmentData(x, roleOptions.GetNumPerGame(x.Role), 100)))
{
- for (;;)
+ while (true)
{
RoleManager.RoleAssignmentData roleAssignmentData2 = roleAssignmentData;
int count = roleAssignmentData2.Count;
@@ -122,7 +122,7 @@ public static class LogicRoleSelectionHnsPatch
foreach (RoleManager.RoleAssignmentData roleAssignmentData in guaranteedRoles.Select((x) =>
new RoleManager.RoleAssignmentData(x, roleOptions.GetNumPerGame(x.Role), 100)))
{
- for (;;)
+ while (true)
{
RoleManager.RoleAssignmentData roleAssignmentData2 = roleAssignmentData;
int count = roleAssignmentData2.Count;
diff --git a/MiraAPI/Patches/Roles/LogicRoleSelectionNormalPatch.cs b/MiraAPI/Patches/Roles/LogicRoleSelectionNormalPatch.cs
index 0d00008..b0540bb 100644
--- a/MiraAPI/Patches/Roles/LogicRoleSelectionNormalPatch.cs
+++ b/MiraAPI/Patches/Roles/LogicRoleSelectionNormalPatch.cs
@@ -36,7 +36,7 @@ public static class LogicRoleSelectionNormalPatch
foreach (RoleManager.RoleAssignmentData roleAssignmentData in guaranteedRoles.Select((x) =>
new RoleManager.RoleAssignmentData(x, roleOptions.GetNumPerGame(x.Role), 100)))
{
- for (;;)
+ while (true)
{
RoleManager.RoleAssignmentData roleAssignmentData2 = roleAssignmentData;
int count = roleAssignmentData2.Count;