diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs
index cdef7cc..50e248b 100644
--- a/MiraAPI/Patches/HudManagerPatches.cs
+++ b/MiraAPI/Patches/HudManagerPatches.cs
@@ -1,5 +1,6 @@
using HarmonyLib;
using MiraAPI.Hud;
+using MiraAPI.Roles;
using Reactor.Utilities.Extensions;
using UnityEngine;
using Object = UnityEngine.Object;
diff --git a/MiraAPI/Patches/Roles/HudManagerPatches.cs b/MiraAPI/Patches/Roles/HudManagerPatches.cs
index 34f0bb9..f833651 100644
--- a/MiraAPI/Patches/Roles/HudManagerPatches.cs
+++ b/MiraAPI/Patches/Roles/HudManagerPatches.cs
@@ -27,10 +27,11 @@ public static void SetHudActivePostfix(
{
var flag = localPlayer.Data != null && localPlayer.Data.IsDead;
- if (role is ICustomRole)
+ if (role is ICustomRole customRole)
{
__instance.KillButton.ToggleVisible(isActive && role.CanUseKillButton && !flag);
__instance.ImpostorVentButton.ToggleVisible(isActive && role.CanVent && !flag);
+ __instance.SabotageButton.gameObject.SetActive(isActive && customRole.CanUseSabotage);
}
if (_roleTab)
diff --git a/MiraAPI/Patches/Roles/SabotageButtonPatch.cs b/MiraAPI/Patches/Roles/SabotageButtonPatch.cs
new file mode 100644
index 0000000..49c5190
--- /dev/null
+++ b/MiraAPI/Patches/Roles/SabotageButtonPatch.cs
@@ -0,0 +1,62 @@
+using HarmonyLib;
+using MiraAPI.Roles;
+
+namespace MiraAPI.Patches.Roles;
+
+[HarmonyPatch(typeof(SabotageButton))]
+public class SabotageButtonPatch
+{
+ ///
+ /// Patches the Sabotage button to check if the player's custom role can use sabotage.
+ ///
+ [HarmonyPatch(nameof(SabotageButton.DoClick))]
+ [HarmonyPrefix]
+ public static bool DoClickPrefix(SabotageButton __instance)
+ {
+ var player = PlayerControl.LocalPlayer;
+
+ if (player.Data.Role is not ICustomRole customRole)
+ {
+ return true;
+ }
+
+ if (!customRole.CanUseSabotage || PlayerControl.LocalPlayer.inVent || !GameManager.Instance.SabotagesEnabled())
+ {
+ return false;
+ }
+
+ DestroyableSingleton.Instance.ToggleMapVisible(
+ new MapOptions
+ {
+ Mode = MapOptions.Modes.Sabotage,
+ });
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(SabotageButton.Refresh))]
+ public static bool RefreshPrefix(SabotageButton __instance)
+ {
+ var player = PlayerControl.LocalPlayer;
+ if (GameManager.Instance == null || player == null)
+ {
+ __instance.ToggleVisible(false);
+ __instance.SetDisabled();
+ return false;
+ }
+
+ if (player.Data.Role is not ICustomRole customRole)
+ {
+ return true;
+ }
+
+ if (player.inVent || !GameManager.Instance.SabotagesEnabled() || player.petting)
+ {
+ __instance.ToggleVisible(customRole.CanUseSabotage && GameManager.Instance.SabotagesEnabled());
+ __instance.SetDisabled();
+ return false;
+ }
+ __instance.SetEnabled();
+ return false;
+ }
+}
diff --git a/MiraAPI/Roles/ICustomRole.cs b/MiraAPI/Roles/ICustomRole.cs
index 3087dbe..9fc2b61 100644
--- a/MiraAPI/Roles/ICustomRole.cs
+++ b/MiraAPI/Roles/ICustomRole.cs
@@ -77,6 +77,11 @@ public interface ICustomRole
///
bool CanUseVent => Team == ModdedRoleTeams.Impostor;
+ ///
+ /// Gets a value indicating whether the role can use the sabotage button.
+ ///
+ bool CanUseSabotage => Team == ModdedRoleTeams.Impostor;
+
///
/// Gets a value indicating whether the role's tasks count towards task progress.
///