From 8dd0e7e124072ebfa58e1579f5087eb389a7f953 Mon Sep 17 00:00:00 2001 From: EoF-1141 <61620805+EoF-1141@users.noreply.github.com> Date: Sat, 17 Apr 2021 00:43:58 +0200 Subject: [PATCH] Code to allow FreePlay Mode to work - Modify CheckEndCriteria to check for FreePlay - Added FreePlayFix class, due to lack of finding access to GameModes.FreePlay --- EndGamePatch.cs | 450 ++++++++++++++++++++++++++++++++++++++++++++++++ FreePlayFix.cs | 20 +++ 2 files changed, 470 insertions(+) create mode 100644 EndGamePatch.cs create mode 100644 FreePlayFix.cs diff --git a/EndGamePatch.cs b/EndGamePatch.cs new file mode 100644 index 0000000..72cfff8 --- /dev/null +++ b/EndGamePatch.cs @@ -0,0 +1,450 @@ + +using HarmonyLib; +using static TheOtherRoles.TheOtherRoles; +using static TheOtherRoles.GameHistory; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System.Linq; +using Hazel; +using UnhollowerBaseLib; +using System; +using System.Text; + +using GameOverReason = AMGMAKBHCMN; +using TempData = MFEGHOFFKKA; +using WinningPlayerData = FDAHKHEDJPN; +using DeathReason = EGHDCAKGMKI; +using SystemTypes = BCPJLGGNHBC; +using ISystemType = JBBCJFNFOBB; +using LifeSuppSystemType = GIICFCLBGOD; +using ICriticalSabotage = KMBJMPDCFJE; + +namespace TheOtherRoles { + enum CustomGameOverReason { + LoversWin = 10, + TeamJackalWin = 11, + ChildLose = 12, + JesterWin = 13 + } + + enum WinCondition { + Default, + LoversTeamWin, + LoversSoloWin, + JesterWin, + JackalWin, + ChildLose + } + + static class AdditionalTempData { + // Should be implemented using a proper GameOverReason in the future + public static WinCondition winCondition = WinCondition.Default; + public static bool localIsLover = false; + + + public static void clear() { + winCondition = WinCondition.Default; + localIsLover = false; + + } + } + + [HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.DDIEDPFFHOG))] + public class OnGameEndPatch { + private static GameOverReason gameOverReason; + public static void Prefix(AmongUsClient __instance, ref GameOverReason NEPMFBMGGLF, bool FBEKDLNKNLL) { + gameOverReason = NEPMFBMGGLF; + if ((int)NEPMFBMGGLF >= 10) NEPMFBMGGLF = GameOverReason.ImpostorByKill; + } + + public static void Postfix(AmongUsClient __instance, GameOverReason NEPMFBMGGLF, bool FBEKDLNKNLL) { + AdditionalTempData.clear(); + + // Remove Jester from winners (on Jester win he will be added again, see below) + if (Jester.jester != null) { + WinningPlayerData jesterWinner = null; + foreach (WinningPlayerData winner in TempData.BPDANAHEJDD) + if (winner.NNMPJKHJLMB == Jester.jester.PPMOEEPBHJO.PCLLABJCIPC) jesterWinner = winner; + + if (jesterWinner != null) TempData.BPDANAHEJDD.Remove(jesterWinner); + } + // Remove Jackal and Sidekick from winners (on Jackal win he will be added again, see below) + if (Jackal.jackal != null || Sidekick.sidekick != null) { + List winnersToRemove = new List(); + foreach (WinningPlayerData winner in TempData.BPDANAHEJDD) { + if (winner.NNMPJKHJLMB == Jackal.jackal?.PPMOEEPBHJO?.PCLLABJCIPC) winnersToRemove.Add(winner); + if (winner.NNMPJKHJLMB == Sidekick.sidekick?.PPMOEEPBHJO?.PCLLABJCIPC) winnersToRemove.Add(winner); + foreach(var player in Jackal.formerJackals) { + if (winner.NNMPJKHJLMB == player.PPMOEEPBHJO.PCLLABJCIPC) { + winnersToRemove.Add(winner); + } + } + } + + foreach (var winner in winnersToRemove) { + TempData.BPDANAHEJDD.Remove(winner); + } + } + + bool jesterWin = Jester.jester != null && gameOverReason == (GameOverReason)CustomGameOverReason.JesterWin; + bool childLose = Child.child != null && gameOverReason == (GameOverReason)CustomGameOverReason.ChildLose; + bool loversWin = Lovers.existingAndAlive() && (gameOverReason == (GameOverReason)CustomGameOverReason.LoversWin || (TempData.OMHNAMNPJCP(gameOverReason) && Lovers.existingAndCrewLovers())); // Either they win if they are among the last 3 players, or they win if they are both Crewmates and both alive and the Crew wins (Team Imp/Jackal Lovers can only win solo wins) + bool teamJackalWin = gameOverReason == (GameOverReason)CustomGameOverReason.TeamJackalWin && ((Jackal.jackal != null && !Jackal.jackal.PPMOEEPBHJO.IAGJEKLJCCI) || (Sidekick.sidekick != null && !Sidekick.sidekick.PPMOEEPBHJO.IAGJEKLJCCI)); + + // Child lose + if (childLose) { + TempData.BPDANAHEJDD = new Il2CppSystem.Collections.Generic.List(); + WinningPlayerData wpd = new WinningPlayerData(Child.child.PPMOEEPBHJO); + wpd.APIPIPIKLCE = false; // If "no one is the Child", it will display the Child, but also show defeat to everyone + TempData.BPDANAHEJDD.Add(wpd); + AdditionalTempData.winCondition = WinCondition.ChildLose; + } + + // Jester win + else if (jesterWin) { + TempData.BPDANAHEJDD = new Il2CppSystem.Collections.Generic.List(); + WinningPlayerData wpd = new WinningPlayerData(Jester.jester.PPMOEEPBHJO); + TempData.BPDANAHEJDD.Add(wpd); + AdditionalTempData.winCondition = WinCondition.JesterWin; + } + + // Lovers win conditions + else if (loversWin) { + AdditionalTempData.localIsLover = (PlayerControl.LocalPlayer == Lovers.lover1 || PlayerControl.LocalPlayer == Lovers.lover2); + // Double win for lovers, crewmates also win + if (Lovers.existingAndCrewLovers()) { + AdditionalTempData.winCondition = WinCondition.LoversTeamWin; + TempData.BPDANAHEJDD = new Il2CppSystem.Collections.Generic.List(); + foreach (PlayerControl p in PlayerControl.AllPlayerControls) { + if (p == null) continue; + if (p == Lovers.lover1 || p == Lovers.lover2) + TempData.BPDANAHEJDD.Add(new WinningPlayerData(p.PPMOEEPBHJO)); + else if (p != Jester.jester && p != Jackal.jackal && p != Sidekick.sidekick && !p.PPMOEEPBHJO.FDNMBJOAPFL) + TempData.BPDANAHEJDD.Add(new WinningPlayerData(p.PPMOEEPBHJO)); + } + } + // Lovers solo win + else { + AdditionalTempData.winCondition = WinCondition.LoversSoloWin; + TempData.BPDANAHEJDD = new Il2CppSystem.Collections.Generic.List(); + TempData.BPDANAHEJDD.Add(new WinningPlayerData(Lovers.lover1.PPMOEEPBHJO)); + TempData.BPDANAHEJDD.Add(new WinningPlayerData(Lovers.lover2.PPMOEEPBHJO)); + } + } + + // Jackal win condition (should be implemented using a proper GameOverReason in the future) + else if (teamJackalWin) { + // Jackal wins if nobody except jackal is alive + AdditionalTempData.winCondition = WinCondition.JackalWin; + TempData.BPDANAHEJDD = new Il2CppSystem.Collections.Generic.List(); + WinningPlayerData wpd = new WinningPlayerData(Jackal.jackal.PPMOEEPBHJO); + wpd.FDNMBJOAPFL = false; + TempData.BPDANAHEJDD.Add(wpd); + // If there is a sidekick. The sidekick also wins + if (Sidekick.sidekick != null) { + WinningPlayerData wpdSidekick = new WinningPlayerData(Sidekick.sidekick.PPMOEEPBHJO); + wpdSidekick.FDNMBJOAPFL = false; + TempData.BPDANAHEJDD.Add(wpdSidekick); + } + foreach(var player in Jackal.formerJackals) { + WinningPlayerData wpdFormerJackal = new WinningPlayerData(player.PPMOEEPBHJO); + wpdFormerJackal.FDNMBJOAPFL = false; + TempData.BPDANAHEJDD.Add(wpdFormerJackal); + } + } + + // Reset Settings + RPCProcedure.resetVariables(); + } + } + + [HarmonyPatch(typeof(EndGameManager), nameof(EndGameManager.CMELCNKGDDP))] + public class EndGameManagerSetUpPatch { + public static void Postfix(EndGameManager __instance) { + GameObject bonusText = UnityEngine.Object.Instantiate(__instance.WinText.gameObject); + bonusText.transform.position = new Vector3(__instance.WinText.transform.position.x, __instance.WinText.transform.position.y - 0.8f, __instance.WinText.transform.position.z); + bonusText.transform.localScale = new Vector3(0.7f, 0.7f, 1f); + TMPro.TMP_Text textRenderer = bonusText.GetComponent(); + textRenderer.text = ""; + + if (AdditionalTempData.winCondition == WinCondition.JesterWin) { + textRenderer.text = "Jester Wins"; + textRenderer.color = Jester.color; + } + else if (AdditionalTempData.winCondition == WinCondition.LoversTeamWin) { + if (AdditionalTempData.localIsLover) { + __instance.WinText.text = "Double Victory"; + } + textRenderer.text = "Lovers And Crewmates Win"; + textRenderer.color = Lovers.color; + __instance.BackgroundBar.material.SetColor("_Color", Lovers.color); + } + else if (AdditionalTempData.winCondition == WinCondition.LoversSoloWin) { + textRenderer.text = "Lovers Win"; + textRenderer.color = Lovers.color; + __instance.BackgroundBar.material.SetColor("_Color", Lovers.color); + } + else if (AdditionalTempData.winCondition == WinCondition.JackalWin) { + textRenderer.text = "Team Jackal Wins"; + textRenderer.color = Jackal.color; + } + else if (AdditionalTempData.winCondition == WinCondition.ChildLose) { + textRenderer.text = "Child died"; + textRenderer.color = Child.color; + } + + AdditionalTempData.clear(); + } + } + + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.KMPKPPGPNIH))] + class CheckEndCriteriaPatch { + public static bool Prefix(ShipStatus __instance) { + if (!GameData.Instance) return false; + if (FreePlayFix.isInFreePlay) // if (__instance.DummyLocations != null && __instance.DummyLocations.Count > 0) + return true; // I don't know how to get from ShipStatus GameModes.FreePlay + var statistics = new PlayerStatistics(__instance); + if (CheckAndEndGameForChildLose(__instance)) return false; + if (CheckAndEndGameForJesterWin(__instance)) return false; + if (CheckAndEndGameForSabotageWin(__instance)) return false; + if (CheckAndEndGameForTaskWin(__instance)) return false; + if (CheckAndEndGameForLoverWin(__instance, statistics)) return false; + if (CheckAndEndGameForJackalWin(__instance, statistics)) return false; + if (CheckAndEndGameForImpostorWin(__instance, statistics)) return false; + if (CheckAndEndGameForCrewmateWin(__instance, statistics)) return false; + return false; + } + + private static bool CheckAndEndGameForChildLose(ShipStatus __instance) { + if (Child.triggerChildLose) { + if (!DestroyableSingleton.BMHJGNNOGDM) + { + __instance.enabled = false; + ShipStatus.EABBNOODFGL((GameOverReason)CustomGameOverReason.ChildLose, false); + return true; + } + DestroyableSingleton.CHNDKKBEIDG.ShowPopUp(DestroyableSingleton.CHNDKKBEIDG.GetString(StringNames.GameOverImpostorDead, new Il2CppReferenceArray(0))); + ReviveEveryone(); + return true; + } + return false; + } + + private static bool CheckAndEndGameForJesterWin(ShipStatus __instance) { + if (Jester.triggerJesterWin) { + if (!DestroyableSingleton.BMHJGNNOGDM) + { + __instance.enabled = false; + ShipStatus.EABBNOODFGL((GameOverReason)CustomGameOverReason.JesterWin, false); + return true; + } + DestroyableSingleton.CHNDKKBEIDG.ShowPopUp(DestroyableSingleton.CHNDKKBEIDG.GetString(StringNames.GameOverImpostorDead, new Il2CppReferenceArray(0))); + ReviveEveryone(); + return true; + } + return false; + } + + private static bool CheckAndEndGameForSabotageWin(ShipStatus __instance) { + if (__instance.Systems == null) return false; + ISystemType systemType = __instance.Systems.ContainsKey(SystemTypes.LifeSupp) ? __instance.Systems[SystemTypes.LifeSupp] : null; + if (systemType != null) { + LifeSuppSystemType lifeSuppSystemType = systemType.TryCast(); + if (lifeSuppSystemType != null && lifeSuppSystemType.GPBBPGOINOF < 0f) { + EndGameForSabotage(__instance); + lifeSuppSystemType.GPBBPGOINOF = 10000f; + return true; + } + } + ISystemType systemType2 = __instance.Systems.ContainsKey(SystemTypes.Reactor) ? __instance.Systems[SystemTypes.Reactor] : null; + if (systemType2 == null) { + systemType2 = __instance.Systems.ContainsKey(SystemTypes.Laboratory) ? __instance.Systems[SystemTypes.Laboratory] : null; + } + if (systemType2 != null) { + ICriticalSabotage criticalSystem = systemType2.TryCast(); + if (criticalSystem != null && criticalSystem.GPBBPGOINOF < 0f) { + EndGameForSabotage(__instance); + criticalSystem.ClearSabotage(); + return true; + } + } + return false; + } + + private static bool CheckAndEndGameForTaskWin(ShipStatus __instance) { + bool localCompletedAllTasks = true; + foreach (PlayerTask t in PlayerControl.LocalPlayer.myTasks) { + localCompletedAllTasks = localCompletedAllTasks && t.FDIIBNGHCAK; + } + + if (!DestroyableSingleton.BMHJGNNOGDM) + { + if (GameData.Instance.TotalTasks <= GameData.Instance.CompletedTasks) + { + __instance.enabled = false; + ShipStatus.EABBNOODFGL(GameOverReason.HumansByTask, false); + return true; + } + } + else if (localCompletedAllTasks) + { + DestroyableSingleton.CHNDKKBEIDG.ShowPopUp(DestroyableSingleton.CHNDKKBEIDG.GetString(StringNames.GameOverTaskWin, new Il2CppReferenceArray(0))); + __instance.Begin(); + return true; + } + return false; + } + + private static bool CheckAndEndGameForLoverWin(ShipStatus __instance, PlayerStatistics statistics) { + if (statistics.TeamLoversAlive == 2 && statistics.TotalAlive <= 3) { + if (!DestroyableSingleton.BMHJGNNOGDM) + { + __instance.enabled = false; + ShipStatus.EABBNOODFGL((GameOverReason)CustomGameOverReason.LoversWin, false); + return true; + } + DestroyableSingleton.CHNDKKBEIDG.ShowPopUp(DestroyableSingleton.CHNDKKBEIDG.GetString(StringNames.GameOverImpostorDead, new Il2CppReferenceArray(0))); + ReviveEveryone(); + return true; + } + return false; + } + + private static bool CheckAndEndGameForJackalWin(ShipStatus __instance, PlayerStatistics statistics) { + if (statistics.TeamJackalAlive >= statistics.TotalAlive - statistics.TeamJackalAlive && statistics.TeamImpostorsAlive == 0 && !(statistics.TeamJackalHasAliveLover && statistics.TeamLoversAlive == 2)) { + if (!DestroyableSingleton.BMHJGNNOGDM) + { + __instance.enabled = false; + ShipStatus.EABBNOODFGL((GameOverReason)CustomGameOverReason.TeamJackalWin, false); + return true; + } + DestroyableSingleton.CHNDKKBEIDG.ShowPopUp(DestroyableSingleton.CHNDKKBEIDG.GetString(StringNames.GameOverImpostorKills, new Il2CppReferenceArray(0))); + ReviveEveryone(); + return true; + } + return false; + } + + private static bool CheckAndEndGameForImpostorWin(ShipStatus __instance, PlayerStatistics statistics) { + if (statistics.TeamImpostorsAlive >= statistics.TotalAlive - statistics.TeamImpostorsAlive && statistics.TeamJackalAlive == 0 && !(statistics.TeamImpostorHasAliveLover && statistics.TeamLoversAlive == 2)) { + if (!DestroyableSingleton.BMHJGNNOGDM) { + __instance.enabled = false; + GameOverReason endReason; + switch (TempData.PJPCCFAPCKJ) { + case DeathReason.Exile: + endReason = GameOverReason.ImpostorByVote; + break; + case DeathReason.Kill: + endReason = GameOverReason.ImpostorByKill; + break; + default: + endReason = GameOverReason.ImpostorByVote; + break; + } + ShipStatus.EABBNOODFGL(endReason, false); + return true; + } + DestroyableSingleton.CHNDKKBEIDG.ShowPopUp(DestroyableSingleton.CHNDKKBEIDG.GetString(StringNames.GameOverImpostorKills, new Il2CppReferenceArray(0))); + ReviveEveryone(); + return true; + } + return false; + } + + private static bool CheckAndEndGameForCrewmateWin(ShipStatus __instance, PlayerStatistics statistics) { + if (statistics.TeamImpostorsAlive == 0 && statistics.TeamJackalAlive == 0) { + if (!DestroyableSingleton.BMHJGNNOGDM) { + __instance.enabled = false; + ShipStatus.EABBNOODFGL(GameOverReason.HumansByVote, false); + return true; + } + DestroyableSingleton.CHNDKKBEIDG.ShowPopUp(DestroyableSingleton.CHNDKKBEIDG.GetString(StringNames.GameOverImpostorDead, new Il2CppReferenceArray(0))); + ReviveEveryone(); + return true; + } + return false; + } + + private static void ReviveEveryone() { + for (int i = 0; i < GameData.Instance.MFDAIFHGKMG; i++) + GameData.Instance.AllPlayers[i].GJPBCGFPMOD.Revive(); + DeadBody[] array = UnityEngine.Object.FindObjectsOfType(); + for (int i = 0; i < array.Length; i++) UnityEngine.Object.Destroy(array[i].gameObject); + } + + private static void EndGameForSabotage(ShipStatus __instance) + { + if (!DestroyableSingleton.BMHJGNNOGDM) + { + __instance.enabled = false; + ShipStatus.EABBNOODFGL(GameOverReason.ImpostorBySabotage, false); + return; + } + DestroyableSingleton.CHNDKKBEIDG.ShowPopUp(DestroyableSingleton.CHNDKKBEIDG.GetString(StringNames.GameOverSabotage, new Il2CppReferenceArray(0))); + ReviveEveryone(); + } + + } + + internal class PlayerStatistics { + public int TeamImpostorsAlive {get;set;} + public int TeamJackalAlive {get;set;} + public int TeamLoversAlive {get;set;} + public int TotalAlive {get;set;} + public bool TeamImpostorHasAliveLover {get;set;} + public bool TeamJackalHasAliveLover {get;set;} + + public PlayerStatistics(ShipStatus __instance) { + GetMFDAIFHGKMGs(); + } + + private bool isLover(GameData.LGBOMGHJELL p) { + return (Lovers.lover1 != null && Lovers.lover1.PlayerId == p.FNPNJHNKEBK) || (Lovers.lover2 != null && Lovers.lover2.PlayerId == p.FNPNJHNKEBK); + } + + private void GetMFDAIFHGKMGs() { + int numJackalAlive = 0; + int numImpostorsAlive = 0; + int numLoversAlive = 0; + int numTotalAlive = 0; + bool impLover = false; + bool jackalLover = false; + + for (int i = 0; i < GameData.Instance.MFDAIFHGKMG; i++) + { + GameData.LGBOMGHJELL LGBOMGHJELL = GameData.Instance.AllPlayers[i]; + if (!LGBOMGHJELL.MFFAGDHDHLO) + { + if (!LGBOMGHJELL.IAGJEKLJCCI) + { + numTotalAlive++; + + bool lover = isLover(LGBOMGHJELL); + if (lover) numLoversAlive++; + + if (LGBOMGHJELL.FDNMBJOAPFL) { + numImpostorsAlive++; + if (lover) impLover = true; + } + if (Jackal.jackal != null && Jackal.jackal.PlayerId == LGBOMGHJELL.FNPNJHNKEBK) { + numJackalAlive++; + if (lover) jackalLover = true; + } + if (Sidekick.sidekick != null && Sidekick.sidekick.PlayerId == LGBOMGHJELL.FNPNJHNKEBK) { + numJackalAlive++; + if (lover) jackalLover = true; + } + } + } + } + + TeamJackalAlive = numJackalAlive; + TeamImpostorsAlive = numImpostorsAlive; + TeamLoversAlive = numLoversAlive; + TotalAlive = numTotalAlive; + TeamImpostorHasAliveLover = impLover; + TeamJackalHasAliveLover = jackalLover; + } + } +} \ No newline at end of file diff --git a/FreePlayFix.cs b/FreePlayFix.cs new file mode 100644 index 0000000..816f762 --- /dev/null +++ b/FreePlayFix.cs @@ -0,0 +1,20 @@ +using System; +using System.Linq; +using HarmonyLib; +using UnityEngine; + +namespace TheOtherRoles { + [HarmonyPatch] + public static class FreePlayFix { + public static bool isInFreePlay = false; + + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.Begin))] + public static class ShipStatusBeginPatch { + public static void Prefix(ShipStatus __instance) { + System.Console.WriteLine("Begin"); + isInFreePlay = UnityEngine.Object.FindObjectsOfType().ToList() + .Find(console => console.name == "TaskAddConsole"); + } + } + } +} \ No newline at end of file -- 2.39.5