cleared all warnings

except for the todo ones, since they are supposed to be annoying
This commit is contained in:
Az committed 2026-09-06 07:03:31 -04:00
1 parent 7099e377ac
commit 8418b479d8
85 files changed
+866 -599

No files matched your search

+15
View File
@@ -20,3 +20,18 @@ dotnet_diagnostic.S3358.severity = none
# IDE1006: Naming Styles # IDE1006: Naming Styles
dotnet_diagnostic.IDE1006.severity = none dotnet_diagnostic.IDE1006.severity = none
# S3267: Use LINQ methods to simply foreach loops
dotnet_diagnostic.S3267.severity = none
# S125: Sections of code should not be commented out
dotnet_diagnostic.S125.severity = none
# SA1512: Single-line comments should not be followed by blank line
dotnet_diagnostic.SA1512.severity = none
# S2696: Instance members should not write to "static" fields
dotnet_diagnostic.S2696.severity = none
# S2245: Pseudorandom number generators (PRNGs) should not be used in security contexts
dotnet_diagnostic.S2245.severity = none
+1 -1
View File
@@ -34,7 +34,7 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="all" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)\stylecop.json" Link="stylecop.json" Visible="false" /> <AdditionalFiles Include="$(MSBuildThisFileDirectory)\stylecop.json" Link="stylecop.json" Visible="false" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.7.0.110445"> <PackageReference Include="SonarAnalyzer.CSharp" Version="10.32.0.713">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>
@@ -12,6 +12,6 @@ public class GeneralModifierOptions : AbstractOptionGroup
[ModdedToggleOption("options.generalModifier.someBooleanOption")] [ModdedToggleOption("options.generalModifier.someBooleanOption")]
public bool SomeBooleanOption { get; set; } = true; public bool SomeBooleanOption { get; set; } = true;
[ModdedNumberOption("options.generalModifier.numberOption", 0, 10, 1)] [ModdedNumberOption("options.generalModifier.numberOption", 0, 10)]
public float NumberOption { get; set; } = 5; public float NumberOption { get; set; } = 5;
} }
+5 -14
View File
@@ -5,26 +5,17 @@ namespace MiraAPI.Events.Mira;
/// <summary> /// <summary>
/// Event fired by Mira API to adjust the UI buttons at the top right of the screen. /// Event fired by Mira API to adjust the UI buttons at the top right of the screen.
/// </summary> /// </summary>
public class UiButtonPostResetEvent : MiraEvent /// <param name="topUiRow">The <see cref="GameObject"/> for the top UI row.</param>
/// <param name="secondUiRow">The <see cref="GameObject"/> for the second UI row.</param>
public class UiButtonPostResetEvent(GameObject topUiRow, GameObject secondUiRow) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="GameObject"/> parent for the very top UI row. /// Gets the <see cref="GameObject"/> parent for the very top UI row.
/// </summary> /// </summary>
public GameObject MainTopUiRow { get; } public GameObject MainTopUiRow { get; } = topUiRow;
/// <summary> /// <summary>
/// Gets the <see cref="GameObject"/> parent for the second top UI row. /// Gets the <see cref="GameObject"/> parent for the second top UI row.
/// </summary> /// </summary>
public GameObject SecondTopUiRow { get; } public GameObject SecondTopUiRow { get; } = secondUiRow;
/// <summary>
/// Initializes a new instance of the <see cref="UiButtonPostResetEvent"/> class.
/// </summary>
/// <param name="topUiRow">The <see cref="GameObject"/> for the top UI row.</param>
/// <param name="secondUiRow">The <see cref="GameObject"/> for the second UI row.</param>
public UiButtonPostResetEvent(GameObject topUiRow, GameObject secondUiRow)
{
MainTopUiRow = topUiRow;
SecondTopUiRow = secondUiRow;
}
} }
@@ -45,23 +45,13 @@ public sealed class BeforeMurderEvent(PlayerControl source, PlayerControl target
/// </summary> /// </summary>
public MeetingCheck InMeeting { get; } = inMeeting; public MeetingCheck InMeeting { get; } = inMeeting;
/// <summary>
/// Initializes a new instance of the <see cref="BeforeMurderEvent"/> class.
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param>
public BeforeMurderEvent(PlayerControl source, PlayerControl target)
: this(source, target, MeetingCheck.Ignore)
{
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BeforeMurderEvent"/> class. /// Initializes a new instance of the <see cref="BeforeMurderEvent"/> class.
/// </summary> /// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param> /// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param> /// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param> /// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
public BeforeMurderEvent(PlayerControl source, PlayerControl target, MeetingCheck inMeeting) public BeforeMurderEvent(PlayerControl source, PlayerControl target, MeetingCheck inMeeting = MeetingCheck.Ignore)
: this(source, target, false, false, inMeeting) : this(source, target, false, false, inMeeting)
{ {
} }
@@ -1,7 +1,7 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// The event that is invoked when the end game screen is shown. Non cancelable. /// The event that is invoked when the end game screen is shown. Non-cancelable.
/// </summary> /// </summary>
/// <param name="manager">The <see cref="global::EndGameManager"/> instance.</param> /// <param name="manager">The <see cref="global::EndGameManager"/> instance.</param>
public class GameEndEvent(EndGameManager manager) : MiraEvent public class GameEndEvent(EndGameManager manager) : MiraEvent
@@ -1,7 +1,7 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// The event that is invoked when the intro cutscene is shown. Non cancelable. /// The event that is invoked when the intro cutscene is shown. Non-cancelable.
/// </summary> /// </summary>
/// <param name="introCutscene">The intro cutscene.</param> /// <param name="introCutscene">The intro cutscene.</param>
public class IntroBeginEvent(IntroCutscene introCutscene) : MiraEvent public class IntroBeginEvent(IntroCutscene introCutscene) : MiraEvent
@@ -1,7 +1,7 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// The event that is invoked when the player's role is shown on the intro cutscene. Non cancelable. /// The event that is invoked when the player's role is shown on the intro cutscene. Non-cancelable.
/// </summary> /// </summary>
/// <param name="introCutscene">The intro cutscene.</param> /// <param name="introCutscene">The intro cutscene.</param>
public class IntroRoleRevealEvent(IntroCutscene introCutscene) : MiraEvent public class IntroRoleRevealEvent(IntroCutscene introCutscene) : MiraEvent
@@ -13,8 +13,6 @@ public class ProcessVotesEvent(List<CustomVote> votes, NetworkedPlayerInfo? exil
{ {
private readonly List<CustomVote> _originalVotes = [.. votes]; private readonly List<CustomVote> _originalVotes = [.. votes];
private NetworkedPlayerInfo? _exiledPlayer = exiledPlayer;
/// <summary> /// <summary>
/// Gets a value indicating whether the exiled player has been modified by the event. /// Gets a value indicating whether the exiled player has been modified by the event.
/// </summary> /// </summary>
@@ -45,11 +43,12 @@ public class ProcessVotesEvent(List<CustomVote> votes, NetworkedPlayerInfo? exil
/// </summary> /// </summary>
public NetworkedPlayerInfo? ExiledPlayer public NetworkedPlayerInfo? ExiledPlayer
{ {
get => _exiledPlayer; get;
set set
{ {
_exiledPlayer = value; field = value;
ExiledPlayerModified = true; ExiledPlayerModified = true;
} }
} }
= exiledPlayer;
} }
@@ -1,7 +1,7 @@
namespace MiraAPI.Events.Vanilla.Player; namespace MiraAPI.Events.Vanilla.Player;
/// <summary> /// <summary>
/// The event that is invoked when a player completes a task. Non cancelable. /// The event that is invoked when a player completes a task. Non-cancelable.
/// </summary> /// </summary>
/// <param name="player">The player who completed the task.</param> /// <param name="player">The player who completed the task.</param>
/// <param name="task">The task that the player completed.</param> /// <param name="task">The task that the player completed.</param>
@@ -1,7 +1,7 @@
namespace MiraAPI.Events.Vanilla.Player; namespace MiraAPI.Events.Vanilla.Player;
/// <summary> /// <summary>
/// Event that is invoked when a player dies. Non cancelable. /// Event that is invoked when a player dies. Non-cancelable.
/// </summary> /// </summary>
/// <param name="player">The player who died.</param> /// <param name="player">The player who died.</param>
/// <param name="reason">The reason the player died.</param> /// <param name="reason">The reason the player died.</param>
@@ -3,7 +3,7 @@
namespace MiraAPI.Events.Vanilla.Player; namespace MiraAPI.Events.Vanilla.Player;
/// <summary> /// <summary>
/// Event that is invoked when a player joins the lobby. Non cancelable. /// Event that is invoked when a player joins the lobby. Non-cancelable.
/// </summary> /// </summary>
/// <param name="data">The data of the player who joined.</param> /// <param name="data">The data of the player who joined.</param>
public class PlayerJoinEvent(ClientData data) : MiraEvent public class PlayerJoinEvent(ClientData data) : MiraEvent
@@ -3,7 +3,7 @@
namespace MiraAPI.Events.Vanilla.Player; namespace MiraAPI.Events.Vanilla.Player;
/// <summary> /// <summary>
/// Event that is invoked when a player leaves the game. Non cancelable. /// Event that is invoked when a player leaves the game. Non-cancelable.
/// </summary> /// </summary>
/// <param name="data">The data of the player who left.</param> /// <param name="data">The data of the player who left.</param>
/// <param name="reason">The reason why the player left.</param> /// <param name="reason">The reason why the player left.</param>
@@ -1,7 +1,7 @@
namespace MiraAPI.Events.Vanilla.Usables; namespace MiraAPI.Events.Vanilla.Usables;
/// <summary> /// <summary>
/// Event for if a <see cref="PlayerControl"/> can use an <see cref="IUsable"/> from Vanilla Among Us. Will always be ran locally. /// Event for if a <see cref="PlayerControl"/> can use an <see cref="IUsable"/> from Vanilla Among Us. Will always be run locally.
/// </summary> /// </summary>
/// <param name="usable">The <see cref="IUsable"/>.</param> /// <param name="usable">The <see cref="IUsable"/>.</param>
public class PlayerCanUseEvent(IUsable usable) : PlayerUseEvent(usable); public class PlayerCanUseEvent(IUsable usable) : PlayerUseEvent(usable);
@@ -1,7 +1,7 @@
namespace MiraAPI.Events.Vanilla.Usables; namespace MiraAPI.Events.Vanilla.Usables;
/// <summary> /// <summary>
/// Event for <see cref="PlayerControl"/> using a <see cref="IUsable"/> from Vanilla Among Us. Will always be ran locally. /// Event for <see cref="PlayerControl"/> using a <see cref="IUsable"/> from Vanilla Among Us. Will always be run locally.
/// </summary> /// </summary>
/// <param name="usable">The <see cref="IUsable"/>.</param> /// <param name="usable">The <see cref="IUsable"/>.</param>
public class PlayerUseEvent(IUsable usable) : MiraCancelableEvent public class PlayerUseEvent(IUsable usable) : MiraCancelableEvent
+15 -20
View File
@@ -84,15 +84,11 @@ public abstract class AbstractGameMode : IOptionable
/// <returns>Resulting body type.</returns> /// <returns>Resulting body type.</returns>
public virtual PlayerBodyTypes GetBodyType(PlayerControl player) public virtual PlayerBodyTypes GetBodyType(PlayerControl player)
{ {
if (AprilFoolsMode.ShouldHorseAround()) return AprilFoolsMode.ShouldHorseAround()
{ ? PlayerBodyTypes.Horse
return PlayerBodyTypes.Horse; : (AprilFoolsMode.ShouldLongAround()
} ? PlayerBodyTypes.Long
if (AprilFoolsMode.ShouldLongAround()) : PlayerBodyTypes.Normal);
{
return PlayerBodyTypes.Long;
}
return PlayerBodyTypes.Normal;
} }
/// <summary> /// <summary>
@@ -185,9 +181,9 @@ public abstract class AbstractGameMode : IOptionable
/// <summary> /// <summary>
/// The IEnumerator that plays the intro cutscene for this gamemode. /// The IEnumerator that plays the intro cutscene for this gamemode.
/// </summary> /// </summary>
/// <param name="__instance">An instance of IntroCutscene.</param> /// <param name="introCutscene">An instance of IntroCutscene.</param>
/// <returns>An IEnumerator to run the intro cutscene instead of the base game one.</returns> /// <returns>An IEnumerator to run the intro cutscene instead of the base game one.</returns>
public virtual IEnumerator IntroCutscene(IntroCutscene __instance) public virtual IEnumerator IntroCutscene(IntroCutscene introCutscene)
{ {
yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame();
} }
@@ -268,11 +264,15 @@ public abstract class AbstractGameMode : IOptionable
} }
/// <summary> /// <summary>
/// Does the task bar appear in the gamemode. /// Gets a value indicating whether the task bar appears in the gamemode.
/// </summary> /// </summary>
/// <returns>True if the task bar is enabled in this mode.</returns> /// <returns>True if the task bar is enabled in this mode.</returns>
public virtual bool ShowTaskBar => true; public virtual bool ShowTaskBar => true;
/// <summary>
/// Updates the task panel.
/// </summary>
/// <param name="instance">The task panel to update.</param>
public virtual void UpdateTaskPanel(TaskPanelBehaviour instance) public virtual void UpdateTaskPanel(TaskPanelBehaviour instance)
{ {
instance.background.transform.localScale = (instance.taskText.textBounds.size.x > 0f) instance.background.transform.localScale = (instance.taskText.textBounds.size.x > 0f)
@@ -296,14 +296,9 @@ public abstract class AbstractGameMode : IOptionable
var xPos = -instance.background.sprite.bounds.size.x * instance.background.transform.localScale.x; var xPos = -instance.background.sprite.bounds.size.x * instance.background.transform.localScale.x;
instance.closedPosition = new Vector3(xPos, yPos, instance.closedPosition.z); instance.closedPosition = new Vector3(xPos, yPos, instance.closedPosition.z);
instance.openPosition = new Vector3(instance.openPosition.x, yPos, instance.openPosition.z); instance.openPosition = new Vector3(instance.openPosition.x, yPos, instance.openPosition.z);
if (instance.open) instance.timer = instance.open
{ ? Mathf.Min(1f, instance.timer + Time.deltaTime / instance.animationTimeSeconds)
instance.timer = Mathf.Min(1f, instance.timer + Time.deltaTime / instance.animationTimeSeconds); : Mathf.Max(0f, instance.timer - Time.deltaTime / instance.animationTimeSeconds);
}
else
{
instance.timer = Mathf.Max(0f, instance.timer - Time.deltaTime / instance.animationTimeSeconds);
}
Vector3 relativePos = new( Vector3 relativePos = new(
Mathf.SmoothStep(instance.closedPosition.x, instance.openPosition.x, instance.timer), Mathf.SmoothStep(instance.closedPosition.x, instance.openPosition.x, instance.timer),
+1
View File
@@ -16,5 +16,6 @@ public class ClassicMode : AbstractGameMode
/// <inheritdoc/> /// <inheritdoc/>
public override string Description => "MiraApi.Gamemode.Classic.Description"; public override string Description => "MiraApi.Gamemode.Classic.Description";
/// <inheritdoc/>
public override LoadableAsset<Sprite>? Icon => MiraAssets.ClassicGamemodeIcon; public override LoadableAsset<Sprite>? Icon => MiraAssets.ClassicGamemodeIcon;
} }
+4 -6
View File
@@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using MiraAPI.PluginLoading; using MiraAPI.PluginLoading;
using Reactor.Utilities;
namespace MiraAPI.GameModes; namespace MiraAPI.GameModes;
@@ -42,14 +41,13 @@ public static class CustomGameModeManager
return false; return false;
} }
if (!mode.HideMode) if (mode.HideMode)
{ return true;
IdToModeMap.Add(GetNextId(), mode); IdToModeMap.Add(GetNextId(), mode);
pluginInfo.GameModes.Add(LastId, mode); pluginInfo.GameModes.Add(LastId, mode);
mode.ID = LastId; mode.ID = LastId;
GameModeOption.AddOption(mode); GameModeOption.AddOption(mode);
}
return true; return true;
} }
@@ -135,6 +133,6 @@ public static class CustomGameModeManager
} }
ActiveMode = IdToModeMap[0]; ActiveMode = IdToModeMap[0];
Logger<MiraApiPlugin>.Warning($"Unable to find game mode of id {id}!"); Warning($"Unable to find game mode of id {id}!");
} }
} }
+16 -12
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using HarmonyLib; using HarmonyLib;
using MiraAPI.GameOptions; using MiraAPI.GameOptions;
@@ -26,20 +27,23 @@ public static class GameModeOption
get => get =>
OptionBehaviour != null OptionBehaviour != null
? OptionBehaviour.GetInt() ? OptionBehaviour.GetInt()
: _lastValue; : LastValue;
private set private set
{ {
_lastValue = value; LastValue = value;
if (OptionBehaviour == null) if (OptionBehaviour == null)
return; return;
OptionBehaviour.Value = value; OptionBehaviour.Value = value;
OptionBehaviour.UpdateValue(); OptionBehaviour.UpdateValue();
_lastValue = value; LastValue = value;
} }
} }
internal static StringOption OptionBehaviour { get; set; } = null!; internal static StringOption OptionBehaviour { get; set; } = null!;
internal static int _lastValue; [SuppressMessage("Critical Code Smell", "S2223:Non-constant static fields should not be visible", Justification = "Internal behaviour that does not need property-level validation.")]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Read above.")] // why so many warnings???
internal static int LastValue;
internal static readonly StringNames GamemodeName = MiraLocaleManager.GetOrCreateLocaleString("Gamemode"); internal static readonly StringNames GamemodeName = MiraLocaleManager.GetOrCreateLocaleString("Gamemode");
internal static readonly StringNames CustomName = MiraLocaleManager.GetOrCreateLocaleString("Custom"); internal static readonly StringNames CustomName = MiraLocaleManager.GetOrCreateLocaleString("Custom");
internal static readonly Dictionary<uint, StringNames> Values = new() internal static readonly Dictionary<uint, StringNames> Values = new()
@@ -103,7 +107,7 @@ public static class GameModeOption
Value = val; Value = val;
var previousMode = CustomGameModeManager.ActiveMode; var previousMode = CustomGameModeManager.ActiveMode;
CustomGameModeManager.GetAndSetGameMode(); CustomGameModeManager.GetAndSetGameMode();
HudPatches.SetGameModeText(CustomGameModeManager.GetMode(Values.ElementAt(_lastValue).Key).ColoredName); HudPatches.SetGameModeText(CustomGameModeManager.GetMode(Values.ElementAt(LastValue).Key).ColoredName);
var gm = CustomGameModeManager.ActiveMode!; var gm = CustomGameModeManager.ActiveMode!;
if (gm != previousMode) if (gm != previousMode)
{ {
@@ -112,8 +116,7 @@ public static class GameModeOption
GamemodeName, GamemodeName,
gm.ColoredName, gm.ColoredName,
new Color(0.7333f, 0.7333f, 0.7333f, 1), new Color(0.7333f, 0.7333f, 0.7333f, 1),
gm.TmpIcon, gm.TmpIcon);
true);
if (MenuState.Instance) if (MenuState.Instance)
{ {
// should force reset roles for gamemodes properly // should force reset roles for gamemodes properly
@@ -130,10 +133,12 @@ public static class GameModeOption
[HarmonyPrefix] [HarmonyPrefix]
private static bool ValueChanged(GameOptionsMenu __instance, OptionBehaviour option) private static bool ValueChanged(GameOptionsMenu __instance, OptionBehaviour option)
{ {
if (OptionBehaviour.Equals(option)) if (!OptionBehaviour.Equals(option))
{ return true;
Info($"Game mode changed to {option.GetInt()}"); Info($"Game mode changed to {option.GetInt()}");
RpcSyncGamemode(PlayerControl.LocalPlayer, option.GetInt()); RpcSyncGamemode(PlayerControl.LocalPlayer, option.GetInt());
if (GameSettingMenu.Instance && CustomGameModeManager.ActiveMode != null) if (GameSettingMenu.Instance && CustomGameModeManager.ActiveMode != null)
{ {
GameOptionsMenuPatch.ToggleGamemodeOptions(CustomGameModeManager.ActiveMode, __instance); GameOptionsMenuPatch.ToggleGamemodeOptions(CustomGameModeManager.ActiveMode, __instance);
@@ -141,10 +146,9 @@ public static class GameModeOption
} }
return false; return false;
} }
return true;
}
[MethodRpc((uint) MiraRpc.SyncGamemodeOption)] [MethodRpc((uint)MiraRpc.SyncGamemodeOption)]
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Intentionally unused because the main intent is for it to be used by dependent mods to add to a blacklist.")]
internal static void RpcSyncGamemode(PlayerControl host, int data) internal static void RpcSyncGamemode(PlayerControl host, int data)
{ {
Set(data); Set(data);
+102 -83
View File
@@ -1,6 +1,8 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq; using System.Linq;
using AmongUs.Data; using AmongUs.Data;
using AmongUs.GameOptions; using AmongUs.GameOptions;
@@ -30,52 +32,70 @@ public class HideAndSeekMode : AbstractGameMode
/// <inheritdoc/> /// <inheritdoc/>
public override string Description => "MiraApi.Gamemode.HideAndSeek.Description"; public override string Description => "MiraApi.Gamemode.HideAndSeek.Description";
/// <inheritdoc/>
// TODO: Once the Hide n Seek port is ready for release, we will remove this. // TODO: Once the Hide n Seek port is ready for release, we will remove this.
public override bool HideMode => !MiraApiPlugin.IsDevBuild; public override bool HideMode => !MiraApiPlugin.IsDevBuild;
/// <inheritdoc/>
public override Color Color { get; } = new Color32(255, 88, 90, 255); public override Color Color { get; } = new Color32(255, 88, 90, 255);
public override LoadableAsset<Sprite>? Icon => MiraAssets.HnSGamemodeIcon;
/// <inheritdoc/>
public override LoadableAsset<Sprite> Icon => MiraAssets.HnSGamemodeIcon;
/// <inheritdoc/>
public override bool ShowGameModeIntroCutscene => true;
/// <inheritdoc/>
public override bool GameModeBodyTypeOverride => true;
/// <inheritdoc/>
public override bool ShowNormalGameSettings => false;
/// <inheritdoc/>
public override bool ShowNormalRoleSettings => false;
/// <inheritdoc/>
public override float DefaultImpostorKillCooldown => 1f;
/// <inheritdoc/>
public override bool ShowTaskBar => false;
/// <inheritdoc/>
public override bool CanReport(DeadBody body) public override bool CanReport(DeadBody body)
{ {
return false; return false;
} }
/// <inheritdoc/>
public override bool ShouldShowSabotageMap(MapBehaviour map) public override bool ShouldShowSabotageMap(MapBehaviour map)
{ {
return false; return false;
} }
public override bool ShowGameModeIntroCutscene => true; private static int ImpostorPlayerID()
public override bool GameModeBodyTypeOverride => true;
public override bool ShowNormalGameSettings => false;
public override bool ShowNormalRoleSettings => false;
public override float DefaultImpostorKillCooldown => 1f;
public override bool ShowTaskBar => false;
public static int ImpostorPlayerID()
{ {
return OptionGroupSingleton<HnsImpostorOptions>.Instance.SelectedSeeker.Value; return OptionGroupSingleton<HnsImpostorOptions>.Instance.SelectedSeeker.Value;
} }
public static bool HasImpostorPlayerID() private static bool HasImpostorPlayerID()
{ {
return ImpostorPlayerID() > -1; return ImpostorPlayerID() > -1;
} }
public static bool ValidateImpostorPlayerID(List<NetworkedPlayerInfo> players) private static bool ValidateImpostorPlayerID(List<NetworkedPlayerInfo> players)
{ {
return HasImpostorPlayerID() && players.Find((NetworkedPlayerInfo p) => (int)p.PlayerId == ImpostorPlayerID()) != null; return HasImpostorPlayerID() && players.Find(p => p.PlayerId == ImpostorPlayerID()) != null;
} }
/// <inheritdoc/>
public override void AssignRoles(out bool runOriginal, LogicRoleSelectionNormal instance) public override void AssignRoles(out bool runOriginal, LogicRoleSelectionNormal instance)
{ {
runOriginal = false; runOriginal = false;
Il2CppSystem.Collections.Generic.List<ClientData> list = new(); Il2CppSystem.Collections.Generic.List<ClientData> list = new();
AmongUsClient.Instance.GetAllClients(list); AmongUsClient.Instance.GetAllClients(list);
List<NetworkedPlayerInfo> list2 = list.ToArray() List<NetworkedPlayerInfo> list2 = [.. list.ToArray()
.Where(c => c.Character != null && c.Character.Data != null && !c.Character.Data.Disconnected && .Where(c => c.Character != null && c.Character.Data != null && !c.Character.Data.Disconnected &&
!c.Character.Data.IsDead).OrderBy(c => c.Id).Select(c => c.Character.Data) !c.Character.Data.IsDead).OrderBy(c => c.Id).Select(c => c.Character.Data)];
.ToList();
foreach (NetworkedPlayerInfo networkedPlayerInfo in GameData.Instance.AllPlayers) foreach (NetworkedPlayerInfo networkedPlayerInfo in GameData.Instance.AllPlayers)
{ {
@@ -90,7 +110,7 @@ public class HideAndSeekMode : AbstractGameMode
AssignRolesForTeam(list2, currentGameOptions, RoleTeamTypes.Crewmate, int.MaxValue, RoleTypes.Engineer); AssignRolesForTeam(list2, currentGameOptions, RoleTeamTypes.Crewmate, int.MaxValue, RoleTypes.Engineer);
} }
public static void AssignRolesForTeam( private static void AssignRolesForTeam(
List<NetworkedPlayerInfo> players, List<NetworkedPlayerInfo> players,
IGameOptions opts, IGameOptions opts,
RoleTeamTypes team, RoleTeamTypes team,
@@ -102,7 +122,8 @@ public class HideAndSeekMode : AbstractGameMode
IRoleOptionsCollection roleOptions = opts.RoleOptions; IRoleOptionsCollection roleOptions = opts.RoleOptions;
var source = RoleManager.Instance.AllRoles.ToArray() var source = RoleManager.Instance.AllRoles.ToArray()
.Where(role => role.TeamType == team && !RoleManager.IsGhostRole(role.Role) && .Where(role => role.TeamType == team && !RoleManager.IsGhostRole(role.Role) &&
CustomRoleUtils.CanSpawnOnCurrentMode(role)); CustomRoleUtils.CanSpawnOnCurrentMode(role))
.ToList();
var assignmentData = source.Where(x => !x.IsDead).Select(role => var assignmentData = source.Where(x => !x.IsDead).Select(role =>
new RoleManager.RoleAssignmentData( new RoleManager.RoleAssignmentData(
role, role,
@@ -110,7 +131,7 @@ public class HideAndSeekMode : AbstractGameMode
roleOptions.GetChancePerGame(role.Role))).ToList(); roleOptions.GetChancePerGame(role.Role))).ToList();
var source2 = CustomRoleUtils.GetPossibleRoles(assignmentData, x => x.Chance == 100); var source2 = CustomRoleUtils.GetPossibleRoles(assignmentData, x => x.Chance == 100);
var guaranteedRoles = source.Where(x => source2.Contains(((ushort)x.Role, 100))); var guaranteedRoles = source.Where(x => source2.Contains(((ushort)x.Role, 100)));
List<RoleTypes> list = new List<RoleTypes>(); List<RoleTypes> list = [];
if (team == RoleTeamTypes.Crewmate) if (team == RoleTeamTypes.Crewmate)
{ {
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: Before Guaranteed Assignment"); Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: Before Guaranteed Assignment");
@@ -171,7 +192,7 @@ public class HideAndSeekMode : AbstractGameMode
ValidateImpostorPlayerID(players) && ValidateImpostorPlayerID(players) &&
!AmongUsClient.Instance.IsGamePublic) !AmongUsClient.Instance.IsGamePublic)
{ {
NetworkedPlayerInfo networkedPlayerInfo = players.ToArray() NetworkedPlayerInfo networkedPlayerInfo = players
.First(p => p.PlayerId == ImpostorPlayerID()); .First(p => p.PlayerId == ImpostorPlayerID());
players.Remove(networkedPlayerInfo); players.Remove(networkedPlayerInfo);
newImpostors.Add(networkedPlayerInfo); newImpostors.Add(networkedPlayerInfo);
@@ -183,8 +204,8 @@ public class HideAndSeekMode : AbstractGameMode
int num2 = 0; int num2 = 0;
while (num2 < teamMax && players.Count > 0) while (num2 < teamMax && players.Count > 0)
{ {
PseudoRandomList<NetworkedPlayerInfo> pseudoRandomList = new PseudoRandomList<NetworkedPlayerInfo>(AmongUsClient.Instance.GameId); PseudoRandomList<NetworkedPlayerInfo> pseudoRandomList = new(AmongUsClient.Instance.GameId);
players.Do(x => pseudoRandomList.Add(x)); players.Do(pseudoRandomList.Add);
for (int i = 0; i < GameData.RoundsPlayedInSession; i++) for (int i = 0; i < GameData.RoundsPlayedInSession; i++)
{ {
pseudoRandomList.PickRandom(); pseudoRandomList.PickRandom();
@@ -244,7 +265,7 @@ public class HideAndSeekMode : AbstractGameMode
} }
} }
public static void AssignRolesFromList(List<NetworkedPlayerInfo> players, int teamMax, List<RoleTypes> roleList, ref int rolesAssigned) private static void AssignRolesFromList(List<NetworkedPlayerInfo> players, int teamMax, List<RoleTypes> roleList, ref int rolesAssigned)
{ {
while (roleList.Count > 0 && players.Count > 0 && rolesAssigned < teamMax) while (roleList.Count > 0 && players.Count > 0 && rolesAssigned < teamMax)
{ {
@@ -252,62 +273,56 @@ public class HideAndSeekMode : AbstractGameMode
RoleTypes roleType = roleList[index]; RoleTypes roleType = roleList[index];
roleList.RemoveAt(index); roleList.RemoveAt(index);
int index2 = HashRandom.FastNext(players.Count); int index2 = HashRandom.FastNext(players.Count);
players[index2].Object.RpcSetRole(roleType, false); players[index2].Object.RpcSetRole(roleType);
players.RemoveAt(index2); players.RemoveAt(index2);
rolesAssigned++; rolesAssigned++;
} }
} }
public override IEnumerator IntroCutscene(IntroCutscene __instance) /// <inheritdoc/>
public override IEnumerator IntroCutscene(IntroCutscene introCutscene)
{ {
SoundManager.Instance.PlaySound(__instance.IntroStinger, false, 1f, null); SoundManager.Instance.PlaySound(introCutscene.IntroStinger, false);
Logger.GlobalInstance.Info("IntroCutscene :: CoBegin() :: Game Mode: Hide and Seek (MiraAPI)", null); Logger.GlobalInstance.Info("IntroCutscene :: CoBegin() :: Game Mode: Hide and Seek (MiraAPI)");
__instance.LogPlayerRoleData(); introCutscene.LogPlayerRoleData();
__instance.HideAndSeekPanels.SetActive(true); introCutscene.HideAndSeekPanels.SetActive(true);
if (PlayerControl.LocalPlayer.Data.Role.IsImpostor) if (PlayerControl.LocalPlayer.Data.Role.IsImpostor)
{ {
__instance.CrewmateRules.SetActive(false); introCutscene.CrewmateRules.SetActive(false);
__instance.ImpostorRules.SetActive(true); introCutscene.ImpostorRules.SetActive(true);
} }
else else
{ {
__instance.CrewmateRules.SetActive(true); introCutscene.CrewmateRules.SetActive(true);
__instance.ImpostorRules.SetActive(false); introCutscene.ImpostorRules.SetActive(false);
} }
__instance.ImpostorName.gameObject.SetActive(true); introCutscene.ImpostorName.gameObject.SetActive(true);
__instance.ImpostorTitle.gameObject.SetActive(true); introCutscene.ImpostorTitle.gameObject.SetActive(true);
__instance.BackgroundBar.enabled = false; introCutscene.BackgroundBar.enabled = false;
__instance.TeamTitle.gameObject.SetActive(false); introCutscene.TeamTitle.gameObject.SetActive(false);
var impostor = PlayerControl.AllPlayerControls.ToArray().FirstOrDefault(x => x.Data.Role.IsImpostor); var impostor = PlayerControl.AllPlayerControls.ToArray().FirstOrDefault(x => x.Data.Role.IsImpostor);
if (impostor == null) if (impostor == null)
{ {
Logger.GlobalInstance.Error("IntroCutscene :: CoBegin() :: impostor is NULL", null); Logger.GlobalInstance.Error("IntroCutscene :: CoBegin() :: impostor is NULL");
} }
GameManager.Instance.SetSpecialCosmetics(impostor); GameManager.Instance.SetSpecialCosmetics(impostor);
if (impostor != null) introCutscene.ImpostorName.text = impostor != null ? impostor.Data.PlayerName : "???";
{
__instance.ImpostorName.text = impostor.Data.PlayerName;
}
else
{
__instance.ImpostorName.text = "???";
}
yield return new WaitForSecondsRealtime(0.1f); yield return new WaitForSecondsRealtime(0.1f);
if (impostor != null) if (impostor != null)
{ {
__instance.ImpostorTitle.text = impostor.Data.Role.GetRoleName(); introCutscene.ImpostorTitle.text = impostor.Data.Role.GetRoleName();
} }
PoolablePlayer playerSlot = null; PoolablePlayer? playerSlot = null;
if (impostor != null) if (impostor != null)
{ {
playerSlot = __instance.CreatePlayer(1, 1, impostor.Data, false); playerSlot = introCutscene.CreatePlayer(1, 1, impostor.Data, false);
playerSlot.SetBodyType(PlayerBodyTypes.Normal); playerSlot.SetBodyType(PlayerBodyTypes.Normal);
playerSlot.SetFlipX(false); playerSlot.SetFlipX(false);
playerSlot.transform.localPosition = __instance.impostorPos; playerSlot.transform.localPosition = introCutscene.impostorPos;
playerSlot.transform.localScale = Vector3.one * __instance.impostorScale; playerSlot.transform.localScale = Vector3.one * introCutscene.impostorScale;
} }
yield return ShipStatus.Instance.CosmeticsCache.PopulateFromPlayers(); yield return ShipStatus.Instance.CosmeticsCache.PopulateFromPlayers();
@@ -317,45 +332,43 @@ public class HideAndSeekMode : AbstractGameMode
playerSlot.gameObject.SetActive(false); playerSlot.gameObject.SetActive(false);
} }
__instance.HideAndSeekPanels.SetActive(false); introCutscene.HideAndSeekPanels.SetActive(false);
__instance.CrewmateRules.SetActive(false); introCutscene.CrewmateRules.SetActive(false);
__instance.ImpostorRules.SetActive(false); introCutscene.ImpostorRules.SetActive(false);
HnsMusicHandler.Instance.StartMusicWithIntro(); HnsMusicHandler.Instance.StartMusicWithIntro();
var hideTimer = 10f; var hideTimer = 10f;
if (PlayerControl.LocalPlayer.Data.Role.IsImpostor) if (PlayerControl.LocalPlayer.Data.Role.IsImpostor)
{ {
__instance.HideAndSeekTimerText.gameObject.SetActive(true); introCutscene.HideAndSeekTimerText.gameObject.SetActive(true);
PoolablePlayer poolablePlayer; PoolablePlayer poolablePlayer;
AnimationClip anim; AnimationClip anim;
if (AprilFoolsMode.ShouldHorseAround()) if (AprilFoolsMode.ShouldHorseAround())
{ {
poolablePlayer = __instance.HorseWrangleVisualSuit; poolablePlayer = introCutscene.HorseWrangleVisualSuit;
poolablePlayer.gameObject.SetActive(true); poolablePlayer.gameObject.SetActive(true);
poolablePlayer.SetBodyType(PlayerBodyTypes.Seeker); poolablePlayer.SetBodyType(PlayerBodyTypes.Seeker);
anim = __instance.HnSSeekerSpawnHorseAnim; anim = introCutscene.HnSSeekerSpawnHorseAnim;
__instance.HorseWrangleVisualPlayer.SetBodyType(PlayerBodyTypes.Normal); introCutscene.HorseWrangleVisualPlayer.SetBodyType(PlayerBodyTypes.Normal);
__instance.HorseWrangleVisualPlayer.UpdateFromPlayerData( introCutscene.HorseWrangleVisualPlayer.UpdateFromPlayerData(
PlayerControl.LocalPlayer.Data, PlayerControl.LocalPlayer.Data,
PlayerControl.LocalPlayer.CurrentOutfitType, PlayerControl.LocalPlayer.CurrentOutfitType,
PlayerMaterial.MaskType.None, PlayerMaterial.MaskType.None,
false,
null,
false); false);
} }
else if (AprilFoolsMode.ShouldLongAround()) else if (AprilFoolsMode.ShouldLongAround())
{ {
poolablePlayer = __instance.HideAndSeekPlayerVisual; poolablePlayer = introCutscene.HideAndSeekPlayerVisual;
poolablePlayer.gameObject.SetActive(true); poolablePlayer.gameObject.SetActive(true);
poolablePlayer.SetBodyType(PlayerBodyTypes.LongSeeker); poolablePlayer.SetBodyType(PlayerBodyTypes.LongSeeker);
anim = __instance.HnSSeekerSpawnLongAnim; anim = introCutscene.HnSSeekerSpawnLongAnim;
} }
else else
{ {
poolablePlayer = __instance.HideAndSeekPlayerVisual; poolablePlayer = introCutscene.HideAndSeekPlayerVisual;
poolablePlayer.gameObject.SetActive(true); poolablePlayer.gameObject.SetActive(true);
poolablePlayer.SetBodyType(PlayerBodyTypes.Seeker); poolablePlayer.SetBodyType(PlayerBodyTypes.Seeker);
anim = __instance.HnSSeekerSpawnAnim; anim = introCutscene.HnSSeekerSpawnAnim;
} }
poolablePlayer.SetBodyCosmeticsVisible(false); poolablePlayer.SetBodyCosmeticsVisible(false);
@@ -363,16 +376,14 @@ public class HideAndSeekMode : AbstractGameMode
PlayerControl.LocalPlayer.Data, PlayerControl.LocalPlayer.Data,
PlayerControl.LocalPlayer.CurrentOutfitType, PlayerControl.LocalPlayer.CurrentOutfitType,
PlayerMaterial.MaskType.None, PlayerMaterial.MaskType.None,
false,
null,
false); false);
SpriteAnim component = poolablePlayer.GetComponent<SpriteAnim>(); SpriteAnim component = poolablePlayer.GetComponent<SpriteAnim>();
poolablePlayer.gameObject.SetActive(true); poolablePlayer.gameObject.SetActive(true);
poolablePlayer.ToggleName(false); poolablePlayer.ToggleName(false);
component.Play(anim, 1f); component.Play(anim);
while (hideTimer > 0f) while (hideTimer > 0f)
{ {
__instance.HideAndSeekTimerText.text = Mathf.RoundToInt(hideTimer).ToString(); introCutscene.HideAndSeekTimerText.text = Mathf.RoundToInt(hideTimer).ToString(CultureInfo.InvariantCulture);
hideTimer -= Time.deltaTime; hideTimer -= Time.deltaTime;
yield return null; yield return null;
} }
@@ -384,27 +395,29 @@ public class HideAndSeekMode : AbstractGameMode
{ {
if (impostor != null) if (impostor != null)
{ {
impostor.AnimateCustom(__instance.HnSSeekerSpawnHorseInGameAnim); impostor.AnimateCustom(introCutscene.HnSSeekerSpawnHorseInGameAnim);
} }
} }
else if (AprilFoolsMode.ShouldLongAround()) else if (AprilFoolsMode.ShouldLongAround())
{ {
if (impostor != null) if (impostor != null)
{ {
impostor.AnimateCustom(__instance.HnSSeekerSpawnLongInGameAnim); impostor.AnimateCustom(introCutscene.HnSSeekerSpawnLongInGameAnim);
} }
} }
else if (impostor != null) else if (impostor != null)
{ {
impostor.AnimateCustom(__instance.HnSSeekerSpawnAnim); impostor.AnimateCustom(introCutscene.HnSSeekerSpawnAnim);
impostor.cosmetics.SetBodyCosmeticsVisible(false); impostor.cosmetics.SetBodyCosmeticsVisible(false);
} }
} }
ShipStatus.Instance.StartSFX(); ShipStatus.Instance.StartSFX();
HnsMusicHandler.Instance.OnGameStart(); HnsMusicHandler.Instance.OnGameStart();
HnsDangerMeter.Instance.OnGameStart(); HnsDangerMeter.Instance.OnGameStart();
UnityEngine.Object.Destroy(__instance.gameObject); UnityEngine.Object.Destroy(introCutscene.gameObject);
} }
/// <inheritdoc/>
public override void Initialize() public override void Initialize()
{ {
deadPlayerCount = 0; deadPlayerCount = 0;
@@ -417,9 +430,11 @@ public class HideAndSeekMode : AbstractGameMode
HudManager.Instance.gameObject.AddComponent<HnsDangerMeter>(); HudManager.Instance.gameObject.AddComponent<HnsDangerMeter>();
} }
} }
/// <inheritdoc/>
public override MapOptions GetMapOptions() public override MapOptions GetMapOptions()
{ {
MapOptions mapOptions = new MapOptions MapOptions mapOptions = new()
{ {
Mode = MapOptions.Modes.Normal, Mode = MapOptions.Modes.Normal,
}; };
@@ -433,14 +448,16 @@ public class HideAndSeekMode : AbstractGameMode
return mapOptions; return mapOptions;
} }
/// <inheritdoc/>
public override void CheckGameEnd(out bool runOriginal, LogicGameFlowNormal instance) public override void CheckGameEnd(out bool runOriginal, LogicGameFlowNormal instance)
{ {
runOriginal = false; runOriginal = false;
if (Helpers.GetAlivePlayers().Count(x => x.Data.Role.IsImpostor) == 0) var players = Helpers.GetAlivePlayers();
if (!players.Any(x => x.Data.Role.IsImpostor))
{ {
instance.Manager.RpcEndGame(GameOverReason.ImpostorDisconnect, !DataManager.Player.Ads.HasPurchasedAdRemoval); instance.Manager.RpcEndGame(GameOverReason.ImpostorDisconnect, !DataManager.Player.Ads.HasPurchasedAdRemoval);
} }
if (Helpers.GetAlivePlayers().Count(x => !x.Data.Role.IsImpostor) != 0) if (players.Any(x => !x.Data.Role.IsImpostor))
{ {
if (HideAndSeekHudHelper.Instance.AllTimersExpired()) if (HideAndSeekHudHelper.Instance.AllTimersExpired())
{ {
@@ -451,6 +468,8 @@ public class HideAndSeekMode : AbstractGameMode
instance.Manager.RpcEndGame(GameOverReason.HideAndSeek_ImpostorsByKills, !DataManager.Player.Ads.HasPurchasedAdRemoval); instance.Manager.RpcEndGame(GameOverReason.HideAndSeek_ImpostorsByKills, !DataManager.Player.Ads.HasPurchasedAdRemoval);
} }
/// <inheritdoc/>
[SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Warning cascades into forcing the entire tree to be ternary operators.")]
public override PlayerBodyTypes GetBodyType(PlayerControl player) public override PlayerBodyTypes GetBodyType(PlayerControl player)
{ {
if (player == null || player.Data == null || player.Data.Role == null) if (player == null || player.Data == null || player.Data.Role == null)
@@ -490,6 +509,8 @@ public class HideAndSeekMode : AbstractGameMode
return PlayerBodyTypes.Normal; return PlayerBodyTypes.Normal;
} }
} }
/// <inheritdoc/>
public override void UpdateTaskPanel(TaskPanelBehaviour instance) public override void UpdateTaskPanel(TaskPanelBehaviour instance)
{ {
instance.background.transform.localScale = (instance.taskText.textBounds.size.x > 0f) instance.background.transform.localScale = (instance.taskText.textBounds.size.x > 0f)
@@ -513,14 +534,9 @@ public class HideAndSeekMode : AbstractGameMode
var xPos = -instance.background.sprite.bounds.size.x * instance.background.transform.localScale.x; var xPos = -instance.background.sprite.bounds.size.x * instance.background.transform.localScale.x;
instance.closedPosition = new Vector3(xPos, yPos, instance.closedPosition.z); instance.closedPosition = new Vector3(xPos, yPos, instance.closedPosition.z);
instance.openPosition = new Vector3(instance.openPosition.x, yPos, instance.openPosition.z); instance.openPosition = new Vector3(instance.openPosition.x, yPos, instance.openPosition.z);
if (instance.open) instance.timer = instance.open
{ ? Mathf.Min(1f, instance.timer + Time.deltaTime / instance.animationTimeSeconds)
instance.timer = Mathf.Min(1f, instance.timer + Time.deltaTime / instance.animationTimeSeconds); : Mathf.Max(0f, instance.timer - Time.deltaTime / instance.animationTimeSeconds);
}
else
{
instance.timer = Mathf.Max(0f, instance.timer - Time.deltaTime / instance.animationTimeSeconds);
}
Vector3 relativePos = new( Vector3 relativePos = new(
Mathf.SmoothStep(instance.closedPosition.x, instance.openPosition.x, instance.timer), Mathf.SmoothStep(instance.closedPosition.x, instance.openPosition.x, instance.timer),
@@ -529,7 +545,10 @@ public class HideAndSeekMode : AbstractGameMode
instance.transform.localPosition = instance.transform.localPosition =
AspectPosition.ComputePosition(AspectPosition.EdgeAlignments.LeftTop, relativePos); AspectPosition.ComputePosition(AspectPosition.EdgeAlignments.LeftTop, relativePos);
} }
private int deadPlayerCount; private int deadPlayerCount;
/// <inheritdoc/>
public override void OnPlayerDeath(PlayerControl player, bool assignGhostRole) public override void OnPlayerDeath(PlayerControl player, bool assignGhostRole)
{ {
base.OnPlayerDeath(player, assignGhostRole); base.OnPlayerDeath(player, assignGhostRole);
+3 -3
View File
@@ -87,11 +87,11 @@ public abstract class AbstractOptionGroup<T> : AbstractOptionGroup where T : IOp
get get
{ {
var type = typeof(T); var type = typeof(T);
if (type == typeof(BaseModifier)) if (typeof(BaseModifier).IsAssignableFrom(type))
{ {
return MenuCategory.Modifiers; return MenuCategory.Modifiers;
} }
else if (type == typeof(RoleBehaviour)) else if (typeof(RoleBehaviour).IsAssignableFrom(type))
{ {
return MenuCategory.Roles; return MenuCategory.Roles;
} }
@@ -104,7 +104,7 @@ public abstract class AbstractOptionGroup<T> : AbstractOptionGroup where T : IOp
/// Base class for option groups. An option group is a collection of options that are displayed together in the options menu. /// Base class for option groups. An option group is a collection of options that are displayed together in the options menu.
/// </summary> /// </summary>
/// <typeparam name="T">The custom role that the group is for.</typeparam> /// <typeparam name="T">The custom role that the group is for.</typeparam>
public abstract class AbstractRoleOptionGroup<T>() : AbstractOptionGroup<T> where T : ICustomRole public abstract class AbstractRoleOptionGroup<T> : AbstractOptionGroup<T> where T : ICustomRole
{ {
/// <inheritdoc /> /// <inheritdoc />
public override Type OptionableType => typeof(T); public override Type OptionableType => typeof(T);
@@ -8,6 +8,9 @@ namespace MiraAPI.GameOptions.Attributes;
/// <summary> /// <summary>
/// Attribute for creating a <see cref="ModdedEnumOption"/>. /// Attribute for creating a <see cref="ModdedEnumOption"/>.
/// </summary> /// </summary>
/// <param name="title">The title of the option.</param>
/// <param name="enumType">The <see cref="Enum"/> type.</param>
/// <param name="values">An option list of string values to use in place of the <see langword="enum"/> name.</param>
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class ModdedEnumOptionAttribute(string title, Type enumType, string[]? values = null) public class ModdedEnumOptionAttribute(string title, Type enumType, string[]? values = null)
: ModdedOptionAttribute(title) : ModdedOptionAttribute(title)
@@ -9,6 +9,13 @@ namespace MiraAPI.GameOptions.Attributes;
/// <summary> /// <summary>
/// Attribute for a <see cref="ModdedNumberOption"/>. /// Attribute for a <see cref="ModdedNumberOption"/>.
/// </summary> /// </summary>
/// <param name="title">The option title.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <param name="increment">The increment.</param>
/// <param name="suffixType">The suffix type.</param>
/// <param name="formatString">Optional format string for the option screen.</param>
/// <param name="zeroInfinity">Flag indicating whether 0 means infinity.</param>
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class ModdedNumberOptionAttribute( public class ModdedNumberOptionAttribute(
string title, string title,
+2 -3
View File
@@ -46,9 +46,8 @@ public static class ModdedOptionsManager
/// <param name="playSound">A flag that indicates if a notification sound should be played.</param> /// <param name="playSound">A flag that indicates if a notification sound should be played.</param>
public static void AddSettingsChangeMessage(NotificationPopper notif, StringNames key, string value, Color textColor, TMP_SpriteAsset? sprite, bool playSound = true) public static void AddSettingsChangeMessage(NotificationPopper notif, StringNames key, string value, Color textColor, TMP_SpriteAsset? sprite, bool playSound = true)
{ {
string item;
var text = textColor.ToTextColor(); var text = textColor.ToTextColor();
item = sprite != null var item = sprite != null
? TranslationController.Instance.GetString( ? TranslationController.Instance.GetString(
StringNames.LobbyChangeSettingNotification, StringNames.LobbyChangeSettingNotification,
string.Concat( string.Concat(
@@ -187,7 +186,7 @@ public static class ModdedOptionsManager
RegisterOption(option, group, property.Name, pluginInfo); RegisterOption(option, group, property.Name, pluginInfo);
} }
internal static void RegisterOption( private static void RegisterOption(
IModdedOption option, IModdedOption option,
AbstractOptionGroup group, AbstractOptionGroup group,
string propertyName, string propertyName,
@@ -30,14 +30,14 @@ public class ModdedStringOption : ModdedOption<string>
/// </summary> /// </summary>
/// <param name="value">The option's string value.</param> /// <param name="value">The option's string value.</param>
/// <returns>The option's value in the index.</returns> /// <returns>The option's value in the index.</returns>
public int GetIndex(string value, int location) public int GetIndex(string value)
{ {
if (Values.Contains(value)) if (Values.Contains(value))
{ {
return Values.ToList().IndexOf(value); return Array.IndexOf(Values, value);
} }
Info($"Cannot find a valid index for {value} in {location}. Returning 0 instead. Values: {string.Join(", ", Values)}"); Info($"Cannot find a valid index for {value}. Returning -1 instead. Values: {string.Join(", ", Values)}");
return 0; return -1;
} }
/// <summary> /// <summary>
@@ -54,10 +54,10 @@ public class ModdedStringOption : ModdedOption<string>
var newVals = Values.ToList(); var newVals = Values.ToList();
newVals.Insert(index, value); newVals.Insert(index, value);
Values = newVals.ToArray(); Values = [.. newVals];
var newStrVals = StringNameValues.ToList(); var newStrVals = StringNameValues.ToList();
newStrVals.Insert(index, MiraLocaleManager.GetOrCreateLocaleString(value)); newStrVals.Insert(index, MiraLocaleManager.GetOrCreateLocaleString(value));
StringNameValues = newStrVals.ToArray(); StringNameValues = [.. newStrVals];
} }
if (Data != null) if (Data != null)
@@ -65,14 +65,14 @@ public class ModdedStringOption : ModdedOption<string>
var data = (StringGameSetting)Data; var data = (StringGameSetting)Data;
data.Values = StringNameValues; data.Values = StringNameValues;
data.Index = GetIndex(Value, 1); data.Index = GetIndex(Value);
if (OptionBehaviour != null) if (OptionBehaviour != null)
{ {
var strOpt = OptionBehaviour.TryCast<StringOption>(); var strOpt = OptionBehaviour.TryCast<StringOption>();
if (strOpt != null) if (strOpt != null)
{ {
strOpt.Values = StringNameValues; strOpt.Values = StringNameValues;
strOpt.Value = GetIndex(Value, 2); strOpt.Value = GetIndex(Value);
Warning("StringOption is valid"); Warning("StringOption is valid");
} }
else else
@@ -100,7 +100,7 @@ public class ModdedStringOption : ModdedOption<string>
/// <param name="defaultValue">The default value as a string.</param> /// <param name="defaultValue">The default value as a string.</param>
/// <param name="values">An option list of string values to use.</param> /// <param name="values">An option list of string values to use.</param>
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param> /// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
public ModdedStringOption(string title, string defaultValue, string[] values, bool includeInPreset=true) : base(title, defaultValue, includeInPreset) public ModdedStringOption(string title, string defaultValue, string[] values, bool includeInPreset = true) : base(title, defaultValue, includeInPreset)
{ {
Values = values; Values = values;
Data = ScriptableObject.CreateInstance<StringGameSetting>(); Data = ScriptableObject.CreateInstance<StringGameSetting>();
@@ -108,10 +108,10 @@ public class ModdedStringOption : ModdedOption<string>
data.Title = StringName; data.Title = StringName;
data.Type = global::OptionTypes.String; data.Type = global::OptionTypes.String;
StringNameValues = values.Select(MiraLocaleManager.GetOrCreateLocaleString).ToArray(); StringNameValues = [.. values.Select(MiraLocaleManager.GetOrCreateLocaleString)];
data.Values = StringNameValues; data.Values = StringNameValues;
data.Index = GetIndex(Value, 3); data.Index = GetIndex(Value);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -124,10 +124,10 @@ public class ModdedStringOption : ModdedOption<string>
stringOption.SetUpFromData(Data, 20); stringOption.SetUpFromData(Data, 20);
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged; stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
// SetUpFromData method doesnt work correctly so we must set the values manually // SetUpFromData method doesn't work correctly so we must set the values manually
stringOption.Title = StringName; stringOption.Title = StringName;
stringOption.Values = (Data as StringGameSetting)?.Values ?? new Il2CppStructArray<StringNames>(0); stringOption.Values = (Data as StringGameSetting)?.Values ?? new Il2CppStructArray<StringNames>(0);
stringOption.Value = GetIndex(Value, 4); stringOption.Value = GetIndex(Value);
OptionBehaviour = stringOption; OptionBehaviour = stringOption;
ModdedOptionsManager.CreatedStringOptions.TryAdd(stringOption, this); ModdedOptionsManager.CreatedStringOptions.TryAdd(stringOption, this);
@@ -162,7 +162,7 @@ public class ModdedStringOption : ModdedOption<string>
/// <inheritdoc /> /// <inheritdoc />
protected override void OnValueChanged(string newValue) protected override void OnValueChanged(string newValue)
{ {
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(GetIndex(newValue, 5)), false); HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(GetIndex(newValue)), false);
if (!OptionBehaviour) if (!OptionBehaviour)
{ {
return; return;
@@ -170,7 +170,7 @@ public class ModdedStringOption : ModdedOption<string>
if (OptionBehaviour is StringOption opt) if (OptionBehaviour is StringOption opt)
{ {
opt.Value = GetIndex(newValue, 5); opt.Value = GetIndex(newValue);
} }
} }
} }
@@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using BepInEx.Unity.IL2CPP.Utils.Collections; using BepInEx.Unity.IL2CPP.Utils.Collections;
using Il2CppInterop.Runtime.Attributes; using Il2CppInterop.Runtime.Attributes;
@@ -10,44 +11,57 @@ using UnityEngine;
namespace MiraAPI.HnsReimplemented; namespace MiraAPI.HnsReimplemented;
/// <summary>
/// A Unity script designed to help manage the HUD during HnS mode.
/// </summary>
/// <param name="cppPtr">The pointer of this instance's equivalent in the Il2Cpp domain.</param>
[RegisterInIl2Cpp] [RegisterInIl2Cpp]
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity Convention.")]
public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr) public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
{ {
/// <summary>
/// Gets the instance of the HnS hud helper.
/// </summary>
public static HideAndSeekHudHelper Instance { get; private set; } public static HideAndSeekHudHelper Instance { get; private set; }
public AudioClip FinalHideAlertSfx; private AudioClip finalHideAlertSfx;
private AudioClip finalHideCountdownSfx;
[SuppressMessage("Style", "IDE0052:Remove unread private members", Justification = "Ignore for now; tentative code.")]
private AudioClip taskFinishedSound;
public AudioClip FinalHideCountdownSfx; // private const int SECONDS_TO_BEEP = 10;
// private const float SECONDS_TO_SET_DIRTY = 1f;
private AudioClip TaskFinishedSound;
private const int SECONDS_TO_BEEP = 10;
private const float SECONDS_TO_SET_DIRTY = 1f;
private HideAndSeekTimerBar timerBar;
private float totalHideTime = float.MaxValue; private float totalHideTime = float.MaxValue;
private float currentHideTime = float.MaxValue; private float currentHideTime = float.MaxValue;
private float totalFinalHideTime = float.MaxValue; private float totalFinalHideTime = float.MaxValue;
private float currentFinalHideTime = float.MaxValue; private float currentFinalHideTime = float.MaxValue;
private float secondsSinceLastSetDirty; private float secondsSinceLastSetDirty;
private Coroutine beepCoroutine; private Coroutine beepCoroutine;
private HideAndSeekTimerBar timerBar;
private float taskDirtyTimer;
/// <summary>
/// Gets or sets the hide countdown timer.
/// </summary>
public float HideCountdown { get; set; }
/// <summary>
/// Gets a value indicating whether the game has reached the final phase.
/// </summary>
public bool IsFinalCountdown => currentHideTime <= 0f;
private void Awake() private void Awake()
{ {
Instance = this; Instance = this;
} }
public bool IsFinalCountdown /// <summary>
{ /// Checks to see if the player can use the Seeker admin.
get { return currentHideTime <= 0f; } /// </summary>
} /// <param name="player">The player to check.</param>
/// <returns>true if the player can use the admin ability.</returns>
public bool SeekerAdminMapEnabled(PlayerControl player) public bool SeekerAdminMapEnabled(PlayerControl player)
{ {
int item = Helpers.GetAlivePlayers().Count(x => !x.Data.Role.IsImpostor); int item = Helpers.GetAlivePlayers().Count(x => !x.Data.Role.IsImpostor);
@@ -59,6 +73,10 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
(GameData.Instance.PlayerCount - 1) / 3)); (GameData.Instance.PlayerCount - 1) / 3));
} }
/// <summary>
/// A event that is called when a task is completed.
/// </summary>
/// <param name="timeDeduction">The amount of time to deduct from the timer.</param>
public void OnTaskComplete(float timeDeduction) public void OnTaskComplete(float timeDeduction)
{ {
if (timerBar != null) if (timerBar != null)
@@ -69,24 +87,36 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
AdjustEscapeTimer(timeDeduction, true); AdjustEscapeTimer(timeDeduction, true);
} }
public float GetTotalRoundTime() /// <summary>
/// Gets the match duration.
/// </summary>
/// <returns>The match duration in seconds.</returns>
public static float GetTotalRoundTime()
{ {
float escapeTime = OptionGroupSingleton<HnsCrewmateOptions>.Instance.HidingTime.Value; float escapeTime = OptionGroupSingleton<HnsCrewmateOptions>.Instance.HidingTime.Value;
float finalCountdownTime = OptionGroupSingleton<HnsFinalHideOptions>.Instance.FinalHideTime.Value; float finalCountdownTime = OptionGroupSingleton<HnsFinalHideOptions>.Instance.FinalHideTime.Value;
return escapeTime + finalCountdownTime; return escapeTime + finalCountdownTime;
} }
/// <summary>
/// Gets the amount of total time remaining in the current round.
/// </summary>
/// <returns>The remaining time in seconds.</returns>
public float GetTotalTimeRemaining() public float GetTotalTimeRemaining()
{ {
return currentHideTime + currentFinalHideTime; return currentHideTime + currentFinalHideTime;
} }
/// <summary>
/// Gets how much time has passed since the start of the round.
/// </summary>
/// <returns>The elapsed time in seconds.</returns>
public float GetRoundTimeElapsed() public float GetRoundTimeElapsed()
{ {
return GetTotalRoundTime() - GetTotalTimeRemaining(); return GetTotalRoundTime() - GetTotalTimeRemaining();
} }
public void Start() private void Start()
{ {
totalHideTime = OptionGroupSingleton<HnsCrewmateOptions>.Instance.HidingTime.Value; totalHideTime = OptionGroupSingleton<HnsCrewmateOptions>.Instance.HidingTime.Value;
currentHideTime = totalHideTime; currentHideTime = totalHideTime;
@@ -97,19 +127,19 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
Object.Destroy(timerBar); Object.Destroy(timerBar);
} }
FinalHideAlertSfx = GameManagerCreator.Instance.HideAndSeekManagerPrefab.FinalHideAlertSFX; finalHideAlertSfx = GameManagerCreator.Instance.HideAndSeekManagerPrefab.FinalHideAlertSFX;
FinalHideCountdownSfx = GameManagerCreator.Instance.HideAndSeekManagerPrefab.FinalHideCountdownSFX; finalHideCountdownSfx = GameManagerCreator.Instance.HideAndSeekManagerPrefab.FinalHideCountdownSFX;
TaskFinishedSound = GameManagerCreator.Instance.HideAndSeekManagerPrefab.TaskFinishedSound; taskFinishedSound = GameManagerCreator.Instance.HideAndSeekManagerPrefab.TaskFinishedSound;
timerBar = Object.Instantiate<HideAndSeekTimerBar>( timerBar = Instantiate(
GameManagerCreator.Instance.HideAndSeekManagerPrefab.TimerBarPrefab, GameManagerCreator.Instance.HideAndSeekManagerPrefab.TimerBarPrefab,
HudManager.Instance.transform.parent); HudManager.Instance.transform.parent);
} }
public void OnGameEnd() private void OnGameEnd()
{ {
if (timerBar != null) if (timerBar != null)
{ {
Object.Destroy(timerBar.gameObject); Destroy(timerBar.gameObject);
} }
if (beepCoroutine != null) if (beepCoroutine != null)
@@ -119,10 +149,8 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
beepCoroutine = null!; beepCoroutine = null!;
} }
private float taskDirtyTimer;
public float HideCountdown { get; set; }
public void LateUpdate() private void LateUpdate()
{ {
if (!HudManager.InstanceExists) if (!HudManager.InstanceExists)
{ {
@@ -178,9 +206,11 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
HudManager.Instance.TaskPanel.SetTaskText(HudManager.Instance.tasksString.ToString()); HudManager.Instance.TaskPanel.SetTaskText(HudManager.Instance.tasksString.ToString());
} }
} }
public void FixedUpdate()
private void FixedUpdate()
{ {
secondsSinceLastSetDirty += Time.fixedDeltaTime; secondsSinceLastSetDirty += Time.fixedDeltaTime;
if (IsFinalCountdown) if (IsFinalCountdown)
{ {
AdjustFinalEscapeTimer(Time.fixedDeltaTime); AdjustFinalEscapeTimer(Time.fixedDeltaTime);
@@ -190,11 +220,11 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
AdjustEscapeTimer(Time.fixedDeltaTime, false); AdjustEscapeTimer(Time.fixedDeltaTime, false);
} }
public void OnDestroy() private void OnDestroy()
{ {
if (timerBar != null) if (timerBar != null)
{ {
Object.Destroy(timerBar); Destroy(timerBar);
} }
} }
@@ -205,7 +235,7 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
if (!playerControl.Data.Role.IsImpostor && !playerControl.Data.IsDead) if (!playerControl.Data.Role.IsImpostor && !playerControl.Data.IsDead)
{ {
playerControl.ClearTasks(); playerControl.ClearTasks();
PlayerTask.GetOrCreateTask<ImportantTextTask>(playerControl, 0).Text = PlayerTask.GetOrCreateTask<ImportantTextTask>(playerControl).Text =
DestroyableSingleton<TranslationController>.Instance.GetString(StringNames.HideActionButton); DestroyableSingleton<TranslationController>.Instance.GetString(StringNames.HideActionButton);
} }
} }
@@ -220,7 +250,7 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
} }
timerBar.StartFinalHide(); timerBar.StartFinalHide();
SoundManager.Instance.PlaySound(FinalHideAlertSfx, false, 1f, null); SoundManager.Instance.PlaySound(finalHideAlertSfx, false);
DestroyableSingleton<HudManager>.Instance.SetAlertOverlay(true); DestroyableSingleton<HudManager>.Instance.SetAlertOverlay(true);
} }
@@ -253,7 +283,7 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
{ {
float num = currentHideTime / 10f; float num = currentHideTime / 10f;
float pitch = 1.5f - num / 2f; float pitch = 1.5f - num / 2f;
SoundManager.Instance.PlaySoundImmediate(FinalHideCountdownSfx, false, 1f, pitch, null); SoundManager.Instance.PlaySoundImmediate(finalHideCountdownSfx, false, 1f, pitch);
yield return new WaitForSeconds(1f); yield return new WaitForSeconds(1f);
} }
@@ -262,11 +292,9 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
{ {
float num2 = currentFinalHideTime / 10f; float num2 = currentFinalHideTime / 10f;
float pitch2 = 1.5f - num2 / 2f; float pitch2 = 1.5f - num2 / 2f;
SoundManager.Instance.PlaySoundImmediate(FinalHideCountdownSfx, false, 1f, pitch2, null); SoundManager.Instance.PlaySoundImmediate(finalHideCountdownSfx, false, 1f, pitch2);
yield return new WaitForSeconds(1f); yield return new WaitForSeconds(1f);
} }
yield break;
} }
private void AdjustFinalEscapeTimer(float timeDeduction) private void AdjustFinalEscapeTimer(float timeDeduction)
@@ -280,6 +308,10 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
} }
} }
/// <summary>
/// Checks to see if all timers have expired.
/// </summary>
/// <returns>true if all times have expired.</returns>
public bool AllTimersExpired() public bool AllTimersExpired()
{ {
return currentHideTime <= 0f && currentFinalHideTime <= 0f; return currentHideTime <= 0f && currentFinalHideTime <= 0f;
+28 -21
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using MiraAPI.GameOptions; using MiraAPI.GameOptions;
using MiraAPI.HnsReimplemented.Options; using MiraAPI.HnsReimplemented.Options;
@@ -8,19 +9,22 @@ using UnityEngine;
namespace MiraAPI.HnsReimplemented; namespace MiraAPI.HnsReimplemented;
/// <summary>
/// A Unity script designed to mimic the base game's player danger meter during Hide and Seek.
/// </summary>
/// <param name="cppPtr">The pointer of this instance's equivalent in the Il2Cpp domain.</param>
[RegisterInIl2Cpp] [RegisterInIl2Cpp]
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity Convention.")]
public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr) public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr)
{ {
public static HnsDangerMeter Instance; /// <summary>
/// Gets the instance of the danger meter.
private void Awake() /// </summary>
{ public static HnsDangerMeter Instance { get; private set; }
Instance = this;
}
private DangerMeter dangerMeter; private DangerMeter dangerMeter;
private List<PlayerControl> impostors = []; private List<PlayerControl>? impostors = [];
private float scaryMusicDistance; private float scaryMusicDistance;
@@ -34,7 +38,12 @@ public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr)
private float firstCrossfadeCountdown; private float firstCrossfadeCountdown;
public void FixedUpdate() private void Awake()
{
Instance = this;
}
private void FixedUpdate()
{ {
PlayerControl localPlayer = PlayerControl.LocalPlayer; PlayerControl localPlayer = PlayerControl.LocalPlayer;
if (impostors == null || localPlayer == null) if (impostors == null || localPlayer == null)
@@ -50,15 +59,14 @@ public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr)
float num = float.MaxValue; float num = float.MaxValue;
foreach (PlayerControl playerControl in impostors) foreach (PlayerControl playerControl in impostors)
{ {
if (!(playerControl == null)) if (playerControl == null)
{ continue;
float sqrMagnitude = (playerControl.transform.position - localPlayer.transform.position).sqrMagnitude; float sqrMagnitude = (playerControl.transform.position - localPlayer.transform.position).sqrMagnitude;
if (sqrMagnitude < scaryMusicDistance && num > sqrMagnitude) if (sqrMagnitude < scaryMusicDistance && num > sqrMagnitude)
{ {
num = sqrMagnitude; num = sqrMagnitude;
} }
} }
}
if (HideAndSeekHudHelper.Instance.HideCountdown > 0f) if (HideAndSeekHudHelper.Instance.HideCountdown > 0f)
{ {
@@ -71,7 +79,7 @@ public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr)
{ {
firstMusicActivation = false; firstMusicActivation = false;
firstCrossfadeCountdown = 3f; firstCrossfadeCountdown = 3f;
HnsMusicHandler.Instance.SetMusicCrossfadeSpeed(0.6f); HnsMusicHandler.Instance.SetMusicCrossFadeSpeed(0.6f);
} }
if (firstCrossfadeCountdown > 0f) if (firstCrossfadeCountdown > 0f)
@@ -79,7 +87,7 @@ public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr)
firstCrossfadeCountdown -= Time.deltaTime; firstCrossfadeCountdown -= Time.deltaTime;
if (firstCrossfadeCountdown <= 0f) if (firstCrossfadeCountdown <= 0f)
{ {
HnsMusicHandler.Instance.SetMusicCrossfadeSpeed(5f); HnsMusicHandler.Instance.SetMusicCrossFadeSpeed(5f);
} }
} }
@@ -115,6 +123,9 @@ public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr)
dangerMeter.SetDangerValue(dangerLevel1, dangerLevel2); dangerMeter.SetDangerValue(dangerLevel1, dangerLevel2);
} }
/// <summary>
/// An event that is executed when the game starts.
/// </summary>
public void OnGameStart() public void OnGameStart()
{ {
firstMusicActivation = true; firstMusicActivation = true;
@@ -124,19 +135,15 @@ public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr)
dangerMeter.gameObject.SetActive(true); dangerMeter.gameObject.SetActive(true);
} }
impostors = Helpers.GetAlivePlayers().Where(x => x.Data.Role.IsImpostor).ToList(); impostors = [.. Helpers.GetAlivePlayers().Where(x => x.Data.Role.IsImpostor)];
var baseSpeed = OptionGroupSingleton<HnsCrewmateOptions>.Instance.PlayerSpeed.Value; var baseSpeed = OptionGroupSingleton<HnsCrewmateOptions>.Instance.PlayerSpeed.Value;
scaryMusicDistance = 55f * scaryMusicDistance = 55f * baseSpeed;
baseSpeed; veryScaryMusicDistance = 15f * baseSpeed;
veryScaryMusicDistance = 15f * if (scaryMusicDistance >= veryScaryMusicDistance) return;
baseSpeed;
if (scaryMusicDistance < veryScaryMusicDistance)
{
float num = veryScaryMusicDistance; float num = veryScaryMusicDistance;
float num2 = scaryMusicDistance; float num2 = scaryMusicDistance;
scaryMusicDistance = num; scaryMusicDistance = num;
veryScaryMusicDistance = num2; veryScaryMusicDistance = num2;
} }
}
} }
+64 -34
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Amongus.GameModes.HideAndSeek; using Amongus.GameModes.HideAndSeek;
using MiraAPI.GameOptions; using MiraAPI.GameOptions;
using MiraAPI.HnsReimplemented.Options; using MiraAPI.HnsReimplemented.Options;
@@ -7,15 +8,18 @@ using UnityEngine;
namespace MiraAPI.HnsReimplemented; namespace MiraAPI.HnsReimplemented;
/// <summary>
/// A Unity script designed to handle the music during Hide and Seek.
/// </summary>
/// <param name="cppPtr">The pointer of this instance's equivalent in the Il2Cpp domain.</param>
[RegisterInIl2Cpp] [RegisterInIl2Cpp]
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")]
public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr) public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr)
{ {
public static HnsMusicHandler Instance; /// <summary>
/// Gets the instance of the music handler.
private void Awake() /// </summary>
{ public static HnsMusicHandler Instance { get; private set; }
Instance = this;
}
private HideAndSeekMusicCollection musicCollection; private HideAndSeekMusicCollection musicCollection;
@@ -41,18 +45,46 @@ public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr)
private float musicLerpSpeed = 5f; private float musicLerpSpeed = 5f;
public void Start() private readonly Dictionary<LogicHnSMusic.HideAndSeekMusicTrack, string> musicNames = new()
{
{
LogicHnSMusic.HideAndSeekMusicTrack.Normal,
"HnS_Music_Normal"
},
{
LogicHnSMusic.HideAndSeekMusicTrack.Task,
"HnS_Music_Task"
},
{
LogicHnSMusic.HideAndSeekMusicTrack.DangerLevel1,
"HnS_Music_DangerLevel1"
},
{
LogicHnSMusic.HideAndSeekMusicTrack.DangerLevel2,
"HnS_Music_DangerLevel2"
},
};
private void Awake()
{
Instance = this;
}
private void Start()
{ {
musicCollection = GameManagerCreator.Instance.HideAndSeekManagerPrefab.MusicCollection; musicCollection = GameManagerCreator.Instance.HideAndSeekManagerPrefab.MusicCollection;
} }
/// <summary>
/// An event that is executed when the round starts.
/// </summary>
public void OnGameStart() public void OnGameStart()
{ {
InitMusic(); InitMusic();
ResetMusic(); ResetMusic();
} }
public void OnDestroy() private void OnDestroy()
{ {
ResetMusic(); ResetMusic();
} }
@@ -107,6 +139,9 @@ public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr)
SyncMusic(); SyncMusic();
} }
/// <summary>
/// Gets the music with the intro.
/// </summary>
public void StartMusicWithIntro() public void StartMusicWithIntro()
{ {
if (PlayerControl.LocalPlayer.Data.Role.IsImpostor) if (PlayerControl.LocalPlayer.Data.Role.IsImpostor)
@@ -123,12 +158,16 @@ public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr)
} }
} }
/// <summary>
/// Sets the current task state to alter music behaviour.
/// </summary>
/// <param name="isDoingTask">The new value of the state.</param>
public void SetTaskState(bool isDoingTask) public void SetTaskState(bool isDoingTask)
{ {
isDoingTask = isDoingTask; this.isDoingTask = isDoingTask;
} }
public void FixedUpdate() private void FixedUpdate()
{ {
if (normalSource == null || taskSource == null || dangerLevel1Source == null || if (normalSource == null || taskSource == null || dangerLevel1Source == null ||
dangerLevel2Source == null) dangerLevel2Source == null)
@@ -167,16 +206,28 @@ public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr)
lastMusicSyncTime = Time.unscaledTime; lastMusicSyncTime = Time.unscaledTime;
} }
/// <summary>
/// Resets the music currently playing.
/// </summary>
public void ResetMusic() public void ResetMusic()
{ {
SetMusicValues(0f, 0f); SetMusicValues(0f, 0f);
} }
public void SetMusicCrossfadeSpeed(float lerpSpeed) /// <summary>
/// Sets the music crossfade speed.
/// </summary>
/// <param name="lerpSpeed">The new speed.</param>
public void SetMusicCrossFadeSpeed(float lerpSpeed)
{ {
musicLerpSpeed = lerpSpeed; musicLerpSpeed = lerpSpeed;
} }
/// <summary>
/// Sets the current music value based on the danger level.
/// </summary>
/// <param name="dangerLevel1">The first danger level.</param>
/// <param name="dangerLevel2">The second danger level.</param>
public void SetMusicValues(float dangerLevel1, float dangerLevel2) public void SetMusicValues(float dangerLevel1, float dangerLevel2)
{ {
if (PlayerControl.LocalPlayer != null && PlayerControl.LocalPlayer.Data.Role.IsImpostor) if (PlayerControl.LocalPlayer != null && PlayerControl.LocalPlayer.Data.Role.IsImpostor)
@@ -190,8 +241,8 @@ public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr)
return; return;
} }
normalVolume = (isDoingTask ? 0f : 1f); normalVolume = isDoingTask ? 0f : 1f;
taskVolume = (isDoingTask ? 1f : 0f); taskVolume = isDoingTask ? 1f : 0f;
dangerLevel1Volume = 0f; dangerLevel1Volume = 0f;
dangerLevel2Volume = 0f; dangerLevel2Volume = 0f;
if (dangerLevel1 > 0f) if (dangerLevel1 > 0f)
@@ -213,25 +264,4 @@ public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr)
dangerLevel1Volume = 1f - dangerLevel2; dangerLevel1Volume = 1f - dangerLevel2;
} }
} }
private readonly Dictionary<LogicHnSMusic.HideAndSeekMusicTrack, string> musicNames =
new Dictionary<LogicHnSMusic.HideAndSeekMusicTrack, string>
{
{
LogicHnSMusic.HideAndSeekMusicTrack.Normal,
"HnS_Music_Normal"
},
{
LogicHnSMusic.HideAndSeekMusicTrack.Task,
"HnS_Music_Task"
},
{
LogicHnSMusic.HideAndSeekMusicTrack.DangerLevel1,
"HnS_Music_DangerLevel1"
},
{
LogicHnSMusic.HideAndSeekMusicTrack.DangerLevel2,
"HnS_Music_DangerLevel2"
},
};
} }
@@ -5,12 +5,17 @@ using MiraAPI.Utilities;
namespace MiraAPI.HnsReimplemented.Options; namespace MiraAPI.HnsReimplemented.Options;
/// <inheritdoc /> /// <summary>
/// Gets or sets the crewmate options for Hide and Seek.
/// </summary>
public class HnsCrewmateOptions : AbstractOptionGroup<HideAndSeekMode> public class HnsCrewmateOptions : AbstractOptionGroup<HideAndSeekMode>
{ {
/// <inheritdoc /> /// <inheritdoc />
public override string GroupName => "Crewmates"; public override string GroupName => "Crewmates";
/// <summary>
/// Gets or sets the player speed.
/// </summary>
public ModdedNumberOption PlayerSpeed { get; set; } = new( public ModdedNumberOption PlayerSpeed { get; set; } = new(
"Player Speed", "Player Speed",
1f, 1f,
@@ -22,6 +27,9 @@ public class HnsCrewmateOptions : AbstractOptionGroup<HideAndSeekMode>
MiraNumberSuffixes.Multiplier, MiraNumberSuffixes.Multiplier,
"0.00"); "0.00");
/// <summary>
/// Gets or sets the hiding time.
/// </summary>
public ModdedNumberOption HidingTime { get; set; } = new( public ModdedNumberOption HidingTime { get; set; } = new(
"Hiding Time", "Hiding Time",
200, 200,
@@ -32,6 +40,9 @@ public class HnsCrewmateOptions : AbstractOptionGroup<HideAndSeekMode>
"#", "#",
MiraNumberSuffixes.Seconds); MiraNumberSuffixes.Seconds);
/// <summary>
/// Gets or sets the limits of a crewmate's vision.
/// </summary>
public ModdedNumberOption CrewmateVision { get; set; } = new( public ModdedNumberOption CrewmateVision { get; set; } = new(
"Crewmate Vision", "Crewmate Vision",
0.6f, 0.6f,
@@ -43,33 +54,16 @@ public class HnsCrewmateOptions : AbstractOptionGroup<HideAndSeekMode>
MiraNumberSuffixes.Multiplier, MiraNumberSuffixes.Multiplier,
"0.00"); "0.00");
public ModdedNumberOption MaxVentUses { get; set; } = new( /// <summary>
"Max Vent Uses", /// Gets or sets a flag that toggles flashlight vision.
1, /// </summary>
0,
5,
1,
"#",
"#",
MiraNumberSuffixes.None);
public ModdedNumberOption MaxTimeInVent { get; set; } = new(
"Max Time in Vent",
3,
1,
10,
1,
"#",
"#",
MiraNumberSuffixes.Seconds)
{
Visible = () => (int)OptionGroupSingleton<HnsCrewmateOptions>.Instance.MaxVentUses.Value > 0,
};
public ModdedToggleOption FlashlightMode { get; set; } = new( public ModdedToggleOption FlashlightMode { get; set; } = new(
"Flashlight Mode", "Flashlight Mode",
true); true);
/// <summary>
/// Gets or sets the range of a crewmate's flashlight.
/// </summary>
public ModdedNumberOption CrewmateFlashlightSize { get; set; } = new( public ModdedNumberOption CrewmateFlashlightSize { get; set; } = new(
"Crewmate Flashlight Size", "Crewmate Flashlight Size",
0.35f, 0.35f,
@@ -83,6 +77,38 @@ public class HnsCrewmateOptions : AbstractOptionGroup<HideAndSeekMode>
Visible = () => OptionGroupSingleton<HnsCrewmateOptions>.Instance.FlashlightMode.Value, Visible = () => OptionGroupSingleton<HnsCrewmateOptions>.Instance.FlashlightMode.Value,
}; };
/// <summary>
/// Gets or sets the maximum number of times a crewmate can vent.
/// </summary>
public ModdedNumberOption MaxVentUses { get; set; } = new(
"Max Vent Uses",
1,
0,
5,
1,
"#",
"#",
MiraNumberSuffixes.None);
/// <summary>
/// Gets or sets the maximum amount of time a crewmate can spend inside a vent.
/// </summary>
public ModdedNumberOption MaxTimeInVent { get; set; } = new(
"Max Time in Vent",
3,
1,
10,
1,
"#",
"#",
MiraNumberSuffixes.Seconds)
{
Visible = () => (int)OptionGroupSingleton<HnsCrewmateOptions>.Instance.MaxVentUses.Value > 0,
};
/// <summary>
/// Gets or sets the visibility of player names.
/// </summary>
public ModdedToggleOption ShowNames { get; set; } = new( public ModdedToggleOption ShowNames { get; set; } = new(
"Show Names", "Show Names",
false); false);
@@ -5,12 +5,17 @@ using MiraAPI.Utilities;
namespace MiraAPI.HnsReimplemented.Options; namespace MiraAPI.HnsReimplemented.Options;
/// <inheritdoc /> /// <summary>
/// Gets or sets the Final Hide options for Hide and Seek.
/// </summary>
public class HnsFinalHideOptions : AbstractOptionGroup<HideAndSeekMode> public class HnsFinalHideOptions : AbstractOptionGroup<HideAndSeekMode>
{ {
/// <inheritdoc /> /// <inheritdoc />
public override string GroupName => "Final Hide"; public override string GroupName => "Final Hide";
/// <summary>
/// Gets or sets the duration of the Final Hide phase.
/// </summary>
public ModdedNumberOption FinalHideTime { get; set; } = new( public ModdedNumberOption FinalHideTime { get; set; } = new(
"Hiding Time", "Hiding Time",
50, 50,
@@ -21,10 +26,9 @@ public class HnsFinalHideOptions : AbstractOptionGroup<HideAndSeekMode>
"#", "#",
MiraNumberSuffixes.Seconds); MiraNumberSuffixes.Seconds);
public ModdedToggleOption FinalHidePings { get; set; } = new( /// <summary>
"Final Hide Pings", /// Gets or sets the Seeker's speed when the Final Hide phase begins.
true); /// </summary>
public ModdedNumberOption FinalHideImpostorSpeed { get; set; } = new( public ModdedNumberOption FinalHideImpostorSpeed { get; set; } = new(
"Final Hide Impostor Speed", "Final Hide Impostor Speed",
1.2f, 1.2f,
@@ -36,6 +40,16 @@ public class HnsFinalHideOptions : AbstractOptionGroup<HideAndSeekMode>
MiraNumberSuffixes.Multiplier, MiraNumberSuffixes.Multiplier,
"0.00"); "0.00");
/// <summary>
/// Gets or sets whether the Seeker sees the Final hide player pings.
/// </summary>
public ModdedToggleOption FinalHidePings { get; set; } = new(
"Final Hide Pings",
true);
/// <summary>
/// Gets or sets the interval between each ping.
/// </summary>
public ModdedNumberOption PingInterval { get; set; } = new( public ModdedNumberOption PingInterval { get; set; } = new(
"Ping Interval", "Ping Interval",
6, 6,
@@ -46,6 +60,9 @@ public class HnsFinalHideOptions : AbstractOptionGroup<HideAndSeekMode>
"#", "#",
MiraNumberSuffixes.Seconds); MiraNumberSuffixes.Seconds);
/// <summary>
/// Gets or sets whether the Seeker can see players on an admin map.
/// </summary>
public ModdedToggleOption FinalHideSeekMap { get; set; } = new( public ModdedToggleOption FinalHideSeekMap { get; set; } = new(
"Final Hide Seek Map", "Final Hide Seek Map",
true); true);
@@ -5,15 +5,23 @@ using MiraAPI.Utilities;
namespace MiraAPI.HnsReimplemented.Options; namespace MiraAPI.HnsReimplemented.Options;
/// <inheritdoc /> /// <summary>
/// Gets or sets the seeker settings on Hide and Seek.
/// </summary>
public class HnsImpostorOptions : AbstractOptionGroup<HideAndSeekMode> public class HnsImpostorOptions : AbstractOptionGroup<HideAndSeekMode>
{ {
/// <inheritdoc /> /// <inheritdoc />
public override string GroupName => "Impostors"; public override string GroupName => "Impostors";
/// <summary>
/// Gets or sets the player who will be the seeker.
/// </summary>
public ModdedPlayerOption SelectedSeeker { get; set; } = new( public ModdedPlayerOption SelectedSeeker { get; set; } = new(
"Forced Impostor"); "Forced Impostor");
/// <summary>
/// Gets or sets the range of a seeker's vision.
/// </summary>
public ModdedNumberOption ImpostorVision { get; set; } = new( public ModdedNumberOption ImpostorVision { get; set; } = new(
"Impostor Vision", "Impostor Vision",
0.6f, 0.6f,
@@ -25,6 +33,9 @@ public class HnsImpostorOptions : AbstractOptionGroup<HideAndSeekMode>
MiraNumberSuffixes.Multiplier, MiraNumberSuffixes.Multiplier,
"0.00"); "0.00");
/// <summary>
/// Gets or sets the range of a seeker's flashlight.
/// </summary>
public ModdedNumberOption ImpostorFlashlightSize { get; set; } = new( public ModdedNumberOption ImpostorFlashlightSize { get; set; } = new(
"Impostor Flashlight Size", "Impostor Flashlight Size",
0.35f, 0.35f,
@@ -5,12 +5,17 @@ using MiraAPI.Utilities;
namespace MiraAPI.HnsReimplemented.Options; namespace MiraAPI.HnsReimplemented.Options;
/// <inheritdoc /> /// <summary>
/// Gets or sets the task options for Hide and Seek.
/// </summary>
public class HnsTaskOptions : AbstractOptionGroup<HideAndSeekMode> public class HnsTaskOptions : AbstractOptionGroup<HideAndSeekMode>
{ {
/// <inheritdoc /> /// <inheritdoc />
public override string GroupName => "Tasks"; public override string GroupName => "Tasks";
/// <summary>
/// Gets or sets the umber of common tasks.
/// </summary>
public ModdedNumberOption CommonTasks { get; set; } = new( public ModdedNumberOption CommonTasks { get; set; } = new(
"# Common Tasks", "# Common Tasks",
1, 1,
@@ -21,6 +26,9 @@ public class HnsTaskOptions : AbstractOptionGroup<HideAndSeekMode>
"#", "#",
MiraNumberSuffixes.None); MiraNumberSuffixes.None);
/// <summary>
/// Gets or sets the number of long tasks.
/// </summary>
public ModdedNumberOption LongTasks { get; set; } = new( public ModdedNumberOption LongTasks { get; set; } = new(
"# Long Tasks", "# Long Tasks",
1, 1,
@@ -31,6 +39,9 @@ public class HnsTaskOptions : AbstractOptionGroup<HideAndSeekMode>
"#", "#",
MiraNumberSuffixes.None); MiraNumberSuffixes.None);
/// <summary>
/// Gets or sets the number of short tasks.
/// </summary>
public ModdedNumberOption ShortTasks { get; set; } = new( public ModdedNumberOption ShortTasks { get; set; } = new(
"# Short Tasks", "# Short Tasks",
2, 2,
+2 -2
View File
@@ -9,7 +9,6 @@ using Reactor.Utilities.Attributes;
using Reactor.Utilities.Extensions; using Reactor.Utilities.Extensions;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace MiraAPI.Hud; namespace MiraAPI.Hud;
@@ -21,6 +20,8 @@ namespace MiraAPI.Hud;
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention.")] [SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention.")]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Unity Convention.")] [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Unity Convention.")]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Unity Convention.")] [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Unity Convention.")]
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")]
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member (Justification: Unity fields to mirror base game ShapeshifterMinigame; not worth documenting)
public class CustomPlayerMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr) public class CustomPlayerMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr)
{ {
public ShapeshifterPanel panelPrefab; public ShapeshifterPanel panelPrefab;
@@ -68,7 +69,6 @@ public class CustomPlayerMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr)
return customMenu; return customMenu;
} }
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")]
private void OnDisable() private void OnDisable()
{ {
ControllerManager.Instance.CloseOverlayMenu(name); ControllerManager.Instance.CloseOverlayMenu(name);
+34 -29
View File
@@ -1,4 +1,5 @@
using BepInEx.Unity.IL2CPP.Utils.Collections; using System.Diagnostics.CodeAnalysis;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using InnerNet; using InnerNet;
using MiraAPI.LocalSettings; using MiraAPI.LocalSettings;
using MiraAPI.Modifiers.ModifierDisplay; using MiraAPI.Modifiers.ModifierDisplay;
@@ -9,9 +10,13 @@ using UnityEngine;
namespace MiraAPI.Hud; namespace MiraAPI.Hud;
[RegisterInIl2Cpp] [RegisterInIl2Cpp]
public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr) [SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity Convention.")]
[SuppressMessage("Critical Code Smell", "S2223:Non-constant static fields should not be visible", Justification = "Is internal code. Property-level protections are not required.")]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Read above.")]
internal sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
{ {
public static MiraHudHelper Instance { get; private set; } public static MiraHudHelper Instance { get; private set; }
public static GameObject ModifierDisplayObject; public static GameObject ModifierDisplayObject;
public static GameObject VanillaMatchInfoButton; public static GameObject VanillaMatchInfoButton;
public static bool ModifierDisplayOnRight; public static bool ModifierDisplayOnRight;
@@ -25,20 +30,25 @@ public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
public static GameObject SubmergedFloorButton; public static GameObject SubmergedFloorButton;
public static SpriteRenderer SubmergedFloorButtonRenderer; public static SpriteRenderer SubmergedFloorButtonRenderer;
public static SpriteRenderer SubmergedFloorButtonRendererHover; public static SpriteRenderer SubmergedFloorButtonRendererHover;
public void Awake()
public static readonly Vector3 BelowOptionPos = new(0.435f, 1.25f, 0f);
public static readonly Vector3 FullTopPos = new(0.435f, 0.475f, 0f);
private void Awake()
{ {
Instance = this; Instance = this;
} }
public void Start() private void Start()
{ {
MiraApiSettings.OldButtonScaleFactor = MiraApiSettings.OldButtonScaleFactor =
LocalSettingsTabSingleton<MiraApiSettings>.Instance.TopRightButtonsFactorSlider.Value; LocalSettingsTabSingleton<MiraApiSettings>.Instance.TopRightButtonsFactorSlider.Value;
StartCoroutine(MiraApiSettings.CoResizeSettingsUI().WrapToIl2Cpp()); StartCoroutine(MiraApiSettings.CoResizeSettingsUI().WrapToIl2Cpp());
} }
#pragma warning disable S2325
#pragma warning disable CA1822 [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Unity script method.")]
public void FixedUpdate() [SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Read above.")]
private void FixedUpdate()
{ {
if (!HudManager.InstanceExists || !PlayerControl.LocalPlayer || !PlayerControl.LocalPlayer.Data) if (!HudManager.InstanceExists || !PlayerControl.LocalPlayer || !PlayerControl.LocalPlayer.Data)
{ {
@@ -60,11 +70,7 @@ public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
} }
UpdateSubmergedButtons(instance); UpdateSubmergedButtons(instance);
} }
#pragma warning restore CA1822
#pragma warning restore S2325
public static Vector3 BelowOptionPos = new(0.435f, 1.25f, 0f);
public static Vector3 FullTopPos = new(0.435f, 0.475f, 0f);
public static void CreateUiRow(HudManager instance) public static void CreateUiRow(HudManager instance)
{ {
if (!UiTopRight) if (!UiTopRight)
@@ -129,8 +135,9 @@ public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
instance.Chat.chatNotifyDot = iconContainer.transform.GetChild(0).GetComponent<SpriteRenderer>(); instance.Chat.chatNotifyDot = iconContainer.transform.GetChild(0).GetComponent<SpriteRenderer>();
} }
if (UiTopRight && UiGrid) if (!UiTopRight || !UiGrid)
{ return;
var isChatButtonVisible = HudManager.Instance.Chat.isActiveAndEnabled; var isChatButtonVisible = HudManager.Instance.Chat.isActiveAndEnabled;
instance.Chat.chatButton.gameObject.SetActive(isChatButtonVisible); instance.Chat.chatButton.gameObject.SetActive(isChatButtonVisible);
if (VanillaMatchInfoButton) if (VanillaMatchInfoButton)
@@ -138,16 +145,16 @@ public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
VanillaMatchInfoButton.SetActive(!GameSettingMenu.Instance && !Minigame.Instance); VanillaMatchInfoButton.SetActive(!GameSettingMenu.Instance && !Minigame.Instance);
} }
} }
}
public static void UpdateSubmergedButtons(HudManager instance) public static void UpdateSubmergedButtons(HudManager instance)
{ {
if (ModCompatibility.IsSubmerged() && !SubmergedFloorButton && ExtraUiTopRight) if (!ModCompatibility.IsSubmerged() || SubmergedFloorButton || !ExtraUiTopRight || SubmergedFloorButton || !ExtraUiTopRight)
{ return;
if (!SubmergedFloorButton && ExtraUiTopRight)
{
var transform = instance.MapButton.transform.parent.Find(instance.MapButton.name + "(Clone)"); var transform = instance.MapButton.transform.parent.Find(instance.MapButton.name + "(Clone)");
if (transform != null) if (transform == null)
{ return;
SubmergedFloorButton = transform.gameObject; SubmergedFloorButton = transform.gameObject;
SubmergedFloorButton.transform.SetParent(ExtraUiTopRight.transform, false); SubmergedFloorButton.transform.SetParent(ExtraUiTopRight.transform, false);
@@ -158,14 +165,12 @@ public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
MiraApiSettings.SetUpButtonPositions(); MiraApiSettings.SetUpButtonPositions();
} }
}
}
}
public static void AdjustModifierTab() public static void AdjustModifierTab()
{ {
if (!ModifierDisplayObject && UiTopRight && ExtraUiTopRight && ModifierDisplayComponent.Instance) if (ModifierDisplayObject || !UiTopRight || !ExtraUiTopRight || !ModifierDisplayComponent.Instance)
{ return;
ModifierDisplayObject = ModifierDisplayComponent.Instance?.gameObject ?? null!; ModifierDisplayObject = ModifierDisplayComponent.Instance?.gameObject ?? null!;
ModifierDisplayOnRight = !LocalSettingsTabSingleton<MiraApiSettings>.Instance.ModifiersHudLeftSide.Value; ModifierDisplayOnRight = !LocalSettingsTabSingleton<MiraApiSettings>.Instance.ModifiersHudLeftSide.Value;
if (ModifierDisplayOnRight) if (ModifierDisplayOnRight)
@@ -179,11 +184,12 @@ public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
} }
MiraApiSettings.SetUpButtonPositions(); MiraApiSettings.SetUpButtonPositions();
} }
}
public static void CreateNewUiRow(HudManager instance) public static void CreateNewUiRow(HudManager instance)
{ {
if (!ExtraUiTopRight && UiTopRight) if (ExtraUiTopRight || !UiTopRight)
{ return;
ExtraUiTopRight = new GameObject("ExtraUiTopRight") ExtraUiTopRight = new GameObject("ExtraUiTopRight")
{ {
layer = UiTopRight.layer, layer = UiTopRight.layer,
@@ -199,5 +205,4 @@ public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
ExtraUiAspectPos.DistanceFromEdge = BelowOptionPos; ExtraUiAspectPos.DistanceFromEdge = BelowOptionPos;
ExtraUiGrid.Start(); ExtraUiGrid.Start();
} }
}
} }
@@ -7,6 +7,8 @@ namespace MiraAPI.LocalSettings.Attributes;
/// <summary> /// <summary>
/// Creates a <see cref="LocalToggleSetting"/> for the <see cref="ConfigEntry{T}"/>. /// Creates a <see cref="LocalToggleSetting"/> for the <see cref="ConfigEntry{T}"/>.
/// </summary> /// </summary>
/// <param name="name">The name of the setting.</param>
/// <param name="description">The description of the setting.</param>
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class LocalToggleSettingAttribute( public class LocalToggleSettingAttribute(
string? name = null, string? name = null,
+5 -2
View File
@@ -59,9 +59,9 @@ public class LocalSettingsButton(string text, Action onClick)
button.name = Text; button.name = Text;
button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
rollover.OutColor = Tab!.TabAppearance.ButtonColor; rollover.OutColor = Tab!.TabAppearance.ButtonColor;
rollover.OverColor = Tab!.TabAppearance.ButtonHoverColor; rollover.OverColor = Tab.TabAppearance.ButtonHoverColor;
rollover.Target = background; rollover.Target = background;
background.color = Tab!.TabAppearance.ButtonColor; background.color = Tab.TabAppearance.ButtonColor;
button.OnClick.AddListener((UnityAction)OnClick); button.OnClick.AddListener((UnityAction)OnClick);
background.transform.localScale = new Vector3(1, 1.25f, 1); background.transform.localScale = new Vector3(1, 1.25f, 1);
@@ -79,6 +79,9 @@ public class LocalSettingsButton(string text, Action onClick)
return button.gameObject; return button.gameObject;
} }
/// <summary>
/// Refreshes the button.
/// </summary>
public void RefreshButton() public void RefreshButton()
{ {
_btnText.text = Text.Translate(); _btnText.text = Text.Translate();
+1 -3
View File
@@ -197,7 +197,7 @@ public abstract class LocalSettingsTab(ConfigFile config)
ref contentOrder, ref contentOrder,
contentIndex == Buttons.Count); contentIndex == Buttons.Count);
obj!.GetComponentsInChildren<SpriteRenderer>(true).Do(x => obj.GetComponentsInChildren<SpriteRenderer>(true).Do(x =>
{ {
x.maskInteraction = SpriteMaskInteraction.VisibleInsideMask; x.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
x.sortingOrder = 150; x.sortingOrder = 150;
@@ -277,10 +277,8 @@ public abstract class LocalSettingsTab(ConfigFile config)
{ {
if (!tabButtonObject.Content.gameObject.activeSelf) if (!tabButtonObject.Content.gameObject.activeSelf)
{ {
#pragma warning disable S125 // Sections of code should not be commented out
// tabButtonObject.Button.color = TabColor; // tabButtonObject.Button.color = TabColor;
// tabButtonObject.Rollover.OutColor = TabColor; // tabButtonObject.Rollover.OutColor = TabColor;
#pragma warning restore S125 // Sections of code should not be commented out
} }
tabButton.transform.localPosition = new Vector3(2.4f, 2.1f - tabOffset, 5.5f); tabButton.transform.localPosition = new Vector3(2.4f, 2.1f - tabOffset, 5.5f);
@@ -80,8 +80,8 @@ public class LocalEnumSetting(
button.name = Name; button.name = Name;
button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
rollover.OutColor = Tab!.TabAppearance.EnumColor; rollover.OutColor = Tab!.TabAppearance.EnumColor;
rollover.OverColor = Tab!.TabAppearance.EnumHoverColor; rollover.OverColor = Tab.TabAppearance.EnumHoverColor;
background.color = Tab!.TabAppearance.EnumColor; background.color = Tab.TabAppearance.EnumColor;
button.OnClick.AddListener((UnityAction)(() => button.OnClick.AddListener((UnityAction)(() =>
{ {
@@ -90,8 +90,8 @@ public class LocalNumberSetting(
button.name = Name; button.name = Name;
button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
rollover.OutColor = Tab!.TabAppearance.NumberColor; rollover.OutColor = Tab!.TabAppearance.NumberColor;
rollover.OverColor = Tab!.TabAppearance.NumberHoverColor; rollover.OverColor = Tab.TabAppearance.NumberHoverColor;
background.color = Tab!.TabAppearance.NumberColor; background.color = Tab.TabAppearance.NumberColor;
button.OnClick.AddListener((UnityAction)(() => button.OnClick.AddListener((UnityAction)(() =>
{ {
@@ -58,7 +58,7 @@ public abstract class LocalSettingBase<T> : ILocalSetting
public abstract void RefreshOption(); public abstract void RefreshOption();
/// <summary> /// <summary>
/// Returns the formated string to use in the text of the setting. /// Returns the formatted string to use in the text of the setting.
/// </summary> /// </summary>
/// <returns>The value text.</returns> /// <returns>The value text.</returns>
protected virtual string GetValueText() protected virtual string GetValueText()
@@ -79,8 +79,8 @@ public class LocalSliderSetting(
newSlider.name = Name; newSlider.name = Name;
newSlider.Range = new FloatRange(-1.5f, 1.5f); newSlider.Range = new FloatRange(-1.5f, 1.5f);
newSlider.SetValue(Mathf.InverseLerp(SliderRange.min, SliderRange.max, GetValue())); newSlider.SetValue(Mathf.InverseLerp(SliderRange.min, SliderRange.max, GetValue()));
rollover.OutColor = Tab!.TabAppearance.SliderColor; rollover.OutColor = Tab.TabAppearance.SliderColor;
rollover.OverColor = Tab!.TabAppearance.SliderHoverColor; rollover.OverColor = Tab.TabAppearance.SliderHoverColor;
newSlider.Title.transform.localPosition = new Vector3(0.5f, 0, -1f); newSlider.Title.transform.localPosition = new Vector3(0.5f, 0, -1f);
newSlider.Title.horizontalAlignment = DisplayValue ? HorizontalAlignmentOptions.Left : HorizontalAlignmentOptions.Center; newSlider.Title.horizontalAlignment = DisplayValue ? HorizontalAlignmentOptions.Left : HorizontalAlignmentOptions.Center;
newSlider.Title.text = GetValueText(); newSlider.Title.text = GetValueText();
@@ -50,13 +50,13 @@ public class LocalToggleSetting(
toggleObject.name = Name.Translate(); toggleObject.name = Name.Translate();
toggleObject.Background.color = GetValue() ? Tab!.TabAppearance.ToggleActiveColor : Tab!.TabAppearance.ToggleInactiveColor; toggleObject.Background.color = GetValue() ? Tab!.TabAppearance.ToggleActiveColor : Tab!.TabAppearance.ToggleInactiveColor;
passiveButton.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); passiveButton.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
rollover.OverColor = Tab!.TabAppearance.ToggleHoverColor; rollover.OverColor = Tab.TabAppearance.ToggleHoverColor;
passiveButton.OnClick.AddListener((UnityAction)(() => passiveButton.OnClick.AddListener((UnityAction)(() =>
{ {
SetValue(!GetValue()); SetValue(!GetValue());
toggleObject.UpdateText(GetValue()); toggleObject.UpdateText(GetValue());
toggleObject.Background.color = GetValue() ? Tab!.TabAppearance.ToggleActiveColor : Tab!.TabAppearance.ToggleInactiveColor; toggleObject.Background.color = GetValue() ? Tab.TabAppearance.ToggleActiveColor : Tab.TabAppearance.ToggleInactiveColor;
})); }));
passiveButton.OnMouseOver.AddListener((UnityAction)(() => passiveButton.OnMouseOver.AddListener((UnityAction)(() =>
{ {
@@ -68,7 +68,7 @@ public class LocalToggleSetting(
passiveButton.OnMouseOut.AddListener((UnityAction)(() => passiveButton.OnMouseOut.AddListener((UnityAction)(() =>
{ {
toggleObject.UpdateText(GetValue()); toggleObject.UpdateText(GetValue());
toggleObject.Background.color = GetValue() ? Tab!.TabAppearance.ToggleActiveColor : Tab!.TabAppearance.ToggleInactiveColor; toggleObject.Background.color = GetValue() ? Tab.TabAppearance.ToggleActiveColor : Tab.TabAppearance.ToggleInactiveColor;
})); }));
Helpers.DivideSize(toggleObject.gameObject, 1.1f); Helpers.DivideSize(toggleObject.gameObject, 1.1f);
@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using Il2CppInterop.Runtime.Attributes; using Il2CppInterop.Runtime.Attributes;
using Reactor.Utilities.Attributes; using Reactor.Utilities.Attributes;
@@ -11,6 +12,7 @@ namespace MiraAPI.MeetingAbilities;
/// A component for handling targeted meeting buttons. /// A component for handling targeted meeting buttons.
/// </summary> /// </summary>
[RegisterInIl2Cpp] [RegisterInIl2Cpp]
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")]
public class MeetingAbilityBehaviour : MonoBehaviour public class MeetingAbilityBehaviour : MonoBehaviour
{ {
/// <summary> /// <summary>
@@ -24,29 +26,29 @@ public class MeetingAbilityBehaviour : MonoBehaviour
private TargetedMeetingButton _button = null!; private TargetedMeetingButton _button = null!;
/// <summary> /// <summary>
/// The <see cref="PassiveButton"/> of this component. /// Gets he <see cref="PassiveButton"/> of this component.
/// </summary> /// </summary>
public PassiveButton Button; public PassiveButton Button { get; internal set; }
/// <summary> /// <summary>
/// The parent <see cref="PlayerVoteArea"/>. /// Gets he parent <see cref="PlayerVoteArea"/>.
/// </summary> /// </summary>
public PlayerVoteArea VoteArea; public PlayerVoteArea VoteArea { get; internal set; }
/// <summary> /// <summary>
/// The button's <see cref="SpriteRenderer"/> component. /// Gets he button's <see cref="SpriteRenderer"/> component.
/// </summary> /// </summary>
public SpriteRenderer Renderer; public SpriteRenderer Renderer { get; internal set; }
/// <summary> /// <summary>
/// The <see cref="TextMeshPro"/> label used for showing the ability's cooldown. /// Gets he <see cref="TextMeshPro"/> label used for showing the ability's cooldown.
/// </summary> /// </summary>
public TextMeshPro CooldownText; public TextMeshPro CooldownText { get; internal set; }
/// <summary> /// <summary>
/// The <see cref="TextMeshPro"/> label used for showing the ability's remaining uses. /// Gets the <see cref="TextMeshPro"/> label used for showing the ability's remaining uses.
/// </summary> /// </summary>
public TextMeshPro UsesText; public TextMeshPro UsesText { get; internal set; }
/// <summary> /// <summary>
/// Initializes the various properties of this component. /// Initializes the various properties of this component.
@@ -61,12 +63,13 @@ public class MeetingAbilityBehaviour : MonoBehaviour
_button = button; _button = button;
Renderer = GetComponent<SpriteRenderer>(); Renderer = GetComponent<SpriteRenderer>();
SetFillUp(1, 1); SetFillUp(1, 1);
if (!TryGetComponent(out Button)) if (!TryGetComponent<PassiveButton>(out var but))
{ {
Error($"Could not initialize MeetingButtonBehaviour for {Button.GetType().Name}, Destroying..."); Error($"Could not initialize MeetingButtonBehaviour for {Button.GetType().Name}, Destroying...");
Destroy(this); Destroy(this);
} }
_init = true; _init = true;
Button = but;
CooldownText = Instantiate(HudManager.Instance.KillButton.cooldownTimerText, transform); CooldownText = Instantiate(HudManager.Instance.KillButton.cooldownTimerText, transform);
CooldownText.GetComponent<TextTranslatorTMP>().Destroy(); CooldownText.GetComponent<TextTranslatorTMP>().Destroy();
CooldownText.transform.localPosition = new Vector3(0, 0, -10); CooldownText.transform.localPosition = new Vector3(0, 0, -10);
@@ -112,6 +115,11 @@ public class MeetingAbilityBehaviour : MonoBehaviour
SetFillUp(_button.Timer, _button.InitialCooldown); SetFillUp(_button.Timer, _button.InitialCooldown);
} }
/// <summary>
/// Sets the button fill up coloring based on the ratio between the time remaining and the maximum time of the button.
/// </summary>
/// <param name="timer">The remaining timer.</param>
/// <param name="maxTimer">The maximum timer.</param>
public void SetFillUp(float timer, float maxTimer) public void SetFillUp(float timer, float maxTimer)
{ {
float percentCool = Mathf.Clamp(timer / maxTimer, 0.001f, 1f); float percentCool = Mathf.Clamp(timer / maxTimer, 0.001f, 1f);
@@ -73,17 +73,17 @@ public abstract class MeetingActionButton
public int UsesSoFar { get; set; } public int UsesSoFar { get; set; }
/// <summary> /// <summary>
/// Gets a value determining if the abiity is disabled upon being used. /// Gets a value indicating whether the ability is disabled upon being used.
/// </summary> /// </summary>
public virtual bool DisableUponUse => false; public virtual bool DisableUponUse => false;
/// <summary> /// <summary>
/// Gets a value determining if the abiity is disabled upon voting. /// Gets a value indicating whether the ability is disabled upon voting.
/// </summary> /// </summary>
public virtual bool DisableUponVoting => false; public virtual bool DisableUponVoting => false;
/// <summary> /// <summary>
/// Gets a value determining if the abiity is hidden when votes wrapping up. /// Gets a value indicating whether the ability is hidden when votes wrapping up.
/// </summary> /// </summary>
public virtual bool HideUponWrapUp => false; public virtual bool HideUponWrapUp => false;
@@ -15,12 +15,12 @@ public static class MeetingButtonManager
/// <summary> /// <summary>
/// Gets a list if==of all registered <see cref="TargetedMeetingButton"/>. /// Gets a list if==of all registered <see cref="TargetedMeetingButton"/>.
/// </summary> /// </summary>
public static List<TargetedMeetingButton> TargetedButtons { get; internal set; } = new(); public static List<TargetedMeetingButton> TargetedButtons { get; internal set; } = [];
/// <summary> /// <summary>
/// Gets a list if==of all registered <see cref="MeetingActionButton"/>. /// Gets a list if==of all registered <see cref="MeetingActionButton"/>.
/// </summary> /// </summary>
public static List<MeetingActionButton> UntargetedButtons { get; internal set; } = new(); public static List<MeetingActionButton> UntargetedButtons { get; internal set; } = [];
internal static bool RegisterTargetedMeetingButton(Type type, MiraPluginInfo info) internal static bool RegisterTargetedMeetingButton(Type type, MiraPluginInfo info)
{ {
@@ -29,7 +29,7 @@ public static class MeetingButtonManager
return false; return false;
} }
var button = Activator.CreateInstance(type) as TargetedMeetingButton; var button = (Activator.CreateInstance(type) as TargetedMeetingButton)!;
info.InternalTargetedMeetingButtons.Add(button); info.InternalTargetedMeetingButtons.Add(button);
TargetedButtons.Add(button); TargetedButtons.Add(button);
return true; return true;
@@ -42,14 +42,15 @@ public static class MeetingButtonManager
return false; return false;
} }
var button = Activator.CreateInstance(type) as MeetingActionButton; var button = (Activator.CreateInstance(type) as MeetingActionButton)!;
info.InternalMeetingButtons.Add(button); info.InternalMeetingButtons.Add(button);
UntargetedButtons.Add(button); UntargetedButtons.Add(button);
return true; return true;
} }
private static CenteredGridArrange? actionButtonsParent = null!; /// <summary>
/// Called on <see cref="TutorialManager.RunTutorial"/> and <see cref="IntroCutscene.CoBegin"/>/<see cref="IntroCutscene.OnDestroy"/>.
/// </summary>
public static void OnGameStart() public static void OnGameStart()
{ {
foreach (var ability in TargetedButtons.Where(x => x.UsesMode == MeetingButtonUsesMode.PerGame)) foreach (var ability in TargetedButtons.Where(x => x.UsesMode == MeetingButtonUsesMode.PerGame))
@@ -69,7 +70,7 @@ public static class MeetingButtonManager
public static void OnMeetingStart(MeetingHud meetingHud) public static void OnMeetingStart(MeetingHud meetingHud)
{ {
// Untargeted buttons parent. // Untargeted buttons parent.
actionButtonsParent = new GameObject("ActionsButtonParent").AddComponent<CenteredGridArrange>(); var actionButtonsParent = new GameObject("ActionsButtonParent").AddComponent<CenteredGridArrange>();
actionButtonsParent.transform.SetParent(meetingHud.MeetingAbilityButton.transform.parent, meetingHud.MeetingAbilityButton.transform.parent); actionButtonsParent.transform.SetParent(meetingHud.MeetingAbilityButton.transform.parent, meetingHud.MeetingAbilityButton.transform.parent);
actionButtonsParent.CellSize = new Vector2(0.7f, 0.7f); actionButtonsParent.CellSize = new Vector2(0.7f, 0.7f);
actionButtonsParent.transform.localPosition = new Vector3(0, -2.1f, -10); actionButtonsParent.transform.localPosition = new Vector3(0, -2.1f, -10);
@@ -104,7 +105,7 @@ public static class MeetingButtonManager
btn2.transform.SetParent(meetingHud.SkipVoteButton.Buttons.transform); btn2.transform.SetParent(meetingHud.SkipVoteButton.Buttons.transform);
if (ability.UsesMode == MeetingButtonUsesMode.PerMeeting) ability.UsesLeft = ability.MaxUses; if (ability.UsesMode == MeetingButtonUsesMode.PerMeeting) ability.UsesLeft = ability.MaxUses;
if (ability is MultiTargetMeetingButton multiAbility) multiAbility.Targets = new(); if (ability is MultiTargetMeetingButton multiAbility) multiAbility.Targets = [];
} }
catch (Exception e) catch (Exception e)
{ {
@@ -1,7 +1,17 @@
namespace MiraAPI.MeetingAbilities; namespace MiraAPI.MeetingAbilities;
/// <summary>
/// The use mode of the meeting button.
/// </summary>
public enum MeetingButtonUsesMode public enum MeetingButtonUsesMode
{ {
/// <summary>
/// Sets the uses to be limited per game.
/// </summary>
PerGame, PerGame,
PerMeeting
/// <summary>
/// Sets the uses to be limited per meeting.
/// </summary>
PerMeeting,
} }
@@ -7,12 +7,12 @@ using UnityEngine.UI;
namespace MiraAPI.MeetingAbilities; namespace MiraAPI.MeetingAbilities;
/// <summary> /// <summary>
/// Abstract class for creating multi target meeting abilities /// Abstract class for creating multi target meeting abilities.
/// </summary> /// </summary>
public abstract class MultiTargetMeetingButton : TargetedMeetingButton public abstract class MultiTargetMeetingButton : TargetedMeetingButton
{ {
/// <summary> /// <summary>
/// The <see cref="LoadableAsset{Sprite}"/> used for when the button is on. /// Gets he <see cref="LoadableAsset{Sprite}"/> used for when the button is on.
/// </summary> /// </summary>
public abstract LoadableAsset<Sprite> SpriteActive { get; } public abstract LoadableAsset<Sprite> SpriteActive { get; }
@@ -24,7 +24,7 @@ public abstract class MultiTargetMeetingButton : TargetedMeetingButton
/// <summary> /// <summary>
/// Gets or sets all selected targets. /// Gets or sets all selected targets.
/// </summary> /// </summary>
public Dictionary<PlayerVoteArea, MeetingAbilityBehaviour> Targets { get; set; } = new(); public Dictionary<PlayerVoteArea, MeetingAbilityBehaviour> Targets { get; set; } = [];
/// <inheritdoc /> /// <inheritdoc />
public override void ClickHandler(MeetingAbilityBehaviour button, PlayerVoteArea playerVoteArea) public override void ClickHandler(MeetingAbilityBehaviour button, PlayerVoteArea playerVoteArea)
@@ -56,7 +56,7 @@ public abstract class MultiTargetMeetingButton : TargetedMeetingButton
Timer = Cooldown; Timer = Cooldown;
UsesLeft -= 1; UsesLeft -= 1;
OnFinish(); OnFinish();
Targets = new(); Targets = [];
} }
/// <summary> /// <summary>
@@ -83,7 +83,7 @@ public abstract class MultiTargetMeetingButton : TargetedMeetingButton
/// <inheritdoc /> /// <inheritdoc />
public override MeetingAbilityBehaviour CreateButton(PlayerVoteArea playerVoteArea) public override MeetingAbilityBehaviour CreateButton(PlayerVoteArea playerVoteArea)
{ {
Targets = new(); Targets = [];
var button = base.CreateButton(playerVoteArea); var button = base.CreateButton(playerVoteArea);
button.Button.OnClick = new Button.ButtonClickedEvent(); button.Button.OnClick = new Button.ButtonClickedEvent();
button.Button.OnClick.AddListener(new System.Action(() => { ClickHandler(button, playerVoteArea); })); button.Button.OnClick.AddListener(new System.Action(() => { ClickHandler(button, playerVoteArea); }));
-1
View File
@@ -17,5 +17,4 @@
</ItemGroup> </ItemGroup>
<Import Project="../AmongUs.props" /> <Import Project="../AmongUs.props" />
</Project> </Project>
+6 -6
View File
@@ -27,12 +27,6 @@ namespace MiraAPI;
[ReactorModFlags(ModFlags.RequireOnAllClients)] [ReactorModFlags(ModFlags.RequireOnAllClients)]
public partial class MiraApiPlugin : BasePlugin, IMiraPlugin public partial class MiraApiPlugin : BasePlugin, IMiraPlugin
{ {
/// <inheritdoc />
public ConfigFile GetConfigFile()
{
return Config;
}
/// <summary> /// <summary>
/// Gets the specified Culture for string manipulations. /// Gets the specified Culture for string manipulations.
/// </summary> /// </summary>
@@ -86,4 +80,10 @@ public partial class MiraApiPlugin : BasePlugin, IMiraPlugin
ModCompatibility ModCompatibility
.Initialize; // Initialise AFTER the mods are loaded to ensure maximum parity (no need for the soft dependency either then) .Initialize; // Initialise AFTER the mods are loaded to ensure maximum parity (no need for the soft dependency either then)
} }
/// <inheritdoc />
public ConfigFile GetConfigFile()
{
return Config;
}
} }
+4 -3
View File
@@ -84,8 +84,10 @@ public class MiraApiSettings(ConfigFile config) : LocalSettingsTab(config)
{ {
var topUi = MiraHudHelper.UiTopRight; var topUi = MiraHudHelper.UiTopRight;
var extraTopUi = MiraHudHelper.ExtraUiTopRight; var extraTopUi = MiraHudHelper.ExtraUiTopRight;
if (topUi && extraTopUi)
{ if (!topUi || !extraTopUi)
return;
var genericEvent = new UiButtonResetEvent(); var genericEvent = new UiButtonResetEvent();
MiraEventManager.InvokeEvent(genericEvent); MiraEventManager.InvokeEvent(genericEvent);
@@ -94,7 +96,6 @@ public class MiraApiSettings(ConfigFile config) : LocalSettingsTab(config)
MiraHudHelper.UiGrid.ArrangeChilds(); MiraHudHelper.UiGrid.ArrangeChilds();
MiraHudHelper.ExtraUiGrid.ArrangeChilds(); MiraHudHelper.ExtraUiGrid.ArrangeChilds();
} }
}
/// <summary> /// <summary>
/// Resizes the UI as a coroutine. /// Resizes the UI as a coroutine.
+25 -3
View File
@@ -14,26 +14,44 @@ public static class ModCompatibility
/// </summary> /// </summary>
public const string SubmergedId = "Submerged"; public const string SubmergedId = "Submerged";
/// <summary>
/// Gets the <see cref="Version"/> of the Submerged mod.
/// </summary>
public static Version SubVersion { get; private set; } public static Version SubVersion { get; private set; }
/// <summary>
/// Gets a value indicating whether Submerged is loaded.
/// </summary>
public static bool SubLoaded { get; private set; } public static bool SubLoaded { get; private set; }
/// <summary>
/// Gets the <see cref="BasePlugin"/> of the Submerged mod.
/// </summary>
public static BasePlugin SubPlugin { get; private set; } public static BasePlugin SubPlugin { get; private set; }
/// <summary>
/// Gets the <see cref="Assembly"/> of the Submerged mod.
/// </summary>
public static Assembly SubAssembly { get; private set; } public static Assembly SubAssembly { get; private set; }
/// <summary>
/// The map ID of Submerged.
/// </summary>
public const ShipStatus.MapType SubmergedMapType = (ShipStatus.MapType)6; public const ShipStatus.MapType SubmergedMapType = (ShipStatus.MapType)6;
public static void Initialize() internal static void Initialize()
{ {
InitSubmerged(); InitSubmerged();
} }
public static void InitSubmerged() internal static void InitSubmerged()
{ {
if (!IL2CPPChainloader.Instance.Plugins.TryGetValue(SubmergedId, out var plugin)) if (!IL2CPPChainloader.Instance.Plugins.TryGetValue(SubmergedId, out var plugin))
{ {
return; return;
} }
SubPlugin = (plugin!.Instance as BasePlugin)!; SubPlugin = (plugin.Instance as BasePlugin)!;
SubVersion = plugin.Metadata.Version; SubVersion = plugin.Metadata.Version;
SubAssembly = SubPlugin.GetType().Assembly; SubAssembly = SubPlugin.GetType().Assembly;
@@ -42,6 +60,10 @@ public static class ModCompatibility
Message("Submerged was detected"); Message("Submerged was detected");
} }
/// <summary>
/// Checks to see if the current map is the Submerged map.
/// </summary>
/// <returns>true if the current map is Submerged.</returns>
public static bool IsSubmerged() public static bool IsSubmerged()
{ {
return SubLoaded && ShipStatus.Instance && ShipStatus.Instance.Type == SubmergedMapType; return SubLoaded && ShipStatus.Instance && ShipStatus.Instance.Type == SubmergedMapType;
+1 -1
View File
@@ -4,8 +4,8 @@ using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using MiraAPI.Modifiers.Types; using MiraAPI.Modifiers.Types;
using MiraAPI.PluginLoading; using MiraAPI.PluginLoading;
using MiraAPI.Translation;
using MiraAPI.Roles; using MiraAPI.Roles;
using MiraAPI.Translation;
using MiraAPI.Utilities; using MiraAPI.Utilities;
using Reactor.Utilities.Extensions; using Reactor.Utilities.Extensions;
using Random = System.Random; using Random = System.Random;
@@ -50,7 +50,7 @@ public static class HudManagerFlashPatches
hudManager.FullScreen.gameObject.SetActive(settings.EnableSabotageFlashes.Value && !hudManager.FullScreen.gameObject.activeSelf); hudManager.FullScreen.gameObject.SetActive(settings.EnableSabotageFlashes.Value && !hudManager.FullScreen.gameObject.activeSelf);
if (settings.EnableSabotageBlares.Value) if (settings.EnableSabotageBlares.Value)
{ {
SoundManager.Instance.PlaySound(ShipStatus.Instance.SabotageSound, false, 1f, null); SoundManager.Instance.PlaySound(ShipStatus.Instance.SabotageSound, false);
} }
light = !light; light = !light;
@@ -1,6 +1,6 @@
namespace MiraAPI.Patches; /*namespace MiraAPI.Patches;
/*[HarmonyPatch(typeof(DetectiveNotesMinigame), nameof(DetectiveNotesMinigame.SetImpostorPopup))] [HarmonyPatch(typeof(DetectiveNotesMinigame), nameof(DetectiveNotesMinigame.SetImpostorPopup))]
public static class DetectiveNotesMinigamePatch public static class DetectiveNotesMinigamePatch
{ {
public static void Prefix(DetectiveNotesMinigame __instance, bool active) public static void Prefix(DetectiveNotesMinigame __instance, bool active)
+1 -9
View File
@@ -310,16 +310,12 @@ public static class TaskAdderPatches
switch (task.TaskType) switch (task.TaskType)
{ {
case TaskTypes.DivertPower: case TaskTypes.DivertPower:
#pragma warning disable IDE0055 // Fix formatting
{
var targetSystem = task.Cast<DivertPowerTask>().TargetSystem; var targetSystem = task.Cast<DivertPowerTask>().TargetSystem;
taskAddButton.Text.text = TranslationController.Instance.GetString( taskAddButton.Text.text = TranslationController.Instance.GetString(
StringNames.DivertPowerTo, StringNames.DivertPowerTo,
TranslationController.Instance.GetString(targetSystem)); TranslationController.Instance.GetString(targetSystem));
break; break;
}
case TaskTypes.FixWeatherNode: case TaskTypes.FixWeatherNode:
{
var nodeId = task.Cast<WeatherNodeTask>().NodeId; var nodeId = task.Cast<WeatherNodeTask>().NodeId;
taskAddButton.Text.text = taskAddButton.Text.text =
TranslationController.Instance.GetString( TranslationController.Instance.GetString(
@@ -327,20 +323,16 @@ public static class TaskAdderPatches
TranslationController.Instance.GetString( TranslationController.Instance.GetString(
WeatherSwitchGame.ControlNames[nodeId]); WeatherSwitchGame.ControlNames[nodeId]);
break; break;
}
default: default:
{
taskAddButton.Text.text = taskAddButton.Text.text =
TranslationController.Instance.GetString(task.TaskType); TranslationController.Instance.GetString(task.TaskType);
break; break;
} }
#pragma warning restore IDE0055 // Fix formatting
}
__instance.AddFileAsChildCustom(taskAddButton, ref num, ref num2, ref num3); __instance.AddFileAsChildCustom(taskAddButton, ref num, ref num2, ref num3);
if (taskAddButton != null && taskAddButton.Button != null) if (taskAddButton != null && taskAddButton.Button != null)
{ {
ControllerManager.Instance.AddSelectableUiElement(taskAddButton.Button, false); ControllerManager.Instance.AddSelectableUiElement(taskAddButton.Button);
} }
} }
+5 -20
View File
@@ -36,7 +36,7 @@ internal static class ConsolePatches
} }
[HarmonyPrefix, HarmonyPatch(typeof(SystemConsole), nameof(SystemConsole.CanUse))] [HarmonyPrefix, HarmonyPatch(typeof(SystemConsole), nameof(SystemConsole.CanUse))]
public static bool SystemCanUsePatch(SystemConsole __instance, [HarmonyArgument(0)] NetworkedPlayerInfo pc, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse) public static bool SystemCanUsePatch(SystemConsole __instance, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse)
{ {
if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance) if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance)
{ {
@@ -55,7 +55,7 @@ internal static class ConsolePatches
} }
[HarmonyPrefix, HarmonyPatch(typeof(MapConsole), nameof(MapConsole.CanUse))] [HarmonyPrefix, HarmonyPatch(typeof(MapConsole), nameof(MapConsole.CanUse))]
public static bool MapCanUsePatch(MapConsole __instance, [HarmonyArgument(0)] NetworkedPlayerInfo pc, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse) public static bool MapCanUsePatch(MapConsole __instance, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse)
{ {
if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance) if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance)
{ {
@@ -76,36 +76,21 @@ internal static class ConsolePatches
[HarmonyPrefix, HarmonyPatch(typeof(MapConsole), nameof(MapConsole.Use))] [HarmonyPrefix, HarmonyPatch(typeof(MapConsole), nameof(MapConsole.Use))]
public static bool MapUsePatch(MapConsole __instance) public static bool MapUsePatch(MapConsole __instance)
{ {
if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance) return AmongUsClient.Instance.GameState != InnerNetClient.GameStates.Started || !ShipStatus.Instance || CustomGameModeManager.ActiveMode == null ||
{
return CustomGameModeManager.ActiveMode == null ||
CustomGameModeManager.ActiveMode.CanUseMapConsole(__instance); CustomGameModeManager.ActiveMode.CanUseMapConsole(__instance);
} }
return true;
}
[HarmonyPrefix, HarmonyPatch(typeof(SystemConsole), nameof(SystemConsole.Use))] [HarmonyPrefix, HarmonyPatch(typeof(SystemConsole), nameof(SystemConsole.Use))]
public static bool SystemUsePatch(SystemConsole __instance) public static bool SystemUsePatch(SystemConsole __instance)
{ {
if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance) return AmongUsClient.Instance.GameState != InnerNetClient.GameStates.Started || !ShipStatus.Instance || CustomGameModeManager.ActiveMode == null ||
{
return CustomGameModeManager.ActiveMode == null ||
CustomGameModeManager.ActiveMode.CanUseSystemConsole(__instance); CustomGameModeManager.ActiveMode.CanUseSystemConsole(__instance);
} }
return true;
}
[HarmonyPrefix, HarmonyPatch(typeof(Console), nameof(Console.Use))] [HarmonyPrefix, HarmonyPatch(typeof(Console), nameof(Console.Use))]
public static bool ConsoleUsePatch(Console __instance) public static bool ConsoleUsePatch(Console __instance)
{ {
if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance) return AmongUsClient.Instance.GameState != InnerNetClient.GameStates.Started || !ShipStatus.Instance || CustomGameModeManager.ActiveMode == null ||
{
return CustomGameModeManager.ActiveMode == null ||
CustomGameModeManager.ActiveMode.CanUseTasks(__instance); CustomGameModeManager.ActiveMode.CanUseTasks(__instance);
} }
return true;
}
} }
@@ -9,22 +9,22 @@ internal static class GameLogicPatches
[HarmonyPrefix, HarmonyPatch(typeof(GameManager), nameof(GameManager.DidHumansWin))] [HarmonyPrefix, HarmonyPatch(typeof(GameManager), nameof(GameManager.DidHumansWin))]
public static bool DidHumansWin(GameOverReason reason, ref bool __result) public static bool DidHumansWin(GameOverReason reason, ref bool __result)
{ {
__result = reason == GameOverReason.CrewmatesByTask || reason == GameOverReason.CrewmatesByVote || __result = reason is GameOverReason.CrewmatesByTask or GameOverReason.CrewmatesByVote or
reason == GameOverReason.ImpostorDisconnect || reason == GameOverReason.HideAndSeek_CrewmatesByTimer; GameOverReason.ImpostorDisconnect or GameOverReason.HideAndSeek_CrewmatesByTimer;
return false; return false;
} }
[HarmonyPrefix, HarmonyPatch(typeof(GameManager), nameof(GameManager.DidImpostorsWin))] [HarmonyPrefix, HarmonyPatch(typeof(GameManager), nameof(GameManager.DidImpostorsWin))]
public static bool DidImpostorsWin(GameOverReason reason, ref bool __result) public static bool DidImpostorsWin(GameOverReason reason, ref bool __result)
{ {
__result = reason == GameOverReason.ImpostorsByKill || reason == GameOverReason.ImpostorsBySabotage || __result = reason is GameOverReason.ImpostorsByKill or GameOverReason.ImpostorsBySabotage or
reason == GameOverReason.ImpostorsByVote || reason == GameOverReason.HideAndSeek_ImpostorsByKills || GameOverReason.ImpostorsByVote or GameOverReason.HideAndSeek_ImpostorsByKills or
reason == GameOverReason.CrewmateDisconnect; GameOverReason.CrewmateDisconnect;
return false; return false;
} }
[HarmonyPrefix, HarmonyPatch(typeof(NormalGameManager), nameof(NormalGameManager.GetBodyType))] [HarmonyPrefix, HarmonyPatch(typeof(NormalGameManager), nameof(NormalGameManager.GetBodyType))]
public static bool BodyTypePatch(NormalGameManager __instance, PlayerControl player, ref PlayerBodyTypes __result) public static bool BodyTypePatch(PlayerControl player, ref PlayerBodyTypes __result)
{ {
if (CustomGameModeManager.ActiveMode == null || !CustomGameModeManager.ActiveMode.GameModeBodyTypeOverride) if (CustomGameModeManager.ActiveMode == null || !CustomGameModeManager.ActiveMode.GameModeBodyTypeOverride)
{ {
@@ -68,7 +68,7 @@ internal static class GameLogicPatches
[HarmonyPostfix] [HarmonyPostfix]
[HarmonyPatch(typeof(LogicGameFlowNormal), nameof(LogicGameFlowNormal.IsGameOverDueToDeath))] [HarmonyPatch(typeof(LogicGameFlowNormal), nameof(LogicGameFlowNormal.IsGameOverDueToDeath))]
public static void IsGameOverDueToDeathPatch(LogicGameFlowNormal __instance, ref bool __result) public static void IsGameOverDueToDeathPatch(ref bool __result)
{ {
if (CustomGameModeManager.IsActiveGameMode<HideAndSeekMode>()) if (CustomGameModeManager.IsActiveGameMode<HideAndSeekMode>())
{ {
-1
View File
@@ -23,7 +23,6 @@ internal static class HudPatches
} }
} }
[HarmonyPatch(typeof(HudManager), nameof(HudManager.Start))] [HarmonyPatch(typeof(HudManager), nameof(HudManager.Start))]
[HarmonyPostfix] [HarmonyPostfix]
public static void PostHudStart(HudManager __instance) public static void PostHudStart(HudManager __instance)
@@ -2,6 +2,7 @@
using MiraAPI.GameModes; using MiraAPI.GameModes;
namespace MiraAPI.Patches.GameModes; namespace MiraAPI.Patches.GameModes;
[HarmonyPatch(typeof(ProgressTracker), nameof(ProgressTracker.Start))] [HarmonyPatch(typeof(ProgressTracker), nameof(ProgressTracker.Start))]
internal static class ProgressTrackerPatch internal static class ProgressTrackerPatch
{ {
@@ -2,6 +2,7 @@
using MiraAPI.GameModes; using MiraAPI.GameModes;
namespace MiraAPI.Patches.GameModes; namespace MiraAPI.Patches.GameModes;
[HarmonyPatch(typeof(TaskPanelBehaviour), nameof(TaskPanelBehaviour.Update))] [HarmonyPatch(typeof(TaskPanelBehaviour), nameof(TaskPanelBehaviour.Update))]
internal static class TaskPanelPatch internal static class TaskPanelPatch
{ {
-7
View File
@@ -112,16 +112,13 @@ public static class HudManagerPatches
} }
catch catch
{ {
#pragma warning disable S125 // Sections of code should not be commented out
// Error($"Error arranging child objects in GridArrange: {e}"); // Error($"Error arranging child objects in GridArrange: {e}");
#pragma warning restore S125 // Sections of code should not be commented out
} }
} }
} }
} }
} }
#pragma warning disable S125 // Sections of code should not be commented out
/* /*
/// <summary> /// <summary>
/// Trigger HudStart on current custom gamemode /// Trigger HudStart on current custom gamemode
@@ -133,7 +130,6 @@ public static class HudManagerPatches
CustomGameModeManager.ActiveMode?.HudStart(__instance); CustomGameModeManager.ActiveMode?.HudStart(__instance);
} }
*/ */
#pragma warning restore S125 // Sections of code should not be commented out
[HarmonyPrefix] [HarmonyPrefix]
[HarmonyPriority(Priority.First)] [HarmonyPriority(Priority.First)]
@@ -371,10 +367,7 @@ public static class HudManagerPatches
} }
} }
// suppressed warning because we want minimum allocations here
#pragma warning disable S3267
foreach (var entry in KeybindManager.VanillaKeybinds.Values) foreach (var entry in KeybindManager.VanillaKeybinds.Values)
#pragma warning restore S3267
{ {
if (player.GetButtonDown(entry.Id)) if (player.GetButtonDown(entry.Id))
{ {
+1 -1
View File
@@ -3,8 +3,8 @@ using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes;
using MiraAPI.Events; using MiraAPI.Events;
using MiraAPI.Events.Vanilla.Gameplay; using MiraAPI.Events.Vanilla.Gameplay;
using MiraAPI.MeetingAbilities;
using MiraAPI.GameModes; using MiraAPI.GameModes;
using MiraAPI.MeetingAbilities;
using MiraAPI.Roles; using MiraAPI.Roles;
using MiraAPI.Translation; using MiraAPI.Translation;
using MiraAPI.Utilities; using MiraAPI.Utilities;
+33 -71
View File
@@ -25,12 +25,12 @@ namespace MiraAPI.Patches.Options;
[HarmonyPatch(typeof(GameOptionsMenu))] [HarmonyPatch(typeof(GameOptionsMenu))]
internal static class GameOptionsMenuPatch internal static class GameOptionsMenuPatch
{ {
private static List<CategoryHeaderMasked> _vanillaHeaders = new(); private static readonly List<CategoryHeaderMasked> _vanillaHeaders = new();
private static List<OptionBehaviour> _vanillaOptions = new(); private static readonly List<OptionBehaviour> _vanillaOptions = new();
private static List<OptionBehaviour> _mainOptions = new(); private static readonly List<OptionBehaviour> _mainOptions = new();
private static System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<AbstractOptionGroup>> _gameModeGroups = new(); private static readonly System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<AbstractOptionGroup>> _gameModeGroups = [];
private static System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<OptionBehaviour>> _gameModeOptions = new(); private static readonly System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<OptionBehaviour>> _gameModeOptions = [];
private static System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<CategoryHeaderMasked>> _gameModeHeaders = new(); private static readonly System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<CategoryHeaderMasked>> _gameModeHeaders = [];
private static TextMeshPro _gamemodeDescription = null!; private static TextMeshPro _gamemodeDescription = null!;
private static SpriteRenderer _modIcon = null!; private static SpriteRenderer _modIcon = null!;
@@ -77,7 +77,8 @@ internal static class GameOptionsMenuPatch
return false; return false;
} }
public static float AdditionalVanillaScrollNum; private static float additionalVanillaScrollNum;
internal static void ToggleGamemodeOptions(AbstractGameMode gameMode, GameOptionsMenu instance) internal static void ToggleGamemodeOptions(AbstractGameMode gameMode, GameOptionsMenu instance)
{ {
float num = -1.217f; float num = -1.217f;
@@ -185,7 +186,6 @@ internal static class GameOptionsMenuPatch
instance.scrollBar.SetYBoundsMax(-num - 1.65f); instance.scrollBar.SetYBoundsMax(-num - 1.65f);
} }
private static void CreateSettings(GameOptionsMenu instance, Transform container) private static void CreateSettings(GameOptionsMenu instance, Transform container)
{ {
float num = 0.713f; float num = 0.713f;
@@ -200,21 +200,17 @@ internal static class GameOptionsMenuPatch
gmCategory.SetHeader(GameModeOption.CustomName, 20); gmCategory.SetHeader(GameModeOption.CustomName, 20);
gmCategory.transform.localScale = Vector3.one * 0.63f; gmCategory.transform.localScale = Vector3.one * 0.63f;
gmCategory.transform.localPosition = new Vector3(-0.903f, num, -2f); gmCategory.transform.localPosition = new Vector3(-0.903f, num, -2f);
GameModeOption.OptionBehaviour = Object.Instantiate( GameModeOption.OptionBehaviour = Object.Instantiate(instance.stringOptionOrigin, container);
instance.stringOptionOrigin,
Vector3.zero,
Quaternion.identity,
container);
num -= 0.63f; num -= 0.63f;
GameModeOption.OptionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f); GameModeOption.OptionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
GameModeOption.OptionBehaviour.SetClickMask(instance.ButtonClickMask); GameModeOption.OptionBehaviour.SetClickMask(instance.ButtonClickMask);
StringGameSetting setting = ScriptableObject.CreateInstance<StringGameSetting>(); StringGameSetting setting = ScriptableObject.CreateInstance<StringGameSetting>();
setting.Type = OptionTypes.MultipleChoice; setting.Type = OptionTypes.MultipleChoice;
setting.Title = GameModeOption.GamemodeName; setting.Title = GameModeOption.GamemodeName;
setting.Index = GameModeOption._lastValue; setting.Index = GameModeOption.LastValue;
setting.Values = new Il2CppStructArray<StringNames>([GameModeOption.Values[0]]); setting.Values = new Il2CppStructArray<StringNames>([GameModeOption.Values[0]]);
GameModeOption.OptionBehaviour.SetUpFromData(setting, 20); GameModeOption.OptionBehaviour.SetUpFromData(setting, 20);
GameModeOption.Set(GameModeOption._lastValue); GameModeOption.Set(GameModeOption.LastValue);
GameModeOption.OptionBehaviour.TitleText.fontSize = 3; GameModeOption.OptionBehaviour.TitleText.fontSize = 3;
instance.Children.Add(GameModeOption.OptionBehaviour); instance.Children.Add(GameModeOption.OptionBehaviour);
foreach (var optionBehaviour in instance.Children) foreach (var optionBehaviour in instance.Children)
@@ -267,81 +263,47 @@ internal static class GameOptionsMenuPatch
_gamemodeDescription.alignment = TextAlignmentOptions.Left; _gamemodeDescription.alignment = TextAlignmentOptions.Left;
num -= 1.3f; num -= 1.3f;
AdditionalVanillaScrollNum = 0f; additionalVanillaScrollNum = 0f;
foreach (RulesCategory rulesCategory in GameManager.Instance.GameSettingsList.AllCategories) foreach (RulesCategory rulesCategory in GameManager.Instance.GameSettingsList.AllCategories)
{ {
CategoryHeaderMasked categoryHeaderMasked = Object.Instantiate<CategoryHeaderMasked>( var categoryHeaderMasked = Object.Instantiate(instance.categoryHeaderOrigin, container);
instance.categoryHeaderOrigin,
Vector3.zero,
Quaternion.identity,
container);
categoryHeaderMasked.SetHeader(rulesCategory.CategoryName, 20); categoryHeaderMasked.SetHeader(rulesCategory.CategoryName, 20);
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f; categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, num, -2f); categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, num, -2f);
_vanillaHeaders.Add(categoryHeaderMasked); _vanillaHeaders.Add(categoryHeaderMasked);
num -= 0.63f; num -= 0.63f;
AdditionalVanillaScrollNum -= 0.63f; additionalVanillaScrollNum -= 0.63f;
foreach (BaseGameSetting baseGameSetting in rulesCategory.AllGameSettings) foreach (BaseGameSetting baseGameSetting in rulesCategory.AllGameSettings)
{ {
OptionBehaviour? optionBehaviour = null;
switch (baseGameSetting.Type) switch (baseGameSetting.Type)
{ {
case OptionTypes.Checkbox: case OptionTypes.Checkbox:
{ optionBehaviour = Object.Instantiate(instance.checkboxOrigin, container);
OptionBehaviour optionBehaviour = Object.Instantiate<ToggleOption>(
instance.checkboxOrigin,
Vector3.zero,
Quaternion.identity,
container);
optionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
optionBehaviour.SetClickMask(instance.ButtonClickMask);
optionBehaviour.SetUpFromData(baseGameSetting, 20);
_vanillaOptions.Add(optionBehaviour);
break; break;
}
case OptionTypes.String: case OptionTypes.String:
{ optionBehaviour = Object.Instantiate(instance.stringOptionOrigin, container);
OptionBehaviour optionBehaviour = Object.Instantiate<StringOption>(
instance.stringOptionOrigin,
Vector3.zero,
Quaternion.identity,
container);
optionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
optionBehaviour.SetClickMask(instance.ButtonClickMask);
optionBehaviour.SetUpFromData(baseGameSetting, 20);
_vanillaOptions.Add(optionBehaviour);
break; break;
}
case OptionTypes.Float: case OptionTypes.Float:
case OptionTypes.Int: case OptionTypes.Int:
{ optionBehaviour = Object.Instantiate(instance.numberOptionOrigin, container);
OptionBehaviour optionBehaviour = Object.Instantiate<NumberOption>(
instance.numberOptionOrigin,
Vector3.zero,
Quaternion.identity,
container);
optionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
optionBehaviour.SetClickMask(instance.ButtonClickMask);
optionBehaviour.SetUpFromData(baseGameSetting, 20);
_vanillaOptions.Add(optionBehaviour);
break; break;
}
case OptionTypes.Player: case OptionTypes.Player:
{ optionBehaviour = Object.Instantiate(instance.playerOptionOrigin, container);
OptionBehaviour optionBehaviour = Object.Instantiate<PlayerOption>(
instance.playerOptionOrigin,
Vector3.zero,
Quaternion.identity,
container);
optionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
optionBehaviour.SetClickMask(instance.ButtonClickMask);
optionBehaviour.SetUpFromData(baseGameSetting, 20);
_vanillaOptions.Add(optionBehaviour);
break; break;
} }
}
if (!optionBehaviour)
continue;
optionBehaviour!.transform.localPosition = new Vector3(0.952f, num, -2f);
optionBehaviour.SetClickMask(instance.ButtonClickMask);
optionBehaviour.SetUpFromData(baseGameSetting, 20);
_vanillaOptions.Add(optionBehaviour);
num -= 0.45f; num -= 0.45f;
AdditionalVanillaScrollNum -= 0.45f; additionalVanillaScrollNum -= 0.45f;
} }
} }
foreach (var optionBehaviour in _vanillaOptions) foreach (var optionBehaviour in _vanillaOptions)
@@ -363,11 +325,11 @@ internal static class GameOptionsMenuPatch
var filteredGroups = var filteredGroups =
ModdedOptionsManager.GameModeOptionGroups ModdedOptionsManager.GameModeOptionGroups
.Where(x => x.Key == mode.GetType()).Select(y => y.Value).SelectMany(y => y) ?? []; .Where(x => x.Key == mode.GetType()).Select(y => y.Value).SelectMany(y => y) ?? [];
_gameModeGroups.Add(mode, filteredGroups.ToList()); _gameModeGroups.Add(mode, [.. filteredGroups]);
var optionBehaviours = new System.Collections.Generic.List<OptionBehaviour>(); var optionBehaviours = new System.Collections.Generic.List<OptionBehaviour>();
var categoryHeaders = new System.Collections.Generic.List<CategoryHeaderMasked>(); var categoryHeaders = new System.Collections.Generic.List<CategoryHeaderMasked>();
var newNum = mode.ShowNormalGameSettings ? num : num - AdditionalVanillaScrollNum; var newNum = mode.ShowNormalGameSettings ? num : num - additionalVanillaScrollNum;
foreach (var group in filteredGroups) foreach (var group in filteredGroups)
{ {
CreateGroup(instance, group, container, ref newNum, ref optionBehaviours, ref categoryHeaders); CreateGroup(instance, group, container, ref newNum, ref optionBehaviours, ref categoryHeaders);
@@ -550,7 +512,7 @@ internal static class GameOptionsMenuPatch
foreach (var option in group.Options) foreach (var option in group.Options)
{ {
if (option.OptionBehaviour != null && option.OptionBehaviour.gameObject != null) if (option.OptionBehaviour != null && option.OptionBehaviour.gameObject != null)
option.OptionBehaviour?.gameObject.SetActive(false); option.OptionBehaviour.gameObject.SetActive(false);
} }
return; return;
@@ -601,7 +563,7 @@ internal static class GameOptionsMenuPatch
if (mode.ShowNormalGameSettings) if (mode.ShowNormalGameSettings)
{ {
num += AdditionalVanillaScrollNum; num += additionalVanillaScrollNum;
} }
if (!_gameModeGroups.TryGetValue(mode, out var groups) || groups.Count == 0) if (!_gameModeGroups.TryGetValue(mode, out var groups) || groups.Count == 0)
@@ -35,12 +35,7 @@ public static class LobbyViewPanePatches
private static AbstractGameMode? GetCustomGamemode() private static AbstractGameMode? GetCustomGamemode()
{ {
if (!CustomGameModeManager.IsClassic() && !CustomGameModeManager.IsHideNSeek()) return !CustomGameModeManager.IsClassic() && !CustomGameModeManager.IsHideNSeek() ? CustomGameModeManager.ActiveMode : null;
{
return CustomGameModeManager.ActiveMode;
}
return null;
} }
private static IEnumerable<AbstractOptionGroup>? GetCustomGamemodeOptions() private static IEnumerable<AbstractOptionGroup>? GetCustomGamemodeOptions()
+1 -1
View File
@@ -7,8 +7,8 @@ using MiraAPI.GameOptions;
using MiraAPI.Modifiers; using MiraAPI.Modifiers;
using MiraAPI.PluginLoading; using MiraAPI.PluginLoading;
using MiraAPI.Presets; using MiraAPI.Presets;
using MiraAPI.Translation;
using MiraAPI.Roles; using MiraAPI.Roles;
using MiraAPI.Translation;
using MiraAPI.Utilities.Assets; using MiraAPI.Utilities.Assets;
using Reactor.Utilities.Attributes; using Reactor.Utilities.Attributes;
using Reactor.Utilities.Extensions; using Reactor.Utilities.Extensions;
@@ -205,7 +205,7 @@ public static class RoleSettingMenuPatches
foreach (var grouping in sortedRoleGroups) foreach (var grouping in sortedRoleGroups)
{ {
if (!grouping.Any() || if (!grouping.Any() ||
grouping.All(x=> x.Configuration.HideSettings || !x.VisibleInSettings() || !x.Configuration.AssociatedGameMode.IsInstanceOfType(CustomGameModeManager.ActiveMode))) grouping.All(x => x.Configuration.HideSettings || !x.VisibleInSettings() || !x.Configuration.AssociatedGameMode.IsInstanceOfType(CustomGameModeManager.ActiveMode)))
{ {
continue; continue;
} }
+6 -6
View File
@@ -117,15 +117,15 @@ public static class RoleGuidePatches
ControllerManager instance = ControllerManager.Instance; ControllerManager instance = ControllerManager.Instance;
ControllerUiElementsState currentUiState = ControllerManager.Instance.CurrentUiState; ControllerUiElementsState currentUiState = ControllerManager.Instance.CurrentUiState;
Il2CppSystem.Collections.Generic.List<UiElement> controllerSelectable = __instance.ControllerSelectable; Il2CppSystem.Collections.Generic.List<UiElement> controllerSelectable = __instance.ControllerSelectable;
instance.SetUpSelectables(currentUiState, controllerSelectable[controllerSelectable.Count - 1], __instance.ControllerSelectable); instance.SetUpSelectables(currentUiState, controllerSelectable[^1], __instance.ControllerSelectable);
ControllerManager instance2 = ControllerManager.Instance; ControllerManager instance2 = ControllerManager.Instance;
Il2CppSystem.Collections.Generic.List<UiElement> controllerSelectable2 = __instance.ControllerSelectable; Il2CppSystem.Collections.Generic.List<UiElement> controllerSelectable2 = __instance.ControllerSelectable;
instance2.SetCurrentSelected(controllerSelectable2[controllerSelectable2.Count - 1]); instance2.SetCurrentSelected(controllerSelectable2[^1]);
__instance.SetActiveTab(0); __instance.SetActiveTab(0);
return false; return false;
} }
private static Dictionary<RoleBehaviour, MatchInfoRolePanel> _rolePanels = []; private static readonly Dictionary<RoleBehaviour, MatchInfoRolePanel> _rolePanels = [];
public static void DisplayNormalRoleSettings(MatchInfoGuide instance, bool reset) public static void DisplayNormalRoleSettings(MatchInfoGuide instance, bool reset)
{ {
@@ -158,9 +158,9 @@ public static class RoleGuidePatches
GameManager.Instance.LogicOptions.GetTaskBarMode().ToString()); GameManager.Instance.LogicOptions.GetTaskBarMode().ToString());
foreach (RoleBehaviour roleBehaviour in RoleManager.Instance.AllRoles) foreach (RoleBehaviour roleBehaviour in RoleManager.Instance.AllRoles)
{ {
if (roleBehaviour.Role != RoleTypes.Crewmate && roleBehaviour.Role != RoleTypes.Impostor && if (roleBehaviour.Role is not RoleTypes.Crewmate and not RoleTypes.Impostor and
roleBehaviour.Role is not RoleTypes.CrewmateGhost && not RoleTypes.CrewmateGhost and
roleBehaviour.Role is not RoleTypes.ImpostorGhost) not RoleTypes.ImpostorGhost)
{ {
var panel = Object.Instantiate( var panel = Object.Instantiate(
instance.MatchInfoRolePanelPrefab, instance.MatchInfoRolePanelPrefab,
+2 -2
View File
@@ -39,11 +39,11 @@ internal static class HowToPlayPatch
{ {
uiElement.ReceiveMouseOut(); uiElement.ReceiveMouseOut();
} }
ControllerManager.Instance.NewScene(__instance.name, __instance.closeButton, __instance.defaultButtonSelected, __instance.controllerSelectables, false); ControllerManager.Instance.NewScene(__instance.name, __instance.closeButton, __instance.defaultButtonSelected, __instance.controllerSelectables);
} }
__instance.DisableAllScenes(); __instance.DisableAllScenes();
__instance.roleSelectionScene.SetActive(true); __instance.roleSelectionScene.SetActive(true);
ControllerManager.Instance.SetDefaultSelection(__instance.defaultButtonSelected, null); ControllerManager.Instance.SetDefaultSelection(__instance.defaultButtonSelected);
} }
public static void OpenRolePage(HowToPlayScene instance, RoleTypes roleType) public static void OpenRolePage(HowToPlayScene instance, RoleTypes roleType)
{ {
@@ -175,7 +175,7 @@ public static class LogicRoleSelectionHnsPatch
RoleTypes roleType = roleList[index]; RoleTypes roleType = roleList[index];
roleList.RemoveAt(index); roleList.RemoveAt(index);
int index2 = HashRandom.FastNext(players.Count); int index2 = HashRandom.FastNext(players.Count);
players[index2].Object.RpcSetRole(roleType, false); players[index2].Object.RpcSetRole(roleType);
players.RemoveAt(index2); players.RemoveAt(index2);
rolesAssigned++; rolesAssigned++;
} }
+1 -1
View File
@@ -123,7 +123,7 @@ public static class SelectRolesPatch
RoleTypes roleType = roleList[index]; RoleTypes roleType = roleList[index];
roleList.RemoveAt(index); roleList.RemoveAt(index);
int index2 = HashRandom.FastNext(players.Count); int index2 = HashRandom.FastNext(players.Count);
players[index2].Object.RpcSetRole(roleType, false); players[index2].Object.RpcSetRole(roleType);
players.RemoveAt(index2); players.RemoveAt(index2);
rolesAssigned++; rolesAssigned++;
} }
+1
View File
@@ -31,6 +31,7 @@ public static class MinigameStubs
[HarmonyReversePatch] [HarmonyReversePatch]
[HarmonyPatch(typeof(Minigame), nameof(Minigame.Close), [])] [HarmonyPatch(typeof(Minigame), nameof(Minigame.Close), [])]
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
[SuppressMessage("Minor Code Smell", "S3878:Arrays should not be created for params parameters", Justification = "Prevents ambiguity errors.")]
public static void Close(Minigame instance) public static void Close(Minigame instance)
{ {
// nothing needed // nothing needed
+2 -2
View File
@@ -15,9 +15,9 @@ public interface IMiraPlugin
virtual bool DisplayOnOptionsMenu => true; virtual bool DisplayOnOptionsMenu => true;
/// <summary> /// <summary>
/// Gets or sets a value for the localization id to use for anything registered under this mod. /// Gets the localization id to use for anything registered under this mod.
/// </summary> /// </summary>
public virtual string ParentLocaleId => GetType().Name.ToLower(CultureInfo.InvariantCulture); virtual string ParentLocaleId => GetType().Name.ToLower(CultureInfo.InvariantCulture);
/// <summary> /// <summary>
/// Gets the name to display on the options menu. /// Gets the name to display on the options menu.
+3 -4
View File
@@ -41,8 +41,8 @@ public sealed class MiraPluginManager
internal Dictionary<MiraPluginInfo, List<Type>> QueuedRoleRegistrations { get; } = []; internal Dictionary<MiraPluginInfo, List<Type>> QueuedRoleRegistrations { get; } = [];
internal static MiraPluginManager Instance { get; private set; } = new(); internal static MiraPluginManager Instance { get; private set; } = new();
public static ConfigFile MiraApiConfig { get; private set; } = null!; internal static ConfigFile MiraApiConfig { get; private set; } = null!;
public static MiraPluginInfo MiraApiPluginInfo { get; private set; } = null!; internal static MiraPluginInfo MiraApiPluginInfo { get; private set; } = null!;
internal void Initialize(BasePlugin miraApiPlugin, IMiraPlugin apiPlugin) internal void Initialize(BasePlugin miraApiPlugin, IMiraPlugin apiPlugin)
{ {
@@ -222,7 +222,6 @@ public sealed class MiraPluginManager
continue; continue;
} }
if (RegisterMeetingAbility(type, info)) if (RegisterMeetingAbility(type, info))
{ {
continue; continue;
@@ -266,7 +265,7 @@ public sealed class MiraPluginManager
// Cache all the registered plugins into an array for easy access // Cache all the registered plugins into an array for easy access
RegisteredPlugins = [.. _registeredPlugins.Values]; RegisteredPlugins = [.. _registeredPlugins.Values];
RegisteredPluginsWithOptions = [.. RegisteredPlugins.Where(m => m.MiraPlugin.DisplayOnOptionsMenu)]; RegisteredPluginsWithOptions = [.. RegisteredPlugins.Where(m => m.MiraPlugin.DisplayOnOptionsMenu)];
PluginsWithOptionsOrGameModes = [..RegisteredPlugins.Where(m => m.MiraPlugin.DisplayOnOptionsMenu || m.GameModes.Count > 0)]; PluginsWithOptionsOrGameModes = [.. RegisteredPlugins.Where(m => m.MiraPlugin.DisplayOnOptionsMenu || m.GameModes.Count > 0)];
ModifierManager.Modifiers = new ReadOnlyCollection<BaseModifier>(ModifierManager.InternalModifiers); ModifierManager.Modifiers = new ReadOnlyCollection<BaseModifier>(ModifierManager.InternalModifiers);
}; };
+1 -6
View File
@@ -111,7 +111,6 @@ public static class PresetManager
/// </summary> /// </summary>
public static void LoadMasterPreset() public static void LoadMasterPreset()
{ {
#pragma warning disable S125 // Sections of code should not be commented out
/*foreach (var btn in plugin.InternalPresets.Select(x => x.PresetButton)) /*foreach (var btn in plugin.InternalPresets.Select(x => x.PresetButton))
{ {
if (btn != null) if (btn != null)
@@ -121,7 +120,7 @@ public static class PresetManager
} }
plugin.InternalPresets.Clear();*/ plugin.InternalPresets.Clear();*/
#pragma warning restore S125 // Sections of code should not be commented out
if (!Directory.Exists(PresetDirectory)) if (!Directory.Exists(PresetDirectory))
{ {
Directory.CreateDirectory(PresetDirectory); Directory.CreateDirectory(PresetDirectory);
@@ -138,9 +137,7 @@ public static class PresetManager
var fileName = Path.GetFileName(file); var fileName = Path.GetFileName(file);
Info($"Loading preset file {fileName}"); Info($"Loading preset file {fileName}");
#pragma warning disable S125 // Sections of code should not be commented out
// var presetName = Path.GetFileNameWithoutExtension(file); // var presetName = Path.GetFileNameWithoutExtension(file);
#pragma warning restore S125 // Sections of code should not be commented out
var presetConfig = new ConfigFile(file, false) var presetConfig = new ConfigFile(file, false)
{ {
SaveOnConfigSet = false, SaveOnConfigSet = false,
@@ -160,9 +157,7 @@ public static class PresetManager
presetConfig.Save(); presetConfig.Save();
#pragma warning disable S125 // Sections of code should not be commented out
// InternalMasterPresets.Add(new OptionPreset(presetName, plugin, presetConfig)); // InternalMasterPresets.Add(new OptionPreset(presetName, plugin, presetConfig));
#pragma warning restore S125 // Sections of code should not be commented out
} }
MasterPresets = [.. InternalMasterPresets]; MasterPresets = [.. InternalMasterPresets];
} }
+83
View File
@@ -6,25 +6,108 @@ namespace MiraAPI.Translation;
/// </summary> /// </summary>
public enum MiraLanguage public enum MiraLanguage
{ {
/// <summary>
/// English.
/// </summary>
English, English,
/// <summary>
/// Latam.
/// </summary>
Latam, Latam,
/// <summary>
/// Brazilian.
/// </summary>
Brazilian, Brazilian,
/// <summary>
/// Portuguese.
/// </summary>
Portuguese, Portuguese,
/// <summary>
/// Korean.
/// </summary>
Korean, Korean,
/// <summary>
/// Russian.
/// </summary>
Russian, Russian,
/// <summary>
/// Dutch.
/// </summary>
Dutch, Dutch,
/// <summary>
/// Filipino.
/// </summary>
Filipino, Filipino,
/// <summary>
/// French.
/// </summary>
French, French,
/// <summary>
/// German.
/// </summary>
German, German,
/// <summary>
/// Italian.
/// </summary>
Italian, Italian,
/// <summary>
/// Japanese.
/// </summary>
Japanese, Japanese,
/// <summary>
/// Spanish.
/// </summary>
Spanish, Spanish,
/// <summary>
/// SChinese.
/// </summary>
SChinese, SChinese,
/// <summary>
/// TChinese.
/// </summary>
TChinese, TChinese,
/// <summary>
/// Irish.
/// </summary>
Irish, Irish,
/// <summary>
/// Polish.
/// </summary>
Polish, Polish,
/// <summary>
/// Turkish.
/// </summary>
Turkish, Turkish,
/// <summary>
/// Swedish.
/// </summary>
Swedish, Swedish,
/// <summary>
/// Lithuanian.
/// </summary>
Lithuanian, Lithuanian,
/// <summary>
/// Czech.
/// </summary>
Czech, Czech,
} }
+64 -19
View File
@@ -5,23 +5,39 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Xml; using System.Xml;
using MiraAPI.Utilities; using MiraAPI.Utilities;
using MonoMod.Utils;
using Reactor.Localization.Utilities; using Reactor.Localization.Utilities;
using UnityEngine; using UnityEngine;
namespace MiraAPI.Translation; namespace MiraAPI.Translation;
/// <summary>
/// The locale manager to handle translations and more.
/// </summary>
public static class MiraLocaleManager public static class MiraLocaleManager
{ {
private const string LangDirectory = "mira_languages"; private const string LangDirectory = "mira_languages";
// Language, Xml Name, then Value // Language, Xml Name, then Value
/// <summary>
/// Gets the dictionary containing all loaded localization strings, organized by language and XML name.
/// </summary>
public static Dictionary<MiraLanguage, Dictionary<string, string>> Locale { get; } = []; public static Dictionary<MiraLanguage, Dictionary<string, string>> Locale { get; } = [];
/// <summary>
/// Gets the list of mod GUIDs that have been registered with the localization manager.
/// </summary>
public static readonly List<string> RegisteredModIds = []; public static readonly List<string> RegisteredModIds = [];
/// <summary>
/// Gets a dictionary mapping registered string keys to their corresponding <see cref="StringNames"/> enum values.
/// </summary>
public static readonly Dictionary<string, StringNames> RegisteredStringNames = []; public static readonly Dictionary<string, StringNames> RegisteredStringNames = [];
internal static readonly Dictionary<StringNames, string> StringNamesLookup = []; internal static readonly Dictionary<StringNames, string> StringNamesLookup = [];
/// <summary>
/// Gets a dictionary mapping <see cref="MiraLanguage"/> values to their standard language codes.
/// </summary>
public static Dictionary<MiraLanguage, string> LangList { get; } = new() public static Dictionary<MiraLanguage, string> LangList { get; } = new()
{ {
{ MiraLanguage.English, "en_US" }, { MiraLanguage.English, "en_US" },
@@ -46,6 +62,10 @@ public static class MiraLocaleManager
{ MiraLanguage.Lithuanian, "lt_LT" }, // Custom { MiraLanguage.Lithuanian, "lt_LT" }, // Custom
{ MiraLanguage.Czech, "cs_CZ" }, // Custom { MiraLanguage.Czech, "cs_CZ" }, // Custom
}; };
/// <summary>
/// Gets a dictionary mapping <see cref="MiraLanguage"/> values to their standard language codes.
/// </summary>
public static Dictionary<MiraLanguage, string> LangCultureList { get; } = new() public static Dictionary<MiraLanguage, string> LangCultureList { get; } = new()
{ {
{ MiraLanguage.English, "en-US" }, { MiraLanguage.English, "en-US" },
@@ -135,19 +155,13 @@ public static class MiraLocaleManager
/// <returns>A <see cref="string"/> based on the key provided.</returns> /// <returns>A <see cref="string"/> based on the key provided.</returns>
public static string Get(MiraLanguage language, string key, string fallback = "") public static string Get(MiraLanguage language, string key, string fallback = "")
{ {
if (Locale.TryGetValue(language, out var translations) && return Locale.TryGetValue(language, out var translations) &&
translations.TryGetValue(key, out var translation)) translations.TryGetValue(key, out var translation)
{ ? translation
return translation; : Locale.TryGetValue(MiraLanguage.English, out var translationsEng) &&
} translationsEng.TryGetValue(key, out var translationEng)
? translationEng
if (Locale.TryGetValue(MiraLanguage.English, out var translationsEng) && : fallback;
translationsEng.TryGetValue(key, out var translationEng))
{
return translationEng;
}
return fallback;
} }
/// <summary> /// <summary>
@@ -202,11 +216,24 @@ public static class MiraLocaleManager
return text; return text;
} }
/// <summary>
/// Builds a formatted translation ID string using a mod ID, a specific ID part, and a suffix.
/// </summary>
/// <param name="modId">The mod GUID.</param>
/// <param name="idPart">The core part of the ID. If it starts with '#', the character is stripped.</param>
/// <param name="suffix">The suffix to append to the ID.</param>
/// <returns>A formatted translation ID <see cref="string"/>.</returns>
public static string BuildTranslationId(string modId, string idPart, string suffix) public static string BuildTranslationId(string modId, string idPart, string suffix)
{ {
return idPart.StartsWith('#') ? idPart[1..] : $"{modId}.{idPart}.{suffix}"; return idPart.StartsWith('#') ? idPart[1..] : $"{modId}.{idPart}.{suffix}";
} }
/// <summary>
/// Builds a formatted translation ID string using a mod ID and a specific ID part.
/// </summary>
/// <param name="modId">The mod GUID.</param>
/// <param name="idPart">The core part of the ID. If it starts with '#', the character is stripped.</param>
/// <returns>A formatted translation ID <see cref="string"/>.</returns>
public static string BuildTranslationId(string modId, string idPart) public static string BuildTranslationId(string modId, string idPart)
{ {
return idPart.StartsWith('#') ? idPart[1..] : $"{modId}.{idPart}"; return idPart.StartsWith('#') ? idPart[1..] : $"{modId}.{idPart}";
@@ -217,6 +244,11 @@ public static class MiraLocaleManager
return Path.Combine(Application.persistentDataPath, LangDirectory, modGuid); return Path.Combine(Application.persistentDataPath, LangDirectory, modGuid);
} }
/// <summary>
/// Retrieves the <see cref="StringNames"/> value for a given locale string name, creating and registering a new one if it does not already exist.
/// </summary>
/// <param name="name">The name of the locale string.</param>
/// <returns>The corresponding <see cref="StringNames"/> value.</returns>
public static StringNames GetOrCreateLocaleString(string name) public static StringNames GetOrCreateLocaleString(string name)
{ {
if (RegisteredStringNames.TryGetValue(name, out var stringName)) if (RegisteredStringNames.TryGetValue(name, out var stringName))
@@ -230,6 +262,9 @@ public static class MiraLocaleManager
return newString; return newString;
} }
/// <summary>
/// Loads external locale XML files by checking predefined directories, including the plugin path, BepInEx root, game root, and registered mod directories.
/// </summary>
public static void LoadExternalLocale() public static void LoadExternalLocale()
{ {
CheckExternalDirectory("mira.api", BepInEx.Paths.PluginPath); CheckExternalDirectory("mira.api", BepInEx.Paths.PluginPath);
@@ -241,6 +276,11 @@ public static class MiraLocaleManager
} }
} }
/// <summary>
/// Checks a specific directory for XML language files and parses their contents into the <see cref="Locale"/> dictionary.
/// </summary>
/// <param name="modGuid">The mod GUID associated with the directory.</param>
/// <param name="dir">The directory path to search for XML files.</param>
public static void CheckExternalDirectory(string modGuid, string dir) public static void CheckExternalDirectory(string modGuid, string dir)
{ {
Directory.CreateDirectory(dir); Directory.CreateDirectory(dir);
@@ -262,7 +302,7 @@ public static class MiraLocaleManager
} }
catch (Exception e) catch (Exception e)
{ {
Error($"Failed to load external translation {filePath}: {e.Message}"); Error($"Failed to load external translation {filePath} for mod {modGuid}: {e.Message}");
} }
} }
} }
@@ -313,13 +353,20 @@ public static class MiraLocaleManager
xmlDoc.LoadXml(xmlContent); xmlDoc.LoadXml(xmlContent);
XmlNodeList? stringNodes = xmlDoc.SelectNodes("/resources/string"); XmlNodeList? stringNodes = xmlDoc.SelectNodes("/resources/string");
if (stringNodes != null) if (stringNodes == null)
{ {
return;
}
var total = 0; var total = 0;
foreach (XmlNode node in stringNodes) foreach (XmlNode node in stringNodes)
{ {
if (node.Attributes?["name"] != null) if (node.Attributes?["name"] == null)
{ {
continue;
}
string name = node.Attributes["name"]!.Value; string name = node.Attributes["name"]!.Value;
string value = node.InnerText; string value = node.InnerText;
@@ -344,10 +391,8 @@ public static class MiraLocaleManager
dict[name] = value; dict[name] = value;
total++; total++;
} }
}
Info($"Loaded {language.ToDisplayString()} translation with ({total} keys)"); Info($"Loaded {language.ToDisplayString()} translation with ({total} keys)");
} }
}
catch (XmlException ex) catch (XmlException ex)
{ {
Error($"XML parsing error: {ex.Message}"); Error($"XML parsing error: {ex.Message}");
@@ -7,12 +7,17 @@ using Reactor.Utilities;
namespace MiraAPI.Translation; namespace MiraAPI.Translation;
/// <summary>
/// Provides customized localization support, integrating MiraAPI translations into Reactor's localization system.
/// </summary>
public class MiraLocalizationProvider : LocalizationProvider public class MiraLocalizationProvider : LocalizationProvider
{ {
/// <inheritdoc />
public override int Priority => ReactorPriority.Normal; public override int Priority => ReactorPriority.Normal;
private static LocalizationProvider? _reactorProvider; private static LocalizationProvider? _reactorProvider;
private static bool _loadedStrings; private static bool _loadedStrings;
/// <inheritdoc />
public override bool TryGetText(StringNames stringName, out string? result) public override bool TryGetText(StringNames stringName, out string? result)
{ {
if (MiraLocaleManager.StringNamesLookup.TryGetValue(stringName, out var key)) if (MiraLocaleManager.StringNamesLookup.TryGetValue(stringName, out var key))
@@ -24,6 +29,7 @@ public class MiraLocalizationProvider : LocalizationProvider
return false; return false;
} }
/// <inheritdoc />
public override bool TryGetTextFormatted(StringNames stringName, Il2CppReferenceArray<Il2CppSystem.Object> parts, out string? result) public override bool TryGetTextFormatted(StringNames stringName, Il2CppReferenceArray<Il2CppSystem.Object> parts, out string? result)
{ {
if (!TryGetText(stringName, out result)) return false; if (!TryGetText(stringName, out result)) return false;
@@ -32,6 +38,7 @@ public class MiraLocalizationProvider : LocalizationProvider
return true; return true;
} }
/// <inheritdoc />
public override void OnLanguageChanged(SupportedLangs newLanguage) public override void OnLanguageChanged(SupportedLangs newLanguage)
{ {
_reactorProvider ??= LocalizationManager.Providers.First(x => x is HardCodedLocalizationProvider); _reactorProvider ??= LocalizationManager.Providers.First(x => x is HardCodedLocalizationProvider);
@@ -8,6 +8,8 @@ public static class TranslationExtensions
/// <summary> /// <summary>
/// Translates a key to the current language. /// Translates a key to the current language.
/// </summary> /// </summary>
/// <param name="key">The translation key.</param>
/// <returns>The corresponding translation.</returns>
public static string Translate(this string key) public static string Translate(this string key)
{ {
return MiraLocaleManager.Get(key); return MiraLocaleManager.Get(key);
@@ -67,10 +67,8 @@ public static class TmpSpriteUtils
}; };
material.SetTexture(ShaderUtilities.ID_MainTex, sourceTexture); material.SetTexture(ShaderUtilities.ID_MainTex, sourceTexture);
// TODO: Using these values, the icons will NOT clip through chat boxes. However, this breaks quite literally every other tmp text that isn't masked. Please fix this if a good solution is found. // TODO: Using these values, the icons will NOT clip through chat boxes. However, this breaks quite literally every other tmp text that isn't masked. Please fix this if a good solution is found.
#pragma warning disable S125 // Sections of code should not be commented out
/*material.SetFloat(ShaderUtilities.ID_StencilComp, 4); /*material.SetFloat(ShaderUtilities.ID_StencilComp, 4);
material.SetFloat(ShaderUtilities.ID_StencilID, 1);*/ material.SetFloat(ShaderUtilities.ID_StencilID, 1);*/
#pragma warning restore S125 // Sections of code should not be commented out
material.SetFloat(ShaderUtilities.ID_StencilComp, 0); material.SetFloat(ShaderUtilities.ID_StencilComp, 0);
material.SetFloat(ShaderUtilities.ID_StencilID, 0); material.SetFloat(ShaderUtilities.ID_StencilID, 0);
material.SetFloat(ShaderUtilities.ID_StencilOp, 0); material.SetFloat(ShaderUtilities.ID_StencilOp, 0);
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Reactor.Utilities.Attributes; using Reactor.Utilities.Attributes;
using UnityEngine; using UnityEngine;
@@ -11,24 +12,25 @@ namespace MiraAPI.Utilities.Components;
/// </summary> /// </summary>
/// <param name="iPtr">The <see cref="IntPtr"/> for the component.</param> /// <param name="iPtr">The <see cref="IntPtr"/> for the component.</param>
[RegisterInIl2Cpp] [RegisterInIl2Cpp]
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity Convention.")]
public class CenteredGridArrange(IntPtr iPtr) : MonoBehaviour(iPtr) public class CenteredGridArrange(IntPtr iPtr) : MonoBehaviour(iPtr)
{ {
/// <summary> /// <summary>
/// Gets or sets the cell size, which is used for spacing. /// Gets or sets the cell size, which is used for spacing.
/// </summary> /// </summary>
public Vector2 CellSize; public Vector2 CellSize { get; set; }
/// <summary> /// <summary>
/// Gets or sets the maximum amount of columns. /// Gets or sets the maximum amount of columns.
/// </summary> /// </summary>
public int MaxColumns = 6; public int MaxColumns { get; set; } = 6;
private List<Transform> cells; private List<Transform> cells;
private static List<Transform> currentChildren = new List<Transform>(); private static readonly List<Transform> CurrentChildren = [];
private void Start() private void Start()
{ {
cells = new List<Transform>(); cells = [];
GetChildsActive(); GetChildsActive();
CheckCurrentChildren(); CheckCurrentChildren();
} }
@@ -41,23 +43,23 @@ public class CenteredGridArrange(IntPtr iPtr) : MonoBehaviour(iPtr)
private void CheckCurrentChildren() private void CheckCurrentChildren()
{ {
GetChildsActive(); GetChildsActive();
if (cells.SequenceEqual(currentChildren)) if (cells.SequenceEqual(CurrentChildren))
return; return;
cells.Clear(); cells.Clear();
foreach (Transform currentChild in currentChildren) foreach (Transform currentChild in CurrentChildren)
cells.Add(currentChild); cells.Add(currentChild);
ArrangeChilds(); ArrangeChilds();
} }
private void GetChildsActive() private void GetChildsActive()
{ {
currentChildren.Clear(); CurrentChildren.Clear();
foreach (var obj in transform) foreach (var obj in transform)
{ {
var child = obj.TryCast<Transform>(); var child = obj.TryCast<Transform>();
if (child == null) continue; if (child == null) continue;
if (child.gameObject.activeSelf) if (child.gameObject.activeSelf)
currentChildren.Add(child); CurrentChildren.Add(child);
} }
} }
+2 -4
View File
@@ -62,7 +62,7 @@ public static class Extensions
} }
if (self.CloseSound && Constants.ShouldPlaySfx()) if (self.CloseSound && Constants.ShouldPlaySfx())
{ {
SoundManager.Instance.PlaySound(self.CloseSound, false, 1f, null); SoundManager.Instance.PlaySound(self.CloseSound, false);
} }
if (PlayerControl.LocalPlayer.Data.Role.TeamType == RoleTeamTypes.Crewmate) if (PlayerControl.LocalPlayer.Data.Role.TeamType == RoleTeamTypes.Crewmate)
{ {
@@ -222,9 +222,7 @@ public static class Extensions
public static void DeepDestroy(this GameObject obj, bool clearGc = true) public static void DeepDestroy(this GameObject obj, bool clearGc = true)
{ {
obj.Destroy(); obj.Destroy();
#pragma warning disable S125 // Sections of code should not be commented out
// Nuke(obj, clearGc); // Nuke(obj, clearGc);
#pragma warning restore S125 // Sections of code should not be commented out
} }
/// <summary> /// <summary>
@@ -528,7 +526,7 @@ public static class Extensions
/// <returns>A proper string for the <see cref="Enum"/>.</returns> /// <returns>A proper string for the <see cref="Enum"/>.</returns>
public static string ToDisplayString(this Enum @enum) public static string ToDisplayString(this Enum @enum)
{ {
var regex = new Regex(@"([^\^])([A-Z][a-z$])"); var regex = new Regex(@"([^\^])([A-Z][a-z$])", default, default);
return regex.Replace(@enum.ToString(), m => $"{m.Groups[1].Value} {m.Groups[2].Value}"); return regex.Replace(@enum.ToString(), m => $"{m.Groups[1].Value} {m.Groups[2].Value}");
} }
+3 -15
View File
@@ -536,11 +536,7 @@ public static class Helpers
/// <returns>The <see cref="RoleBehaviour"/>'s intro blurb.</returns> /// <returns>The <see cref="RoleBehaviour"/>'s intro blurb.</returns>
public static string GetRoleIntroBlurb(this RoleBehaviour role) public static string GetRoleIntroBlurb(this RoleBehaviour role)
{ {
if (role is ICustomRole custom) return role is ICustomRole custom ? custom.RoleDescription : role.Blurb;
{
return custom.RoleDescription;
}
return role.Blurb;
} }
/// <summary> /// <summary>
@@ -550,11 +546,7 @@ public static class Helpers
/// <returns>The <see cref="RoleBehaviour"/>'s medium description.</returns> /// <returns>The <see cref="RoleBehaviour"/>'s medium description.</returns>
public static string GetRoleMedDescription(this RoleBehaviour role) public static string GetRoleMedDescription(this RoleBehaviour role)
{ {
if (role is ICustomRole custom) return role is ICustomRole custom ? custom.RoleDescription : role.BlurbMed;
{
return custom.RoleDescription;
}
return role.BlurbMed;
} }
/// <summary> /// <summary>
@@ -564,11 +556,7 @@ public static class Helpers
/// <returns>The <see cref="RoleBehaviour"/>'s long description.</returns> /// <returns>The <see cref="RoleBehaviour"/>'s long description.</returns>
public static string GetRoleLongDescription(this RoleBehaviour role) public static string GetRoleLongDescription(this RoleBehaviour role)
{ {
if (role is ICustomRole custom) return role is ICustomRole custom ? custom.RoleLongDescription : role.BlurbLong;
{
return custom.RoleLongDescription;
}
return role.BlurbLong;
} }
/// <summary> /// <summary>
+2 -2
View File
@@ -4,12 +4,12 @@ using MiraAPI.Roles;
namespace MiraAPI.VanillaEvents; namespace MiraAPI.VanillaEvents;
public static class JudgeEvents internal static class JudgeEvents
{ {
public static void Initialize() public static void Initialize()
{ {
// This is required because MiraAPI isn't an IMiraPlugin (besides in the gamemodes branch) // This is required because MiraAPI isn't an IMiraPlugin (besides in the gamemodes branch)
MiraEventManager.RegisterEventHandler<ProcessVotesEvent>(@event => ProcessVotesEventHandler(@event), -1000); MiraEventManager.RegisterEventHandler<ProcessVotesEvent>(ProcessVotesEventHandler, -1000);
} }
public static void ProcessVotesEventHandler(ProcessVotesEvent @event) public static void ProcessVotesEventHandler(ProcessVotesEvent @event)
+6 -6
View File
@@ -5,17 +5,17 @@ using MiraAPI.LocalSettings;
namespace MiraAPI.VanillaEvents; namespace MiraAPI.VanillaEvents;
public static class UiResetEvents internal static class UiResetEvents
{ {
public static void Initialize() public static void Initialize()
{ {
MiraEventManager.RegisterEventHandler<UiButtonResetEvent>(@event => ResetButtonParents(@event)); MiraEventManager.RegisterEventHandler<UiButtonResetEvent>(ResetButtonParents);
MiraEventManager.RegisterEventHandler<UiButtonPostResetEvent>(@event => PlaceWikiButton(@event), -900); MiraEventManager.RegisterEventHandler<UiButtonPostResetEvent>(PlaceWikiButton, -900);
MiraEventManager.RegisterEventHandler<UiButtonPostResetEvent>(@event => PlaceSubmergedButton(@event), -800); MiraEventManager.RegisterEventHandler<UiButtonPostResetEvent>(PlaceSubmergedButton, -800);
MiraEventManager.RegisterEventHandler<UiButtonPostResetEvent>(@event => PlaceModifierUi(@event), -700); MiraEventManager.RegisterEventHandler<UiButtonPostResetEvent>(PlaceModifierUi, -700);
} }
public static void ResetButtonParents(UiButtonResetEvent @event) public static void ResetButtonParents(UiButtonResetEvent _)
{ {
var wikiButton = MiraHudHelper.VanillaMatchInfoButton; var wikiButton = MiraHudHelper.VanillaMatchInfoButton;
var subButton = MiraHudHelper.SubmergedFloorButton; var subButton = MiraHudHelper.SubmergedFloorButton;
+17
View File
@@ -42,6 +42,7 @@ public static class VotingUtils
/// </summary> /// </summary>
/// <param name="voteData">The player's <see cref="PlayerVoteData"/>.</param> /// <param name="voteData">The player's <see cref="PlayerVoteData"/>.</param>
/// <param name="suspectIdx">Who the player voted for.</param> /// <param name="suspectIdx">Who the player voted for.</param>
/// <param name="byJudge">Flag that indicates that the vote was done by a Judge.</param>
/// <param name="cancelVote">Whether you want the vote to commence or not.</param> /// <param name="cancelVote">Whether you want the vote to commence or not.</param>
private static void HandleVote(PlayerVoteData voteData, byte suspectIdx, bool byJudge, out bool cancelVote) private static void HandleVote(PlayerVoteData voteData, byte suspectIdx, bool byJudge, out bool cancelVote)
{ {
@@ -117,11 +118,22 @@ public static class VotingUtils
/// <param name="suspectPlayerId">The voted player's id.</param> /// <param name="suspectPlayerId">The voted player's id.</param>
/// <param name="overruleNonce">Data that is checked by the Judge role to determine which Judge takes priority.</param> /// <param name="overruleNonce">Data that is checked by the Judge role to determine which Judge takes priority.</param>
[MethodRpc((uint)MiraRpc.QueueOverruleVotes)] [MethodRpc((uint)MiraRpc.QueueOverruleVotes)]
[SuppressMessage(
"Style",
"IDE0060:Remove unused parameter",
Justification = "Required parameter: The MethodRpc system mandates an InnerNetObject (or its derived class) as the first parameter for sender context, even if unused in the method body."
)]
public static void RpcQueueOverruleVotes(PlayerControl source, byte srcPlayerId, byte suspectPlayerId, ushort overruleNonce) public static void RpcQueueOverruleVotes(PlayerControl source, byte srcPlayerId, byte suspectPlayerId, ushort overruleNonce)
{ {
CustomCastJudgeVote(srcPlayerId, suspectPlayerId, overruleNonce); CustomCastJudgeVote(srcPlayerId, suspectPlayerId, overruleNonce);
} }
/// <summary>
/// Casts a custom Judge vote.
/// </summary>
/// <param name="judgePlayerId">The Judge's player ID.</param>
/// <param name="targetPlayerId">The unfortunate soul's player ID.</param>
/// <param name="overruleNonce">Overruled.</param>
public static void CustomCastJudgeVote(PlayerId judgePlayerId, PlayerId targetPlayerId, ushort overruleNonce) public static void CustomCastJudgeVote(PlayerId judgePlayerId, PlayerId targetPlayerId, ushort overruleNonce)
{ {
var plr = GameData.Instance.GetPlayerById(judgePlayerId.Value); var plr = GameData.Instance.GetPlayerById(judgePlayerId.Value);
@@ -187,6 +199,11 @@ public static class VotingUtils
CustomCastVote(srcPlayerId, suspectPlayerId); CustomCastVote(srcPlayerId, suspectPlayerId);
} }
/// <summary>
/// Casts a custom vote.
/// </summary>
/// <param name="srcPlayerId">The casting player's ID.</param>
/// <param name="suspectPlayerId">The voted player's ID.</param>
public static void CustomCastVote(byte srcPlayerId, byte suspectPlayerId) public static void CustomCastVote(byte srcPlayerId, byte suspectPlayerId)
{ {
var plr = GameData.Instance.GetPlayerById(srcPlayerId); var plr = GameData.Instance.GetPlayerById(srcPlayerId);