From a37a8a8e1b388b27473621507e1fdd3516aa716f Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Tue, 20 Aug 2024 00:05:00 -0400 Subject: [PATCH] options fixes + start re implement custom game modes --- MiraAPI.Example/CustomRoleSettings.cs | 19 +++++ MiraAPI/GameModes/CustomGameModeManager.cs | 19 ++--- MiraAPI/GameOptions/IModdedOption.cs | 2 +- MiraAPI/GameOptions/ModdedOptionsManager.cs | 14 +++- .../GameOptions/OptionTypes/ModdedOption.cs | 3 +- MiraAPI/Patches/GameModes/ConsolePatches.cs | 76 +++++++++++++++++++ MiraAPI/Patches/GameModes/GameLogicPatches.cs | 24 ++++++ .../Patches/GameModes/ImpostorTargetPatch.cs | 28 +++++++ .../Patches/GameModes/MapBehaviourPatch.cs | 22 ++++++ MiraAPI/Patches/HudManagerPatches.cs | 19 ++--- MiraAPI/Patches/IntroCutscenePatches.cs | 57 ++++++++++++++ .../Patches/Options/RoleSettingMenuPatches.cs | 2 +- MiraAPI/Patches/Roles/NameTagPatch.cs | 9 ++- MiraAPI/PluginLoading/MiraPluginManager.cs | 1 + 14 files changed, 268 insertions(+), 27 deletions(-) create mode 100644 MiraAPI.Example/CustomRoleSettings.cs create mode 100644 MiraAPI/Patches/GameModes/ConsolePatches.cs create mode 100644 MiraAPI/Patches/GameModes/GameLogicPatches.cs create mode 100644 MiraAPI/Patches/GameModes/ImpostorTargetPatch.cs create mode 100644 MiraAPI/Patches/GameModes/MapBehaviourPatch.cs create mode 100644 MiraAPI/Patches/IntroCutscenePatches.cs diff --git a/MiraAPI.Example/CustomRoleSettings.cs b/MiraAPI.Example/CustomRoleSettings.cs new file mode 100644 index 00000000..34cb47af --- /dev/null +++ b/MiraAPI.Example/CustomRoleSettings.cs @@ -0,0 +1,19 @@ +using System; +using MiraAPI.GameOptions; +using MiraAPI.GameOptions.Attributes; +using MiraAPI.GameOptions.OptionTypes; + +namespace MiraAPI.Example; + +public class CustomRoleSettings : IModdedOptionGroup +{ + public string GroupName => "Custom Role"; + + public Type AdvancedRole => typeof(CustomRole); + + [ModdedNumberOption("amogus", min: 3, max: 9)] public float amogus { get; set; } = 1; + + [ModdedEnumOption("dwayne the rock johnson", typeof(TestEnum))] public TestEnum dwayneTheRockJohnson { get; set; } = TestEnum.Hello; + + public ModdedToggleOption testToggle { get; } = new ("test toggle", false); +} \ No newline at end of file diff --git a/MiraAPI/GameModes/CustomGameModeManager.cs b/MiraAPI/GameModes/CustomGameModeManager.cs index f453ccaa..bec9d846 100644 --- a/MiraAPI/GameModes/CustomGameModeManager.cs +++ b/MiraAPI/GameModes/CustomGameModeManager.cs @@ -1,4 +1,5 @@ -using Reactor.Utilities; +#nullable enable +using Reactor.Utilities; using System; using System.Collections.Generic; using System.Linq; @@ -17,13 +18,13 @@ public static class CustomGameModeManager public static bool IsDefault() { - return ActiveMode.Id == 0; + return ActiveMode?.Id == 0; } /// /// Current gamemode /// - public static CustomGameMode ActiveMode; + public static CustomGameMode? ActiveMode; /// /// Set current gamemode @@ -52,17 +53,17 @@ public static class CustomGameModeManager return; } - var gameMode = (CustomGameMode)Activator.CreateInstance(gameModeType); + var modeObj = Activator.CreateInstance(gameModeType); - if (GameModes.Any(x => x.Key == gameMode?.Id)) + if (modeObj is not CustomGameMode gameMode) { - Logger.Error($"ID for gamemode {gameMode?.Name} already exists!"); + Logger.Error($"Failed to create instance of {gameModeType.Name}"); return; } - - if (gameMode == null) + + if (GameModes.Any(x => x.Key == gameMode.Id)) { - Logger.Error($"GAMEMODE WITH TYPE {gameModeType.Name} IS NULL"); + Logger.Error($"ID for gamemode {gameMode.Name} already exists!"); return; } diff --git a/MiraAPI/GameOptions/IModdedOption.cs b/MiraAPI/GameOptions/IModdedOption.cs index 9822eb12..232cf5a4 100644 --- a/MiraAPI/GameOptions/IModdedOption.cs +++ b/MiraAPI/GameOptions/IModdedOption.cs @@ -11,7 +11,7 @@ public interface IModdedOption public BaseGameSetting Data { get; } public IModdedOptionGroup Group { get; set; } public IMiraPlugin ParentMod { get; set; } - public Type AdvancedRole { get; } + public Type AdvancedRole { get; set; } public OptionBehaviour OptionBehaviour { get; protected set; } public string Title { get; } public StringNames StringName { get; } diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs index 02e99f97..0d8e15f2 100644 --- a/MiraAPI/GameOptions/ModdedOptionsManager.cs +++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs @@ -23,7 +23,18 @@ public class ModdedOptionsManager { if (OptionAttributes.ContainsKey(property)) return null; object newObj = Activator.CreateInstance(type); - IModdedOption result = attribute.CreateOption(property.GetValue(newObj), property); + + IModdedOption result; + + try + { + result = attribute.CreateOption(property.GetValue(newObj), property); + } + catch (Exception e) + { + Logger.Error(e); + return null; + } if (result != null) { @@ -43,6 +54,7 @@ public class ModdedOptionsManager { Logger.Error($"Grouping {attribute.Title} with {OriginalTypes[type].GroupName}"); result.Group = OriginalTypes[type]; + result.AdvancedRole = OriginalTypes[type].AdvancedRole; } } diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs index 366ab2d5..386cc7c3 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs @@ -19,7 +19,7 @@ public abstract class ModdedOption : IModdedOption public string Title { get; } public StringNames StringName { get; } public Func Visible { get; set; } - public Type AdvancedRole { get; } + public Type AdvancedRole { get; set; } public OptionBehaviour OptionBehaviour { get; set; } public IModdedOptionGroup Group { get; set; } = null; public IMiraPlugin ParentMod { get; set; } = null; @@ -40,7 +40,6 @@ public abstract class ModdedOption : IModdedOption private ModdedOption() { - Logger.Error("created modded option"); Id = ModdedOptionsManager.NextId++; ModdedOptionsManager.Options.Add(this); ModdedOptionsManager.ModdedOptions.Add(Id, this); diff --git a/MiraAPI/Patches/GameModes/ConsolePatches.cs b/MiraAPI/Patches/GameModes/ConsolePatches.cs new file mode 100644 index 00000000..d37f9405 --- /dev/null +++ b/MiraAPI/Patches/GameModes/ConsolePatches.cs @@ -0,0 +1,76 @@ +using HarmonyLib; +using InnerNet; +using MiraAPI.GameModes; + +namespace MiraAPI.Patches.GameModes; + +[HarmonyPatch] +public static class ConsolePatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(Console), nameof(Console.CanUse))] + public static bool CanUsePatch(Console __instance, [HarmonyArgument(0)] NetworkedPlayerInfo pc, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse) + { + if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance) + { + if (CustomGameModeManager.ActiveMode != null && CustomGameModeManager.ActiveMode.CanUseConsole(__instance)) + { + var task = __instance.FindTask(pc.Object); + + if (task && task.GetComponent()) + { + canUse = couldUse = true; + return true; + } + + canUse = false; + couldUse = false; + return true; + } + + canUse = couldUse = false; + return false; + } + + canUse = couldUse = true; + return true; + } + + [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) + { + if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance) + { + if (CustomGameModeManager.ActiveMode != null && CustomGameModeManager.ActiveMode.CanUseSystemConsole(__instance)) + { + return canUse = couldUse = true; + } + + canUse = couldUse = false; + return false; + } + + canUse = couldUse = true; + return true; + } + + [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) + { + if (AmongUsClient.Instance.GameState == InnerNetClient.GameStates.Started && ShipStatus.Instance) + { + if (CustomGameModeManager.ActiveMode != null && CustomGameModeManager.ActiveMode.CanUseMapConsole(__instance)) + { + return canUse = couldUse = true; + } + + canUse = couldUse = false; + return false; + } + + canUse = couldUse = true; + return true; + } +} \ No newline at end of file diff --git a/MiraAPI/Patches/GameModes/GameLogicPatches.cs b/MiraAPI/Patches/GameModes/GameLogicPatches.cs new file mode 100644 index 00000000..d60a70d3 --- /dev/null +++ b/MiraAPI/Patches/GameModes/GameLogicPatches.cs @@ -0,0 +1,24 @@ +using HarmonyLib; +using MiraAPI.GameModes; + +namespace MiraAPI.Patches.GameModes; + +[HarmonyPatch] +public static class GameLogicPatches +{ + [HarmonyPrefix, HarmonyPatch(typeof(LogicGameFlowNormal), nameof(LogicGameFlowNormal.CheckEndCriteria))] + public static bool EndCritPatch(LogicGameFlowNormal __instance) + { + var runOriginal = true; + CustomGameModeManager.ActiveMode?.CheckGameEnd(out runOriginal, __instance); + return runOriginal; + } + + [HarmonyPrefix, HarmonyPatch(typeof(LogicRoleSelectionNormal), nameof(LogicRoleSelectionNormal.AssignRolesFromList))] + public static bool AssignRolesPatch(LogicRoleSelectionNormal __instance) + { + var runOriginal = true; + CustomGameModeManager.ActiveMode?.AssignRoles(out runOriginal, __instance); + return runOriginal; + } +} \ No newline at end of file diff --git a/MiraAPI/Patches/GameModes/ImpostorTargetPatch.cs b/MiraAPI/Patches/GameModes/ImpostorTargetPatch.cs new file mode 100644 index 00000000..899006dd --- /dev/null +++ b/MiraAPI/Patches/GameModes/ImpostorTargetPatch.cs @@ -0,0 +1,28 @@ +using HarmonyLib; +using MiraAPI.GameModes; + +namespace MiraAPI.Patches.GameModes; + +/// +/// Allow Impostors to kill each other if can kill is enabled in gamemode or friendly fire is toggled on +/// +[HarmonyPatch(typeof(ImpostorRole), "IsValidTarget")] +public static class ImpostorTargetPatch +{ + public static bool Prefix(ImpostorRole __instance, [HarmonyArgument(0)] NetworkedPlayerInfo target, ref bool __result) + { + var runOriginal = true; + var result = false; + CustomGameModeManager.ActiveMode?.CanKill(out runOriginal, out result, target.Object); + if (runOriginal || !result) + { + return true; + } + + __result = target is { Disconnected: false, IsDead: false } && + target.PlayerId != __instance.Player.PlayerId && !(target.Role == null) && + !(target.Object == null) && !target.Object.inVent && !target.Object.inMovingPlat; + return false; + + } +} \ No newline at end of file diff --git a/MiraAPI/Patches/GameModes/MapBehaviourPatch.cs b/MiraAPI/Patches/GameModes/MapBehaviourPatch.cs new file mode 100644 index 00000000..e7629ef0 --- /dev/null +++ b/MiraAPI/Patches/GameModes/MapBehaviourPatch.cs @@ -0,0 +1,22 @@ +using HarmonyLib; +using MiraAPI.GameModes; + +namespace MiraAPI.Patches.GameModes; + +[HarmonyPatch(typeof(MapBehaviour))] +public class MapBehaviourPatch +{ + [HarmonyPrefix] + [HarmonyPatch(nameof(MapBehaviour.ShowSabotageMap))] + public static bool ShowSabotagePatch(MapBehaviour __instance) + { + var shouldShow = CustomGameModeManager.ActiveMode?.ShouldShowSabotageMap(__instance); + if (shouldShow.HasValue && !shouldShow.Value) + { + __instance.ShowNormalMap(); + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs index b7c5a0e7..019ebd9f 100644 --- a/MiraAPI/Patches/HudManagerPatches.cs +++ b/MiraAPI/Patches/HudManagerPatches.cs @@ -1,5 +1,6 @@ using HarmonyLib; using InnerNet; +using MiraAPI.GameModes; using MiraAPI.Hud; using MiraAPI.Roles; using Reactor.Utilities.Extensions; @@ -56,15 +57,15 @@ public static class HudManagerPatches } } - /* /// - /// Trigger hudstart on current custom gamemode - /// - [HarmonyPostfix] - [HarmonyPatch("OnGameStart")] - public static void GameStartPatch(HudManager __instance) - { - CustomGameModeManager.ActiveMode.HudStart(__instance); - }*/ + /// + /// Trigger hudstart on current custom gamemode + /// + [HarmonyPostfix] + [HarmonyPatch(nameof(HudManager.OnGameStart))] + public static void GameStartPatch(HudManager __instance) + { + CustomGameModeManager.ActiveMode?.HudStart(__instance); + } /// /// Create custom buttons parent diff --git a/MiraAPI/Patches/IntroCutscenePatches.cs b/MiraAPI/Patches/IntroCutscenePatches.cs new file mode 100644 index 00000000..1af8acfc --- /dev/null +++ b/MiraAPI/Patches/IntroCutscenePatches.cs @@ -0,0 +1,57 @@ +using HarmonyLib; +using MiraAPI.GameModes; +using MiraAPI.Roles; +using MiraAPI.Utilities; +using UnityEngine; + +namespace MiraAPI.Patches; + +[HarmonyPatch(typeof(IntroCutscene))] +public static class IntroCutscenePatches +{ + [HarmonyPostfix] + [HarmonyPatch(nameof(IntroCutscene.BeginImpostor))] + public static void BeginImpostorPatch(IntroCutscene __instance) + { + if (CustomGameModeManager.ActiveMode != null && CustomGameModeManager.ActiveMode.ShowCustomRoleScreen()) + { + var mode = CustomGameModeManager.ActiveMode; + __instance.TeamTitle.text = $"{mode.Name}\n{mode.Description}"; + } + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(IntroCutscene.BeginCrewmate))] + public static bool BeginCrewmatePatch(IntroCutscene __instance) + { + if (PlayerControl.LocalPlayer.Data.Role is ICustomRole customRole) + { + if (!customRole.IsNeutral) + { + return true; + } + + var barTransform = __instance.BackgroundBar.transform; + var position = barTransform.position; + position.y -= 0.25f; + barTransform.position = position; + + __instance.BackgroundBar.material.SetColor(ShaderID.Color, Color.gray); + __instance.TeamTitle.text = "OUTCAST"; + __instance.impostorScale = 1f; + __instance.ImpostorText.text = "You are an Outcast. You do not have a team."; + __instance.TeamTitle.color = Color.gray; + + __instance.ourCrewmate = __instance.CreatePlayer(0, Mathf.CeilToInt(7.5f), PlayerControl.LocalPlayer.Data, false); + return false; + } + return true; + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(IntroCutscene.OnDestroy))] + public static void GameBeginPatch() + { + CustomGameModeManager.ActiveMode?.Initialize(); + } +} \ No newline at end of file diff --git a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs index 0b3b6fb5..23508011 100644 --- a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs +++ b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs @@ -132,7 +132,7 @@ public static class RoleSettingMenuPatches __instance.advancedSettingChildren.Clear(); float num = -0.872f; - foreach (var option in GameSettingMenuPatches.SelectedMod.Options.Where(option => option.AdvancedRole == role.GetType())) + foreach (var option in GameSettingMenuPatches.SelectedMod.Options.Where(option => option.AdvancedRole != null && option.AdvancedRole == role.GetType())) { OptionBehaviour newOpt = option.CreateOption(__instance.checkboxOrigin, __instance.numberOptionOrigin, __instance.stringOptionOrigin, __instance.AdvancedRolesSettings.transform); newOpt.transform.localPosition = new Vector3(2.17f, num, -2f); diff --git a/MiraAPI/Patches/Roles/NameTagPatch.cs b/MiraAPI/Patches/Roles/NameTagPatch.cs index d74a88c7..35664162 100644 --- a/MiraAPI/Patches/Roles/NameTagPatch.cs +++ b/MiraAPI/Patches/Roles/NameTagPatch.cs @@ -1,4 +1,6 @@ using HarmonyLib; +using MiraAPI.GameModes; +using MiraAPI.GameOptions; using UnityEngine; namespace MiraAPI.Patches.Roles; @@ -13,13 +15,12 @@ public static class NameTagPatch [HarmonyPatch(nameof(PlayerNameColor.Get), typeof(RoleBehaviour))] public static bool GetPatch([HarmonyArgument(0)] RoleBehaviour otherPlayerRole, ref Color __result) { - if (PlayerControl.LocalPlayer.Data.IsDead) + if (PlayerControl.LocalPlayer.Data.Role.IsImpostor && otherPlayerRole.IsImpostor) { - __result = otherPlayerRole.NameColor; - return false; + return true; } - if (PlayerControl.LocalPlayer.Data.Role.IsImpostor && otherPlayerRole.IsImpostor) + if (GameManager.Instance.IsHideAndSeek()) { return true; } diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs index 51788732..1c37baba 100644 --- a/MiraAPI/PluginLoading/MiraPluginManager.cs +++ b/MiraAPI/PluginLoading/MiraPluginManager.cs @@ -85,6 +85,7 @@ public class MiraPluginManager { IModdedOption option = (IModdedOption)property.GetValue(group); option.Group = group; + option.AdvancedRole = group.AdvancedRole; } } }