diff --git a/NewMod/Buttons/Overload/OverloadButton.cs b/NewMod/Buttons/Overload/OverloadButton.cs
index c2352ce..87cba08 100644
--- a/NewMod/Buttons/Overload/OverloadButton.cs
+++ b/NewMod/Buttons/Overload/OverloadButton.cs
@@ -82,7 +82,7 @@ public class OverloadButton : CustomActionButton
///
/// The icon displayed on the button.
///
- public override LoadableAsset Sprite => absorbedSprite;
+ public override LoadableAsset Sprite => MiraAssets.Empty;
///
/// Copies functionality and appearance from another role's button.
diff --git a/NewMod/CustomRPC.cs b/NewMod/CustomRPC.cs
index 88d1919..c340bf9 100644
--- a/NewMod/CustomRPC.cs
+++ b/NewMod/CustomRPC.cs
@@ -15,6 +15,7 @@ public enum CustomRPC
WitnessTrap,
NotifyChampion,
SummonNPC,
+ RequestSummon,
BeaconPulse,
DeployZone
}
\ No newline at end of file
diff --git a/NewMod/ModCompatibility.cs b/NewMod/ModCompatibility.cs
index 0a037e5..ecfb158 100644
--- a/NewMod/ModCompatibility.cs
+++ b/NewMod/ModCompatibility.cs
@@ -52,18 +52,5 @@ public static void DisableRole(string roleName, string pluginGuid)
}
}
}
- public static bool IsRoleActive(string roleName)
- {
- foreach (var roles in RoleManager.Instance.AllRoles)
- {
- CustomRoleManager.GetCustomRoleBehaviour(roles.Role, out var customRole);
-
- if (customRole != null && customRole.RoleName.Equals(roleName, StringComparison.OrdinalIgnoreCase))
- {
- return customRole.GetChance() > 0 && customRole.GetCount() > 0;
- }
- }
- return false;
- }
}
}
diff --git a/NewMod/Modifiers/StickyModifier.cs b/NewMod/Modifiers/StickyModifier.cs
index ab721ff..1d0382d 100644
--- a/NewMod/Modifiers/StickyModifier.cs
+++ b/NewMod/Modifiers/StickyModifier.cs
@@ -1,6 +1,9 @@
using System.Collections;
using System.Collections.Generic;
+using MiraAPI.Events;
+using MiraAPI.Events.Vanilla.Gameplay;
using MiraAPI.GameOptions;
+using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types;
using NewMod.Options;
using NewMod.Options.Modifiers;
@@ -15,6 +18,7 @@ public class StickyModifier : GameModifier
public override bool HideOnUi => false;
public override bool ShowInFreeplay => true;
public static List linkedPlayers = [];
+ public static bool _IsActive = false;
public override int GetAmountPerGame()
{
return (int)OptionGroupSingleton.Instance.StickyAmount;
@@ -29,8 +33,8 @@ public override int GetAssignmentChance()
}
public override string GetDescription()
{
- float distance = OptionGroupSingleton.Instance.StickyDistance.Value;
- float duration = OptionGroupSingleton.Instance.StickyDuration.Value;
+ float distance = (int)OptionGroupSingleton.Instance.StickyDistance;
+ float duration = (int)OptionGroupSingleton.Instance.StickyDuration;
return $"{ModifierName}: Pulls nearby players within {distance} units for {duration} seconds.";
}
@@ -38,53 +42,65 @@ public override void FixedUpdate()
{
base.FixedUpdate();
- if (!Player.CanMove) return;
+ if (_IsActive) return;
+
+ if (!Player.CanMove || Player.Data.IsDead) return;
foreach (var player in PlayerControl.AllPlayerControls)
{
- if (player == Player || linkedPlayers.Contains(player)) continue;
+ if (player == Player) continue;
- float distance = OptionGroupSingleton.Instance.StickyDistance.Value;
+ float distance = (int)OptionGroupSingleton.Instance.StickyDistance;
if (Vector2.Distance(player.GetTruePosition(), Player.GetTruePosition()) < distance)
{
+ _IsActive = true;
linkedPlayers.Add(player);
Coroutines.Start(CoFollowStickyPlayer(player));
+ break;
}
}
}
public IEnumerator CoFollowStickyPlayer(PlayerControl player)
{
- var info = new StickyState
+ float duration = (int)OptionGroupSingleton.Instance.StickyDuration;
+ float timer = 0f;
+ float pullStrength = (int)OptionGroupSingleton.Instance.PullStrength;
+ float stopDistance = 1f;
+
+ while (timer < duration)
{
- StickyOwner = Player,
- LinkedPlayer = player,
- velocity = Vector3.zero,
- };
+ if (player.Data.IsDead || player.Data.Disconnected) break;
- yield return HudManager.Instance.StartCoroutine(
- Effects.Overlerp(0.5f, new System.Action((t) =>
- {
- Vector3 targetPos = info.LinkedPlayer.transform.position;
- Vector3 currentPos = info.StickyOwner.transform.position;
+ timer += Time.deltaTime;
- info.LinkedPlayer.transform.position = Vector3.SmoothDamp(
- targetPos,
- currentPos,
- ref info.velocity,
- t
- );
- })
- ));
+ var ownerPos = Player.transform.position;
+ var targetPos = player.transform.position;
+ float distance = Vector3.Distance(ownerPos, targetPos);
+
+ if (distance > stopDistance)
+ {
+ Vector3 direction = (ownerPos - targetPos).normalized;
+ Vector3 leashPoint = ownerPos - (direction * stopDistance);
+
+ player.transform.position = Vector3.Lerp(targetPos, leashPoint, Time.deltaTime * pullStrength);
+ }
+ yield return null;
+ }
linkedPlayers.Remove(player);
- }
- }
- class StickyState
- {
- public PlayerControl StickyOwner;
- public PlayerControl LinkedPlayer;
- public Vector3 velocity;
+ _IsActive = true;
+
+ if (Player.AmOwner)
+ {
+ PlayerControl.LocalPlayer.RpcRemoveModifier();
+ }
+ }
+ [RegisterEvent]
+ public static void OnRoundStart(RoundStartEvent evt)
+ {
+ linkedPlayers.Clear();
+ }
}
}
diff --git a/NewMod/NewMod.cs b/NewMod/NewMod.cs
index 3aeaacf..4822c30 100644
--- a/NewMod/NewMod.cs
+++ b/NewMod/NewMod.cs
@@ -47,7 +47,7 @@ public override void Load()
{
Instance = this;
AddComponent();
- ReactorCredits.Register(ReactorCredits.AlwaysShow);
+ ReactorCredits.Register("NewMod", "v1.2.9 Hotfix 1", true, ReactorCredits.AlwaysShow);
Harmony.PatchAll();
NewModEventHandler.RegisterEventsLogs();
diff --git a/NewMod/Options/Modifiers/StickyModifierOptions.cs b/NewMod/Options/Modifiers/StickyModifierOptions.cs
index 3654ec5..e997cbb 100644
--- a/NewMod/Options/Modifiers/StickyModifierOptions.cs
+++ b/NewMod/Options/Modifiers/StickyModifierOptions.cs
@@ -26,5 +26,14 @@ public class StickyModifierOptions : AbstractOptionGroup
increment: 0.5f,
suffixType: MiraNumberSuffixes.None
);
+ public ModdedNumberOption PullStrength { get; } =
+ new(
+ "Pull Strength",
+ 1f,
+ min: 1f,
+ max: 5f,
+ increment: 1f,
+ suffixType: MiraNumberSuffixes.None
+ );
}
}
diff --git a/NewMod/Options/ModifiersOptions.cs b/NewMod/Options/ModifiersOptions.cs
index 6bccf5a..02aa181 100644
--- a/NewMod/Options/ModifiersOptions.cs
+++ b/NewMod/Options/ModifiersOptions.cs
@@ -12,24 +12,24 @@ public class ModifiersOptions : AbstractOptionGroup
public override Color GroupColor => Color.blue;
public override bool ShowInModifiersMenu => true;
- [ModdedNumberOption("Sticky Amount", min:0f, max:6)]
- public float StickyAmount { get; set; } = 10f;
+ [ModdedNumberOption("Sticky Amount", min:0f, max:2f)]
+ public float StickyAmount { get; set; } = 1f;
public ModdedNumberOption StickyChance { get; } = new("Sticky Chance", 50f, 0, 100f, 10f, MiraNumberSuffixes.Percent)
{
Visible = () => OptionGroupSingleton.Instance.StickyAmount > 0
};
- [ModdedNumberOption("Drowsy Amount", min:0f, max:6f)]
- public float DrowsyAmount { get; set; } = 10f;
+ [ModdedNumberOption("Drowsy Amount", min:0f, max:2f)]
+ public float DrowsyAmount { get; set; } = 1f;
public ModdedNumberOption DrowsyChance { get; } =new("Drowsy Chance", 50f, 0, 100f, 10f, MiraNumberSuffixes.Percent)
{
Visible = () => OptionGroupSingleton.Instance.DrowsyAmount > 0f
};
- [ModdedNumberOption("Adrenaline Amount", min:0f, max:6f)]
- public float AdrenalineAmount { get; set; } = 10f;
+ [ModdedNumberOption("Adrenaline Amount", min:0f, max:2f)]
+ public float AdrenalineAmount { get; set; } = 1f;
public ModdedNumberOption AdrenalineChance { get; } =new("Adrenaline Chance", 50f, 0, 100f, 10f, MiraNumberSuffixes.Percent)
{
diff --git a/NewMod/Patches/ChatPatch.cs b/NewMod/Patches/ChatPatch.cs
new file mode 100644
index 0000000..b6c88ef
--- /dev/null
+++ b/NewMod/Patches/ChatPatch.cs
@@ -0,0 +1,43 @@
+using AmongUs.Data;
+using HarmonyLib;
+using InnerNet;
+
+namespace NewMod.Patches
+{
+ [HarmonyPatch(typeof(ChatController), nameof(ChatController.SendChat))]
+ public static class ChatPatch
+ {
+ public static bool Prefix(ChatController __instance)
+ {
+ __instance.timeSinceLastMessage = 0f;
+
+ if (__instance.quickChatMenu.CanSend)
+ {
+ __instance.SendQuickChat();
+ }
+ else
+ {
+ if (__instance.quickChatMenu.IsOpen || string.IsNullOrWhiteSpace(__instance.freeChatField.Text) || DataManager.Settings.Multiplayer.ChatMode != QuickChatModes.FreeChatOrQuickChat)
+ {
+ return false;
+ }
+ __instance.SendFreeChat();
+ }
+
+ __instance.timeSinceLastMessage = 0f;
+ __instance.freeChatField.Clear();
+ __instance.quickChatMenu.Clear();
+ __instance.quickChatField.Clear();
+ __instance.UpdateChatMode();
+
+ return false;
+ }
+ [HarmonyPatch(typeof(TextBoxTMP), nameof(TextBoxTMP.Start))]
+ [HarmonyPostfix]
+ public static void StartPostfix(TextBoxTMP __instance)
+ {
+ __instance.AllowSymbols = true;
+ __instance.allowAllCharacters = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/NewMod/Patches/Compatibility/StartGamePatch.cs b/NewMod/Patches/Compatibility/StartGamePatch.cs
index e5fce8c..6392857 100644
--- a/NewMod/Patches/Compatibility/StartGamePatch.cs
+++ b/NewMod/Patches/Compatibility/StartGamePatch.cs
@@ -1,6 +1,7 @@
using HarmonyLib;
using MiraAPI.GameOptions;
using NewMod.Options;
+using NewMod.Utilities;
namespace NewMod.Patches.Compatibility
{
@@ -15,8 +16,8 @@ public static bool Prefix(AmongUsClient __instance)
if (!settings.AllowRevenantHitmanCombo)
{
- var hitman = ModCompatibility.IsRoleActive("Hitman");
- var revenant = ModCompatibility.IsRoleActive("Revenant");
+ var hitman = Utils.IsRoleActive("Hitman");
+ var revenant = Utils.IsRoleActive("Revenant");
if (hitman && revenant)
{
diff --git a/NewMod/Patches/RolePatch.cs b/NewMod/Patches/RolePatch.cs
index 64f4099..94c010f 100644
--- a/NewMod/Patches/RolePatch.cs
+++ b/NewMod/Patches/RolePatch.cs
@@ -1,54 +1,65 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using HarmonyLib;
+using Hazel;
using MiraAPI.GameOptions;
using MiraAPI.Roles;
using MiraAPI.Utilities;
-using NewMod;
using NewMod.Options;
using NewMod.Roles;
using Reactor.Utilities;
using UnityEngine;
-using Hazel;
namespace NewMod.Patches
{
[HarmonyPatch(typeof(RoleManager), nameof(RoleManager.SelectRoles))]
public static class SelectRolePatch
{
- public static bool Prefix(RoleManager __instance)
+ [HarmonyPostfix]
+ [HarmonyPriority(Priority.Last)]
+ public static void Postfix(RoleManager __instance)
{
- if (!AmongUsClient.Instance.AmHost)
- return true;
+ if (!AmongUsClient.Instance.AmHost) return;
+ if (GameManager.Instance.IsHideAndSeek()) return;
+
+ Coroutines.Start(CoAdjustNeutrals());
+ }
- Logger.Instance.LogMessage("-------------- SELECT ROLES: START --------------");
- Logger.Instance.LogMessage($"Running as host (clientId={AmongUsClient.Instance.ClientId})");
+ private static IEnumerator CoAdjustNeutrals()
+ {
+ yield return null;
+ yield return new WaitForSeconds(0.05f);
var opts = OptionGroupSingleton.Instance;
int target = Mathf.RoundToInt(opts.TotalNeutrals);
- Logger.Instance.LogMessage($"Settings -> TotalNeutrals={opts.TotalNeutrals} → target={target}, KeepCrewMajority={opts.KeepCrewMajority}, PreferVariety={opts.PreferVariety}");
- var allPlayers = GameData.Instance.AllPlayers.ToArray()
- .Where(p => p?.Object && !p.IsDead && !p.Disconnected)
+ var allInfos = GameData.Instance.AllPlayers.ToArray()
+ .Where(p => p != null && p.Object != null && !p.Disconnected)
.ToList();
- Logger.Instance.LogMessage($"Eligible players: {allPlayers.Count}");
+ var allPlayers = allInfos.Select(p => p.Object).ToList();
+
+ Logger.Instance.LogMessage("-------------- NEUTRAL ADJUST: START --------------");
+ Logger.Instance.LogMessage($"Players={allPlayers.Count}, TotalNeutrals={opts.TotalNeutrals} target={target}, KeepCrewMajority={opts.KeepCrewMajority}, PreferVariety={opts.PreferVariety}");
var neutrals = allPlayers
- .Where(p => p?.Object?.Data?.Role is ICustomRole cr && cr is INewModRole nm &&
- (nm.Faction == NewModFaction.Apex || nm.Faction == NewModFaction.Entropy))
- .Select(p => p.Object)
+ .Where(pc =>
+ {
+ var rb = pc.Data?.Role;
+ if (rb is ICustomRole cr && cr is INewModRole nm)
+ return nm.Faction == NewModFaction.Apex || nm.Faction == NewModFaction.Entropy;
+ return false;
+ })
.ToList();
- Logger.Instance.LogMessage($"Currently neutral (Apex/Entropy): {neutrals.Count}");
-
if (opts.KeepCrewMajority)
{
- int crewCount = allPlayers.Count(p =>
+ int crewCount = allPlayers.Count(pc =>
{
- var rb = p?.Object?.Data?.Role;
+ var rb = pc.Data?.Role;
if (rb == null) return false;
return rb is CrewmateRole || (!rb.IsImpostor && rb.TeamType == RoleTeamTypes.Crewmate);
});
@@ -60,41 +71,43 @@ public static bool Prefix(RoleManager __instance)
}
int have = neutrals.Count;
+ Logger.Instance.LogMessage($"Currently neutrals={have}");
+
if (have == target)
{
- Logger.Instance.LogMessage("No change needed; exiting cleanly.");
- Logger.Instance.LogMessage("-------------- SELECT ROLES: END (no-op) --------------");
- return false;
+ Logger.Instance.LogMessage("No change needed.");
+ Logger.Instance.LogMessage("-------------- NEUTRAL ADJUST: END (no-op) --------------");
+ yield break;
}
if (have > target)
{
int remove = have - target;
- Logger.Instance.LogMessage($"Too many neutrals; demoting {remove}");
- neutrals.Shuffle();
+ Logger.Instance.LogMessage($"Too many neutrals, demoting {remove}");
+ neutrals.Shuffle();
for (int i = 0; i < remove && i < neutrals.Count; i++)
{
- var ply = neutrals[i];
- if (ply == null) continue;
+ var pc = neutrals[i];
+ if (pc == null) continue;
- Logger.Instance.LogMessage($"→ Demoting {ply.Data.PlayerName} to Crewmate");
- ply.RpcSetRole(RoleTypes.Crewmate);
+ Logger.Instance.LogMessage($"→ Demoting {pc.Data.PlayerName} to Crewmate");
+ pc.RpcSetRole(RoleTypes.Crewmate, true);
}
- Logger.Instance.LogMessage("Demotion complete.");
- Logger.Instance.LogMessage("-------------- SELECT ROLES: END (demotions) --------------");
- return false;
+ Logger.Instance.LogMessage("-------------- NEUTRAL ADJUST: END (demotions) --------------");
+ yield break;
}
int need = target - have;
Logger.Instance.LogMessage($"Need to assign {need} more neutrals.");
var crewElig = allPlayers
- .Where(p =>
+ .Where(pc =>
{
- var rb = p?.Object?.Data?.Role;
+ var rb = pc.Data?.Role;
if (rb == null) return false;
+
bool isCrew = rb is CrewmateRole || (!rb.IsImpostor && rb.TeamType == RoleTeamTypes.Crewmate);
if (!isCrew) return false;
@@ -103,16 +116,14 @@ public static bool Prefix(RoleManager __instance)
return true;
})
- .Select(p => p.Object)
.ToList();
Logger.Instance.LogMessage($"Crew eligible for neutral conversion: {crewElig.Count}");
-
if (crewElig.Count == 0)
{
- Logger.Instance.LogMessage("No eligible crew found; aborting neutral assignment.");
- Logger.Instance.LogMessage("-------------- SELECT ROLES: END (no candidates) --------------");
- return false;
+ Logger.Instance.LogMessage("No eligible crew found, aborting.");
+ Logger.Instance.LogMessage("-------------- NEUTRAL ADJUST: END (no candidates) --------------");
+ yield break;
}
var active = CustomRoleUtils.GetActiveRoles().ToList();
@@ -141,14 +152,15 @@ public static bool Prefix(RoleManager __instance)
}
Logger.Instance.LogMessage($"Built neutral candidate list: {candidates.Count}");
-
if (candidates.Count == 0)
{
- Logger.Instance.LogMessage("No candidates available; exiting.");
- return false;
+ Logger.Instance.LogMessage("No candidates available, exiting.");
+ Logger.Instance.LogMessage("-------------- NEUTRAL ADJUST: END --------------");
+ yield break;
}
var picks = new List();
+
if (opts.PreferVariety)
{
var ordered = candidates.OrderByDescending(x => x.Weight).ToList();
@@ -171,16 +183,12 @@ public static bool Prefix(RoleManager __instance)
float total = available.Sum(c => c.Weight);
float rnum = UnityEngine.Random.Range(0f, total);
float acc = 0f;
- var chosen = available.First();
+ var chosen = available[0];
foreach (var c in available)
{
acc += c.Weight;
- if (rnum <= acc)
- {
- chosen = c;
- break;
- }
+ if (rnum <= acc) { chosen = c; break; }
}
picks.Add(chosen.Role);
@@ -199,19 +207,19 @@ public static bool Prefix(RoleManager __instance)
foreach (var role in picks)
{
if (crewElig.Count == 0) break;
+
int idx = HashRandom.FastNext(crewElig.Count);
var pc = crewElig[idx];
crewElig.RemoveAt(idx);
var rt = (RoleTypes)RoleId.Get(role.GetType());
- Logger.Instance.LogMessage($"Assigning {role.GetType().Name} → {pc.Data.PlayerName}");
- pc.RpcSetRole(rt);
+ pc.RpcSetRole(rt, true);
}
Logger.Instance.LogMessage("Neutral assignment complete.");
- Logger.Instance.LogMessage("-------------- SELECT ROLES: END --------------");
- return false;
+ Logger.Instance.LogMessage("-------------- NEUTRAL ADJUST: END --------------");
}
+
public struct Candidate
{
public ICustomRole Role;
@@ -220,23 +228,17 @@ public struct Candidate
public RoleTypes RoleType;
}
}
-
- // Inspired by https://github.com/AU-Avengers/TOU-Mira/blob/main/TownOfUs/Patches/RoleManagerPatches.cs#L747C3-L768C1
- [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RpcSetRole))]
- public static class RpcSetRolePatch
+ // Thanks to:https://github.com/AU-Avengers/TOU-Mira/blob/main/TownOfUs/Patches/RoleManagerPatches.cs#L1070
+ [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CoSetRole))]
+ public static class CoSetRoleOverridePatch
{
- public static bool Prefix(PlayerControl __instance, [HarmonyArgument(0)] RoleTypes roleType, [HarmonyArgument(1)] bool canOverrideRole = false)
+ [HarmonyPrefix]
+ public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)] RoleTypes role, [HarmonyArgument(1)] bool canOverrideRole)
{
- if (AmongUsClient.Instance.AmClient)
- __instance.StartCoroutine(__instance.CoSetRole(roleType, canOverrideRole));
-
- var writer = AmongUsClient.Instance.StartRpcImmediately(__instance.NetId, (byte)RpcCalls.SetRole, SendOption.Reliable);
- writer.Write((ushort)roleType);
- writer.Write(canOverrideRole);
- AmongUsClient.Instance.FinishRpcImmediately(writer);
-
- Logger.Instance.LogMessage($"RpcSetRole: {__instance.Data.PlayerName} ({roleType})");
- return false;
+ if (canOverrideRole)
+ {
+ __instance.roleAssigned = false;
+ }
}
}
}
diff --git a/NewMod/Patches/Roles/MeetingHudPatch.cs b/NewMod/Patches/Roles/MeetingHudPatch.cs
index ad05f64..479f17d 100644
--- a/NewMod/Patches/Roles/MeetingHudPatch.cs
+++ b/NewMod/Patches/Roles/MeetingHudPatch.cs
@@ -1,17 +1,9 @@
-using System;
-using UnityEngine;
-using Object = UnityEngine.Object;
-using UnityEngine.Events;
using System.Collections.Generic;
using HarmonyLib;
using NewMod.Utilities;
-using MiraAPI.Roles;
-using MiraAPI.Hud;
-using Reactor.Utilities;
using System.Linq;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using AmongUs.GameOptions;
-using NewMod.Roles.NeutralRoles;
namespace NewMod.Patches.Roles
{
@@ -30,6 +22,8 @@ public static class MeetingHud_CoIntro_Patch
{
public static bool Prefix(ref Il2CppReferenceArray deadBodies)
{
+ if (!Utils.IsRoleActive("Prankster")) return true;
+
List pranksterBodies = PranksterUtilities.FindAllPranksterBodies();
deadBodies = new Il2CppReferenceArray(
deadBodies
@@ -44,6 +38,8 @@ public static class MeetingHud_PopulateButtons_Patch
{
public static bool Prefix(MeetingHud __instance, byte reporter)
{
+ if (!Utils.IsRoleActive("Prankster")) return true;
+
var fakeBodies = PranksterUtilities.FindAllPranksterBodies();
var realPlayers = GameData.Instance.AllPlayers
.ToArray()
diff --git a/NewMod/Patches/Roles/Visionary/VisionaryPatches.cs b/NewMod/Patches/Roles/Visionary/VisionaryPatches.cs
index d96d924..de4be38 100644
--- a/NewMod/Patches/Roles/Visionary/VisionaryPatches.cs
+++ b/NewMod/Patches/Roles/Visionary/VisionaryPatches.cs
@@ -13,6 +13,8 @@ public static class VisionaryVentPatch
[RegisterEvent]
public static void OnEnterVent(EnterVentEvent evt)
{
+ if (!Utils.IsRoleActive("The Visionary")) return;
+
PlayerControl player = evt.Player;
var chancePercentage = (int)(0.2f * 100);
@@ -31,6 +33,8 @@ public static void OnEnterVent(EnterVentEvent evt)
[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.RpcExitVent))]
public static void Postfix(PlayerPhysics __instance, int ventId)
{
+ if (!Utils.IsRoleActive("The Visionary")) return;
+
var chancePercentage = (int)(0.2f * 100);
if (Helpers.CheckChance(chancePercentage))
{
@@ -53,6 +57,8 @@ public static class VisionaryMurderPatch
[RegisterEvent]
public static void OnBeforeMurder(BeforeMurderEvent evt)
{
+ if (!Utils.IsRoleActive("The Visionary")) return;
+
PlayerControl source = evt.Source;
int chancePercentage = (int)(0.2f * 100);
diff --git a/NewMod/Patches/StatsPopupPatch.cs b/NewMod/Patches/StatsPopupPatch.cs
index f446d70..eaee3e1 100644
--- a/NewMod/Patches/StatsPopupPatch.cs
+++ b/NewMod/Patches/StatsPopupPatch.cs
@@ -14,7 +14,7 @@ namespace NewMod.Patches
{
public static class CustomStatsManager
{
- private static readonly string SavePath = Path.Combine(Application.consoleLogPath, "customStats.dat");
+ private static readonly string SavePath = Path.Combine(Application.persistentDataPath, "customStats.dat");
public static Dictionary CustomRoleWins = new();
public static bool _loaded = false;
public static void SaveCustomStats()
@@ -74,6 +74,12 @@ public static void LoadCustomStats()
);
using var reader = new BinaryReader(fs);
+ if (reader.BaseStream.Length == 0)
+ {
+ NewMod.Instance.Log.LogError("Stats file is empty.");
+ return;
+ }
+
int count = reader.ReadInt32();
for (int i = 0; i < count; i++)
{
diff --git a/NewMod/Roles/NeutralRoles/Tyrant.cs b/NewMod/Roles/NeutralRoles/Tyrant.cs
index ad5e146..82eea6b 100644
--- a/NewMod/Roles/NeutralRoles/Tyrant.cs
+++ b/NewMod/Roles/NeutralRoles/Tyrant.cs
@@ -109,6 +109,8 @@ public enum ThroneOutcome { None, ChampionSideWin }
[RegisterEvent]
public static void OnAfterMurderEvent(AfterMurderEvent evt)
{
+ if (!Utils.IsRoleActive("Tyrant")) return;
+
var tyrant = evt.Source.Data.Role as Tyrant;
tyrant._kills++;
@@ -185,18 +187,14 @@ public static IEnumerator CoShowTyrantForChampion(MeetingHud hud)
[RegisterEvent]
public static void OnHandleVote(HandleVoteEvent evt)
{
+ if (!Utils.IsRoleActive("Tyrant")) return;
+
var voter = evt.VoteData.Owner;
var allPlayers = PlayerControl.AllPlayerControls.ToArray();
foreach (var player in allPlayers)
{
- var role = player.Data?.Role;
- if (role is not Tyrant tyrant)
- {
- continue;
- }
-
if (voter.PlayerId != _championId)
{
continue;
@@ -238,6 +236,8 @@ public static void OnHandleVote(HandleVoteEvent evt)
[RegisterEvent]
public static void OnProcessVotes(ProcessVotesEvent evt)
{
+ if (!Utils.IsRoleActive("Tyrant")) return;
+
if (PendingBetrayals.Count == 0) return;
var first = default(byte);
diff --git a/NewMod/Utilities/Utils.cs b/NewMod/Utilities/Utils.cs
index 498b518..8aead77 100644
--- a/NewMod/Utilities/Utils.cs
+++ b/NewMod/Utilities/Utils.cs
@@ -698,7 +698,6 @@ public static void RpcMissionSuccess(PlayerControl source, PlayerControl target)
}
}
}
-
}
[MethodRpc((uint)CustomRPC.MissionFails)]
@@ -1179,5 +1178,18 @@ public static GameObject CreateCircle(string name, Vector3 pos, float radius, Co
Coroutines.Start(CoroutinesHelper.DespawnCircle(go, duration));
return go;
}
+ public static bool IsRoleActive(string roleName)
+ {
+ foreach (var roles in RoleManager.Instance.AllRoles)
+ {
+ CustomRoleManager.GetCustomRoleBehaviour(roles.Role, out var customRole);
+
+ if (customRole != null && customRole.RoleName.Equals(roleName, System.StringComparison.OrdinalIgnoreCase))
+ {
+ return customRole.GetChance() > 0 && customRole.GetCount() > 0;
+ }
+ }
+ return false;
+ }
}
}