using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using Archipelago.MultiClient.Net; using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; using Archipelago.MultiClient.Net.Enums; using Archipelago.MultiClient.Net.Helpers; using Archipelago.MultiClient.Net.Models; using Archipelago.MultiClient.Net.Packets; using BepInEx; using BepInEx.Logging; using Enemy; using Equipment; using HarmonyLib; using IAmYourBeastArchipelago.Archipelago; using IAmYourBeastArchipelago.Core; using IAmYourBeastArchipelago.Helpers; using IAmYourBeastArchipelago.Patches; using Progress; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("UnityEngine")] [assembly: AssemblyCompany("IAmYourBeastArchipelago")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("IAmYourBeastArchipelago")] [assembly: AssemblyTitle("IAmYourBeastArchipelago")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] public class CoroutineRunner : MonoBehaviour { private static CoroutineRunner _instance; public static CoroutineRunner Instance { get { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)_instance == (Object)null) { GameObject val = new GameObject("IAYB_CoroutineRunner"); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent(); } return _instance; } } } namespace IAmYourBeastArchipelago { public static class PluginInfo { public const string PLUGIN_GUID = "IAmYourBeastArchipelago"; public const string PLUGIN_NAME = "IAmYourBeastArchipelago"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace IAmYourBeastArchipelago.Helpers { public class UIHelpers : MonoBehaviour { private static GameObject connectUIObject; private bool showWindow = true; private string host = "archipelago.gg:"; private string slotName = ""; private string password = ""; private static string statusMessage = ""; private static bool isError = false; private Rect windowRect = new Rect(20f, 20f, 270f, 270f); public static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown Plugin.Log.LogWarning((object)"UIHelpers.OnSceneLoaded called"); if (((Scene)(ref scene)).name == "Start Screen") { if ((Object)(object)connectUIObject == (Object)null) { connectUIObject = new GameObject("APConnectWindow"); connectUIObject.AddComponent(); Object.DontDestroyOnLoad((Object)(object)connectUIObject); } connectUIObject.SetActive(true); } else if ((Object)(object)connectUIObject != (Object)null) { connectUIObject.SetActive(false); } } private void OnGUI() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (showWindow) { windowRect = GUI.Window(16720, windowRect, new WindowFunction(DrawWindow), "Archipelago Connect"); } } private void DrawWindow(int id) { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) GUILayout.Space(8f); GUILayout.Label("Host:Port", Array.Empty()); host = GUILayout.TextField(host, Array.Empty()); GUILayout.Label("Slot Name", Array.Empty()); slotName = GUILayout.TextField(slotName, Array.Empty()); GUILayout.Label("Password (optional)", Array.Empty()); password = GUILayout.TextField(password, Array.Empty()); GUILayout.Space(10f); if (ArchipelagoManager.IsConnected) { if (GUILayout.Button("Disconnect", Array.Empty())) { AttemptDisconnect(); } } else if (GUILayout.Button("Connect", Array.Empty())) { AttemptConnect(); } if (!string.IsNullOrEmpty(statusMessage)) { Color color = GUI.color; GUI.color = (isError ? Color.red : Color.green); GUILayout.Label(statusMessage, Array.Empty()); GUI.color = color; } GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f)); } private void AttemptConnect() { if (string.IsNullOrWhiteSpace(host) || string.IsNullOrWhiteSpace(slotName)) { statusMessage = "Host and slot name are required."; isError = true; return; } try { ArchipelagoManager.Connect(host, slotName, password); if (ArchipelagoManager.IsConnected) { GameManager.instance.saveManager.InitializeSaveFiles(); ProgressTracker.PopulateProgress(); ArchipelagoTrapManager.ResetTraps(); statusMessage = "Successfully connected to Archipelago"; isError = false; } else { statusMessage = "Could not connect to Archipelago"; isError = true; } } catch (Exception ex) { statusMessage = "Error: " + ex.Message; isError = true; } } private void AttemptDisconnect() { ArchipelagoManager.Disconnect(); statusMessage = "Disconnected from Archipelago"; isError = true; } public static void DisplayMessage(string message, bool error) { statusMessage = message; isError = error; } } public static class HintHelper { private static int hintIndex = -1; private static readonly List<(Func IsActive, Func Text)> hints = new List<(Func, Func)> { (() => true, () => $"You currently have {ProgressTracker.UnlockedCount} levels unlocked"), (() => SlotData.RequiredLevels > 0, () => $"You have completed {ProgressTracker.CompletedCount} levels out of the required {SlotData.RequiredLevels}"), (() => SlotData.RequiredSRanks > 0, () => $"You have completed {ProgressTracker.CompletedSRankCount} S ranks out of the required {SlotData.RequiredSRanks}"), (() => SlotData.RequiredBonusObjectives > 0, () => $"You have completed {ProgressTracker.CompletedBonusObjectives} Bonus Objectives out of the required {SlotData.RequiredBonusObjectives}") }; public static string GetCurrentHint() { List<(Func, Func)> list = hints.Where(((Func IsActive, Func Text) h) => h.IsActive()).ToList(); if (list.Count == 0) { return "No hints available."; } hintIndex = (hintIndex + 1) % list.Count; return list[hintIndex].Item2(); } } public static class PlayerHelper { public static bool IsPlayerActivelyInLevel() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Invalid comparison between Unknown and I4 Player val = GameManager.instance?.player; if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)val.GetHealthManager() == (Object)null) { return false; } if (val.GetHealthManager().IsDead()) { return false; } LevelController val2 = GameManager.instance?.levelController; if ((Object)(object)val2 == (Object)null) { return false; } if ((int)val2.GetLevelState() != 1) { return false; } return true; } } } namespace IAmYourBeastArchipelago.Patches { [HarmonyPatch(typeof(LevelData), "SetLevelCompleted")] public static class LevelCompletePatch { private static void Postfix(LevelData __instance) { if (__instance != null) { AirStrikePatches.SetAirStrikeEnabled(enabled: false); ProgressTracker.SendLevelCheck(__instance); } } } [HarmonyPatch(typeof(LevelData), "SetSnowmanDestroyed")] public static class SnowmanDestroyedPatch { private static void Postfix(LevelData __instance) { if (__instance != null) { ProgressTracker.SendSnowmanCheck(__instance); } } } [HarmonyPatch(typeof(UILevelCompleteTimeScoreBar), "Update")] public static class GradeUpdatePatch { private static void Postfix() { LevelInformation information = GameManager.instance.levelController.GetInformationSetter().GetInformation(); if (!((Object)(object)information == (Object)null)) { LevelData levelData = GameManager.instance.progressManager.GetLevelData(information); if (levelData != null && levelData.GetCurrentGrade() >= 4) { ProgressTracker.SendMaxGradeCheck(levelData); } } } } [HarmonyPatch(typeof(LevelData), "IncreaseCurrentBonusObjective")] public static class BonusObjectiveIncreasePatch { private static void Prefix(LevelData __instance, out int __state) { __state = __instance.GetCurrentBonusObjectiveIndex(); } private static void Postfix(LevelData __instance, int __state) { ProgressTracker.SendBonusObjectiveCheck(__instance, __state); } } [HarmonyPatch(typeof(SceneInformation), "IsUnlocked")] public static class LevelUnlockGatePatch { private static void Postfix(SceneInformation __instance, ref bool __result) { if ((Object)(object)__instance == (Object)null) { __result = false; return; } LevelInformation val = (LevelInformation)(object)((__instance is LevelInformation) ? __instance : null); if (val == null) { __result = false; return; } ProgressManager val2 = GameManager.instance?.progressManager; if ((Object)(object)GameManager.instance == (Object)null && (Object)(object)val2 == (Object)null) { __result = false; return; } LevelData levelData = val2.GetLevelData(val); if (levelData == null) { __result = false; return; } ProgressTracker.LevelKey key = new ProgressTracker.LevelKey(levelData.GetCategory(), levelData.GetID()); __result = ProgressTracker.IsUnlocked(key); } } [HarmonyPatch(typeof(PlayerSpawner), "Spawn")] public static class ApplyPendingTrapsOnSpawnPatch { private static void Postfix() { Player val = GameManager.instance?.player; if (!((Object)(object)val == (Object)null)) { ArchipelagoTrapManager.ApplyPendingTraps(val); } } } [HarmonyPatch(typeof(PlayerArmManager), "EquipWeapon")] public static class DisarmPatch { private static void Prefix(WeaponPickup pickup) { ArchipelagoTrapManager.NotifyWeaponEquipped(pickup); } } [HarmonyPatch(typeof(PlayerMovement), "CanKick")] public static class KickPatch { private static void Postfix(ref bool __result) { if (!WeaponTracker.isWeaponUnlocked["Kick"] && SlotData.IsKickUnlock) { __result = false; } } } [HarmonyPatch(typeof(PlayerHealthManager), "Update")] public static class DeathLinkRecievePatch { private static void Postfix() { if (HealthManager.pendingDeathLinkKill) { HealthManager.pendingDeathLinkKill = false; HealthManager.KillPlayer(); } } } [HarmonyPatch(typeof(PlayerSpawner), "Spawn")] public static class DisableAirStrikePatch { private static void Prefix() { if (AirStrikePatches.IsAirStrikeEnabled) { AirStrikePatches.SetAirStrikeEnabled(enabled: false); } } } [HarmonyPatch(typeof(SaveSystem), "GetSaveStateFilePath")] public static class SaveLocationOverridePatch { private static string ApSaveFolder => Path.Combine(Application.persistentDataPath, "..", "ArchipelagoSaves"); private static bool Prefix(ref string __result) { Directory.CreateDirectory(ApSaveFolder); string path = (ArchipelagoManager.IsConnected ? ("IAYBSave_" + ArchipelagoManager.Seed + ".sav") : "IAYBSave_Dummy.sav"); __result = Path.Combine(ApSaveFolder, path); return false; } } [HarmonyPatch(typeof(UILevelSelectCategorySlide), "RefreshValues")] public static class CategoryUnlockUIPatch { private static void Postfix(UILevelSelectCategorySlide __instance) { string displayName = __instance.GetLevelCollection().GetDisplayName(); if (1 == 0) { } bool flag = displayName switch { "Story" => !SlotData.IsStoryIncluded, "Challenge" => !SlotData.IsChallengeIncluded, "Support Group" => !SlotData.IsSupportGroupIncluded, "Cold Sweat" => !SlotData.IsColdSweatIncluded, _ => false, }; if (1 == 0) { } if (flag) { __instance.lockedText.text = "This collection is not included"; return; } __instance.locked = false; if ((Object)(object)__instance.lockedAnchor != (Object)null) { __instance.lockedAnchor.SetActive(false); } if ((Object)(object)__instance.unlockedAnchor != (Object)null) { __instance.unlockedAnchor.SetActive(true); } } } [HarmonyPatch(typeof(UIStartScreenRoot), "StartSceneTransition")] public static class SkipTutorialPatch { private static void Postfix() { UISceneTransitionFade val = Object.FindObjectOfType(); if ((Object)(object)val != (Object)null) { ((UISceneTransition)val).SetDestination("Scenes/UI/Menus/LevelSelect"); } } } [HarmonyPatch(typeof(UIStartScreenRoot), "StartGame")] public static class DisableStartPatch { private static bool Prefix() { if (ArchipelagoManager.IsConnected) { return true; } UIHelpers.DisplayMessage("You have to connect to an Archipelago session before staring the game.", error: true); return false; } } [HarmonyPatch(typeof(UIHintDisplay), "Start")] internal class UIHintDisplay_Start_Patch { private static void Postfix(UIHintDisplay __instance) { Traverse.Create((object)__instance).Field("timeBeforeRefresh").SetValue((object)5f); } } [HarmonyPatch(typeof(HintManager), "GetCurrentHint")] public static class HintOverridePatch { private static void Postfix(ref string __result) { __result = HintHelper.GetCurrentHint(); } } [HarmonyPatch(typeof(WeaponPickup), "SetHighlighted")] public static class WeaponHighlightPatch { private static void Postfix(WeaponPickup __instance) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) HighlightRenderer[] highlightRenderers = __instance.highlightRenderers; if (highlightRenderers != null) { HighlightType val = (HighlightType)1; if (WeaponTracker.IsWeaponUnlocked(__instance.GetDisplayName())) { val = (HighlightType)0; } HighlightRenderer[] array = highlightRenderers; foreach (HighlightRenderer val2 in array) { val2.Initialize(val); val2.RefreshHighlighted(); } } } } [HarmonyPatch(typeof(WeaponPickup), "Use")] public static class DisableWeaponPickupPatch { private static bool Prefix(WeaponPickup __instance) { return WeaponTracker.IsWeaponUnlocked(__instance.GetDisplayName()); } } [HarmonyPatch(typeof(EquipmentPickup), "Use")] public static class DisableEquipmentPickupPatch { private static bool Prefix(EquipmentPickup __instance) { return WeaponTracker.IsWeaponUnlocked(((PlayerInteractable)__instance).GetPromptDescription()); } } [HarmonyPatch(typeof(EquipmentPickup), "Start")] public static class EquipmentHighlightPatch { private static void Postfix(EquipmentPickup __instance) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) HighlightRenderer[] highlightRenderers = __instance.highlightRenderers; if (highlightRenderers != null) { HighlightType val = (HighlightType)1; if (WeaponTracker.IsWeaponUnlocked(((PlayerInteractable)__instance).GetPromptDescription())) { val = (HighlightType)0; } HighlightRenderer[] array = highlightRenderers; foreach (HighlightRenderer val2 in array) { val2.Initialize(val); val2.RefreshHighlighted(); } } } } public static class AirStrikePatches { [HarmonyPatch(typeof(AirStrikeController), "IsEnabled")] public static class EnableAirStrikePatch { private static void Postfix(ref bool __result) { if (isAirStrikeEnabled) { __result = true; } } } [HarmonyPatch(typeof(AirStrikeController), "Spawn")] public static class DisableAirStrikePatch { private static void Postfix() { SetAirStrikeEnabled(enabled: false); } } private static bool isAirStrikeEnabled; public static bool IsAirStrikeEnabled => isAirStrikeEnabled; public static void SetAirStrikeEnabled(bool enabled) { isAirStrikeEnabled = enabled; } } public class PickupPatches { [HarmonyPatch(typeof(LevelController), "StartLevelIntro")] public class GetAllLevelPickupsPatch { private const string LimboScene = "##_CS_Limbo"; private static readonly string[] LimboStageOrder = new string[3] { "STAGE #1", "STAGE #2", "STAGE #3" }; private static void Postfix(LevelController __instance) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) LevelInformationSetter informationSetter = __instance.GetInformationSetter(); LevelInformation val = ((informationSetter != null) ? informationSetter.GetInformation() : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"No LevelInformation found, skipping."); return; } LevelData levelData = GameManager.instance.progressManager.GetLevelData(val); if (levelData == null) { Plugin.Log.LogWarning((object)("No LevelData for '" + ((Object)val).name + "', skipping.")); return; } string category = levelData.GetCategory(); int iD = levelData.GetID(); Scene activeScene = SceneManager.GetActiveScene(); PlayerHealthPickup[] pickups = ((((Scene)(ref activeScene)).name == "##_CS_Limbo") ? HarvestLimboStages() : Object.FindObjectsOfType()); RebuildPickups(category, iD, pickups); } private static PlayerHealthPickup[] HarvestLimboStages() { List list = new List(); string[] limboStageOrder = LimboStageOrder; foreach (string text in limboStageOrder) { GameObject val = FindStageRoot(text); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("[LIMBO-HARVEST] Could not find stage root '" + text + "'")); continue; } Transform val2 = FindChildByPath(val.transform, "[GAMEPLAY]", "---(Pickups)---"); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("[LIMBO-HARVEST] Could not find Pickups folder under '" + text + "'")); } else { list.AddRange(((Component)val2).GetComponentsInChildren(true)); } } return list.ToArray(); } private static GameObject FindStageRoot(string stageName) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) Transform[] array = Resources.FindObjectsOfTypeAll(); foreach (Transform val in array) { if ((Object)(object)val.parent == (Object)null && ((Object)val).name == stageName) { Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { return ((Component)val).gameObject; } } } return null; } private static Transform FindChildByPath(Transform root, params string[] path) { Transform val = root; foreach (string text in path) { val = val.Find(text); if ((Object)(object)val == (Object)null) { return null; } } return val; } } [HarmonyPatch(typeof(PlayerHealthPickup), "Use")] public class PickupUsePatch { private static void Postfix(PlayerHealthPickup __instance) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (SlotData.PickupLocations == "individual") { int index = currentLevelPickups.IndexOf(__instance); ProgressTracker.SendIndividualPickupCheck(index, currentLevel); } if (SlotData.PickupLocations == "grouped") { collectedPickups.Add(__instance); if (collectedPickups.Count >= GetGroupedTarget()) { ProgressTracker.SendGroupedPickupCheck(currentLevel); } } HighlightRenderer[] highlights = __instance.highlights; if (highlights != null) { HighlightType val = (HighlightType)0; HighlightRenderer[] array = highlights; foreach (HighlightRenderer val2 in array) { val2.Initialize(val); val2.RefreshHighlighted(); } } } } [HarmonyPatch(typeof(PlayerHealthPickup), "Start")] public class PickupHighlightPatch { private static void Postfix(PlayerHealthPickup __instance) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) HighlightRenderer[] highlights = __instance.highlights; if (highlights != null) { HighlightType val = (HighlightType)2; int index = currentLevelPickups.IndexOf(__instance); if (ProgressTracker.IsPickupComplete(index, currentLevel)) { val = (HighlightType)0; } HighlightRenderer[] array = highlights; foreach (HighlightRenderer val2 in array) { val2.Initialize(val); val2.RefreshHighlighted(); } } } } public static ProgressTracker.LevelKey currentLevel; public static List currentLevelPickups = new List(); public static HashSet collectedPickups = new HashSet(); private static readonly Dictionary ExcludedIndices = new Dictionary { { new ProgressTracker.LevelKey("Main", 19), new int[1] { 8 } }, { new ProgressTracker.LevelKey("Main", 22), new int[1] }, { new ProgressTracker.LevelKey("Main", 24), new int[1] }, { new ProgressTracker.LevelKey("Challenge", 3), new int[5] { 1, 3, 4, 5, 6 } }, { new ProgressTracker.LevelKey("Challenge", 7), new int[1] { 4 } }, { new ProgressTracker.LevelKey("Challenge", 9), new int[1] { 7 } }, { new ProgressTracker.LevelKey("Challenge", 12), new int[1] { 4 } }, { new ProgressTracker.LevelKey("PostLaunchPack1", 9), new int[1] { 1 } }, { new ProgressTracker.LevelKey("WIP", 5), new int[4] { 1, 2, 5, 8 } } }; private static readonly Dictionary GroupedTolerance = new Dictionary { { new ProgressTracker.LevelKey("Main", 21), 3 }, { new ProgressTracker.LevelKey("PostLaunchPack1", 5), 8 } }; private static int GetGroupedTarget() { int num = 0; _ = currentLevel; if (GroupedTolerance.TryGetValue(currentLevel, out var value)) { num = value; } return Mathf.Max(0, currentLevelPickups.Count - num); } private static void RebuildPickups(string category, int id, PlayerHealthPickup[] pickups) { currentLevelPickups.Clear(); collectedPickups.Clear(); currentLevel = new ProgressTracker.LevelKey(category, id); if (ExcludedIndices.TryGetValue(currentLevel, out var value)) { HashSet hashSet = new HashSet(value); for (int i = 0; i < pickups.Length; i++) { if (!hashSet.Contains(i)) { currentLevelPickups.Add(pickups[i]); } } } else { currentLevelPickups.AddRange(pickups); } Plugin.Log.LogInfo((object)$"[Pickups] [{category}] {id}: {currentLevelPickups.Count} pickups"); } } public static class HUDPatches { [HarmonyPatch(typeof(HUDGPSIconPickup), "SetPickup")] public static class HUDDisablePickupPatch { private static bool Prefix(PlayerInteractable pickup) { if (IsUnlocked(pickup)) { return true; } return false; } } [HarmonyPatch(typeof(HUDInteractionPrompt), "RefreshHighlight")] private class SuppressPromptPatch { private static bool Prefix(ref PlayerInteractable interactable) { if (!IsUnlocked(interactable)) { interactable = null; } return true; } } private static bool IsUnlocked(PlayerInteractable pickup) { WeaponPickup val = (WeaponPickup)(object)((pickup is WeaponPickup) ? pickup : null); if (val != null) { return WeaponTracker.isWeaponUnlocked[val.GetDisplayName()]; } EquipmentPickup val2 = (EquipmentPickup)(object)((pickup is EquipmentPickup) ? pickup : null); if (val2 != null) { return WeaponTracker.isWeaponUnlocked[((PlayerInteractable)val2).GetPromptDescription()]; } return true; } } [HarmonyPatch(typeof(LevelController), "FailLevel")] public static class SendDeathPatch { private static void Postfix() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown Plugin.Log.LogInfo((object)"Send Death Start!"); if (SlotData.DeathLinkEnabled && !HealthManager.isDeathLinkDeath) { HealthManager.deathCount++; Plugin.Log.LogInfo((object)$"Death count: {HealthManager.deathCount} / {SlotData.DeathlinkAmnesty}"); if (HealthManager.deathCount >= SlotData.DeathlinkAmnesty) { Plugin.Log.LogInfo((object)"Sending DeathLink"); ArchipelagoManager.DeathLinkService.SendDeathLink(new DeathLink(ArchipelagoManager.Session.Players.GetPlayerAlias(ArchipelagoManager.SlotNumber), (string)null)); HealthManager.deathCount = 0; } } if (HealthManager.isDeathLinkDeath) { HealthManager.isDeathLinkDeath = false; } Plugin.Log.LogInfo((object)"Send Death End!"); } } public static class CreditsPatch { private static bool _hooked; public static void Hook() { if (!_hooked) { _hooked = true; SceneManager.sceneLoaded += OnSceneLoaded; } } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (((Scene)(ref scene)).name != "#027_Special_EndCredits") { return; } ProgressTracker.LevelKey key = new ProgressTracker.LevelKey("Main", 27); if (!ProgressTracker.levelStates.TryGetValue(key, out var value) || !value.sentLevelCheck) { ArchipelagoManager.SendCheck(ItemTranslator.ParseLevelKeyToAp(key)); ProgressTracker.levelStates[key] = new ProgressTracker.LevelState { sentLevelCheck = true }; if (ProgressTracker.CheckCompletion()) { ArchipelagoManager.SendGoalCompletion(); } } } } } namespace IAmYourBeastArchipelago.Archipelago { public static class ArchipelagoManager { private const string GameName = "IAmYourBeast"; public static ArchipelagoSession Session; public static bool IsConnected; public static string Seed; public static int SlotNumber; internal static DeathLinkService DeathLinkService; private static bool manualDisconnect; public static event Action OnUnexpectedDisconnect; public static void Connect(string host, string slot, string password = null) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown manualDisconnect = false; Session = ArchipelagoSessionFactory.CreateSession(host, 38281); LoginResult val = Session.TryConnectAndLogin("IAmYourBeast", slot, (ItemsHandlingFlags)7, new Version(0, 6, 7), (string[])null, (string)null, password, true); if (!val.Successful) { LoginFailure val2 = (LoginFailure)val; return; } IsConnected = true; LoginSuccessful val3 = (LoginSuccessful)val; SlotData.SetSlotData(val3.SlotData); SlotNumber = val3.Slot; DeathLinkService = DeathLinkProvider.CreateDeathLinkService(Session); Seed = Session.RoomState.Seed; ProgressTracker.SetAllLocationsChecked(Session.Locations.AllLocationsChecked); InitializeListeners(); } public static void Disconnect() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown manualDisconnect = true; if (Session != null) { Session.Socket.SocketClosed -= new SocketClosedHandler(OnSocketClosed); Session.Socket.DisconnectAsync(); Session = null; } IsConnected = false; } public static void SendCheck(string name) { if (Session != null) { long locationIdFromName = Session.Locations.GetLocationIdFromName("IAmYourBeast", name); Session.Locations.CompleteLocationChecksAsync(new long[1] { locationIdFromName }); } } public static void InitializeListeners() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown if (Session != null) { Session.Items.ItemReceived += new ItemReceivedHandler(OnItemReceived); Session.Socket.SocketClosed += new SocketClosedHandler(OnSocketClosed); Plugin.Log.LogWarning((object)"Subscribed to SocketClosed"); if (SlotData.DeathLinkEnabled) { DeathLinkService.OnDeathLinkReceived += new DeathLinkReceivedHandler(OnDeathLink); DeathLinkService.EnableDeathLink(); } } } private static void OnSocketClosed(string reason) { Plugin.Log.LogWarning((object)("OnSocketClosed fired: " + reason)); IsConnected = false; if (!manualDisconnect) { ArchipelagoManager.OnUnexpectedDisconnect?.Invoke(reason); } } private static void OnItemReceived(ReceivedItemsHelper helper) { while (helper.Any()) { ItemInfo val = helper.DequeueItem(); ArchipelagoItemHandler.HandleItem(val.ItemName, (int)val.ItemId); } } private static void OnDeathLink(DeathLink deathLink) { HealthManager.pendingDeathLinkKill = true; } public static void SendGoalCompletion() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown if (Session != null) { StatusUpdatePacket val = new StatusUpdatePacket { Status = (ArchipelagoClientState)30 }; Session.Socket.SendPacketAsync((ArchipelagoPacketBase)(object)val); } } public static string ArchipelagoIdToName(long id) { return Session.Locations.GetLocationNameFromId(id, "IAmYourBeast"); } } public static class ArchipelagoItemHandler { public static void HandleItem(string itemName, int itemId) { if (itemId < 100) { HandleLevel(itemName); } else if (itemId < 200) { HandleTrap(itemName); } else if (itemId < 300) { HandleFiller(itemName); } else if (itemId < 400) { WeaponTracker.UnlockWeapon(itemName); } } private static void HandleLevel(string name) { ProgressTracker.UnlockLevel(name); } private static void HandleTrap(string name) { Plugin.Log.LogInfo((object)("Sending trap: " + name)); switch (name) { case "Bleed Trap": ArchipelagoTrapManager.QueueTrap(TrapType.BleedTrap); break; case "Immobilizer Trap": ArchipelagoTrapManager.QueueTrap(TrapType.ImmobilizerTrap); break; case "Disarm Trap": ArchipelagoTrapManager.QueueTrap(TrapType.DisarmTrap); break; case "Air Strike Trap": ArchipelagoTrapManager.QueueTrap(TrapType.AirStrikeTrap); break; } } private static void HandleFiller(string name) { if (name == "Super Strength") { ArchipelagoTrapManager.QueueTrap(TrapType.SuperStrength); } else { HealthManager.ApplyHeal(name); } } } public static class ItemTranslator { private static readonly Dictionary CategoryMap; private static readonly Dictionary ReverseCategoryMap; static ItemTranslator() { CategoryMap = new Dictionary { { "Story", "Main" }, { "Challenge", "Challenge" }, { "Support Group", "PostLaunchPack1" }, { "Cold Sweat", "WIP" } }; ReverseCategoryMap = new Dictionary(); foreach (KeyValuePair item in CategoryMap) { ReverseCategoryMap[item.Value] = item.Key; } } public static string ToArchipelagoCategory(string apCategory) { if (ReverseCategoryMap.TryGetValue(apCategory, out var value)) { return value; } return apCategory; } public static string ToGameCategory(string gameCategory) { if (CategoryMap.TryGetValue(gameCategory, out var value)) { return value; } return gameCategory; } public static (string category, int id) ParseApNameToLevelKey(string levelName) { string[] array = levelName.Split(new string[1] { " Level " }, StringSplitOptions.None); if (array.Length != 2) { return (category: "", id: -1); } if (!int.TryParse(array[1], out var result)) { return (category: "", id: -1); } if (!CategoryMap.TryGetValue(array[0], out var value)) { return (category: "", id: -1); } return (category: value, id: result); } public static ProgressTracker.LevelKey ParseApIdToLevelKey(long apId) { string text = ArchipelagoManager.ArchipelagoIdToName(apId); string[] array = text.Split(new string[1] { " - " }, StringSplitOptions.None); string[] array2 = array[0].Split(new string[1] { " Level " }, StringSplitOptions.None); if (!int.TryParse(array2[1], out var result)) { return new ProgressTracker.LevelKey("", -1); } if (!CategoryMap.TryGetValue(array2[0], out var value)) { return new ProgressTracker.LevelKey("", -1); } return new ProgressTracker.LevelKey(value, result); } public static int ParseApToPickupIndex(long apId) { string text = ArchipelagoManager.ArchipelagoIdToName(apId); string[] array = text.Split(new string[1] { " - " }, StringSplitOptions.None); if (array.Length < 2 || !array[1].Contains("Pickup")) { return -1; } string[] array2 = array[1].Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length < 2 || !int.TryParse(array2[1], out var result)) { return -1; } return result - 1; } public static bool ParseApToPickupComplete(long apId) { string text = ArchipelagoManager.ArchipelagoIdToName(apId); string[] array = text.Split(new string[1] { " - " }, StringSplitOptions.None); if (array.Length < 2 || !array[1].Contains("Collect Pickups")) { return false; } return true; } public static string ParseLevelKeyToAp(ProgressTracker.LevelKey key) { return $"{ToArchipelagoCategory(key.category)} Level {key.id}"; } public static string ParseLevelKeyToMaxGrade(ProgressTracker.LevelKey key) { return ParseLevelKeyToAp(key) + " - S Rank"; } public static string ParseLevelKeyToSnowman(ProgressTracker.LevelKey key) { return ParseLevelKeyToAp(key) + " - Destroy Snowman"; } public static string ParseLevelKeyToBonusObjective(ProgressTracker.LevelKey key, int index) { return $"{ParseLevelKeyToAp(key)} - Bonus Objective {index + 1}"; } public static string ParseLevelKeyToIndividualPickup(ProgressTracker.LevelKey key, int index) { return $"{ParseLevelKeyToAp(key)} - Pickup {index + 1}"; } public static string ParseLevelKeyToGroupedPickup(ProgressTracker.LevelKey key) { return ParseLevelKeyToAp(key) + " - Collect Pickups"; } } public static class SlotData { public static Dictionary data; public static int RequiredLevels => (data == null) ? 1 : Convert.ToInt32(data["required_levels"]); public static int RequiredSRanks => (data != null) ? Convert.ToInt32(data["required_s_ranks"]) : 0; public static int RequiredBonusObjectives => (data != null) ? Convert.ToInt32(data["required_bonus_objectives"]) : 0; public static bool IsStoryIncluded => data == null || Convert.ToBoolean(data["is_story_included"]); public static bool IsChallengeIncluded => data != null && Convert.ToBoolean(data["is_challenge_included"]); public static bool IsSupportGroupIncluded => data != null && Convert.ToBoolean(data["is_support_group_included"]); public static bool IsColdSweatIncluded => data != null && Convert.ToBoolean(data["is_cold_sweat_included"]); public static bool IsKickUnlock => data != null && Convert.ToBoolean(data["is_kick_unlock"]); public static bool DeathLinkEnabled => data != null && Convert.ToBoolean(data["death_link_enabled"]); public static bool AreWeaponsUnlockable => data != null && Convert.ToBoolean(data["are_weapons_unlockable"]); public static string PickupLocations => (data != null) ? Convert.ToString(data["pickup_locations"]) : "none"; public static int DeathlinkAmnesty => (data != null) ? Convert.ToInt32(data["deathlink_amnesty"]) : 5; public static void SetSlotData(Dictionary slotData) { data = slotData; } } } namespace IAmYourBeastArchipelago.Core { [BepInPlugin("com.petiboy7.iayb.archipelago", "IAYB Archipelago", "0.1.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; private void Awake() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; new Harmony("ap.patch").PatchAll(); SceneManager.sceneLoaded += UIHelpers.OnSceneLoaded; CreditsPatch.Hook(); } } public static class ProgressTracker { public record struct LevelKey(string category, int id); public class LevelState { public bool sentLevelCheck = false; public bool sentMaxGradeCheck = false; public bool sentSnowmanCheck = false; public int sentBonusObjectivesUpTo = -1; public bool completedAllPickups = false; public HashSet sentPickups = new HashSet(); } public static HashSet unlockedLevels = new HashSet(); public static Dictionary levelStates = new Dictionary(); public static Dictionary AllLevels = new Dictionary(); public static ReadOnlyCollection AllCheckedLocations; public static int UnlockedCount => unlockedLevels.Count; public static int CompletedCount => AllLevels.Count((KeyValuePair kv) => IsCompleted(kv.Key, kv.Value)); public static int CompletedSRankCount => AllLevels.Count((KeyValuePair kv) => HasSRank(kv.Value)); public static int CompletedBonusObjectives => AllLevels.Sum((KeyValuePair kv) => BonusCompletedCount(kv.Value)); private static LevelState GetOrCreateState(LevelKey key) { if (!levelStates.TryGetValue(key, out var value)) { value = new LevelState(); levelStates[key] = value; } return value; } private static bool IsCompleted(LevelKey key, LevelData level) { if (key.category == "Main" && key.id == 27) { return level.GetLevelAttempted(); } return level.GetLevelCompleted(); } private static int BonusCompletedCount(LevelData level) { int currentBonusObjectiveIndex = level.GetCurrentBonusObjectiveIndex(); if (currentBonusObjectiveIndex == -1) { return 0; } return currentBonusObjectiveIndex; } public static void UnlockLevel(string name) { (string category, int id) tuple = ItemTranslator.ParseApNameToLevelKey(name); string item = tuple.category; int item2 = tuple.id; LevelKey item3 = new LevelKey(item, item2); unlockedLevels.Add(item3); } public static bool IsUnlocked(LevelKey key) { return unlockedLevels.Contains(key); } public static void SendLevelCheck(LevelData level) { if (level == null) { return; } LevelKey key = new LevelKey(level.GetCategory(), level.GetID()); LevelState orCreateState = GetOrCreateState(key); if (!orCreateState.sentLevelCheck) { orCreateState.sentLevelCheck = true; ArchipelagoManager.SendCheck(ItemTranslator.ParseLevelKeyToAp(key)); if (CheckCompletion()) { ArchipelagoManager.SendGoalCompletion(); } } } public static void SendMaxGradeCheck(LevelData level) { if (level == null) { return; } LevelKey key = new LevelKey(level.GetCategory(), level.GetID()); LevelState orCreateState = GetOrCreateState(key); if (!orCreateState.sentMaxGradeCheck) { orCreateState.sentMaxGradeCheck = true; ArchipelagoManager.SendCheck(ItemTranslator.ParseLevelKeyToMaxGrade(key)); if (CheckCompletion()) { ArchipelagoManager.SendGoalCompletion(); } } } public static void SendSnowmanCheck(LevelData level) { if (level != null) { LevelKey key = new LevelKey(level.GetCategory(), level.GetID()); LevelState orCreateState = GetOrCreateState(key); if (!orCreateState.sentSnowmanCheck) { orCreateState.sentSnowmanCheck = true; ArchipelagoManager.SendCheck(ItemTranslator.ParseLevelKeyToSnowman(key)); } } } public static void SendBonusObjectiveCheck(LevelData level, int completedIndex) { if (level != null && completedIndex >= 0) { LevelKey key = new LevelKey(level.GetCategory(), level.GetID()); LevelState orCreateState = GetOrCreateState(key); for (int i = orCreateState.sentBonusObjectivesUpTo + 1; i <= completedIndex; i++) { ArchipelagoManager.SendCheck(ItemTranslator.ParseLevelKeyToBonusObjective(key, i)); } orCreateState.sentBonusObjectivesUpTo = completedIndex; if (CheckCompletion()) { ArchipelagoManager.SendGoalCompletion(); } } } public static bool CheckCompletion() { FillAllLevels(); if (CompletedCount >= SlotData.RequiredLevels && CompletedSRankCount >= SlotData.RequiredSRanks && CompletedBonusObjectives >= SlotData.RequiredBonusObjectives) { return true; } return false; } public static bool HasSRank(LevelData level) { return level.GetCurrentGrade() >= 4; } public static void PopulateProgress() { FillAllLevels(); InitializeLevelStates(); } private static void InitializeLevelStates() { levelStates.Clear(); foreach (KeyValuePair allLevel in AllLevels) { LevelKey key = allLevel.Key; LevelData value = allLevel.Value; LevelState orCreateState = GetOrCreateState(key); orCreateState.sentLevelCheck = value.GetLevelCompleted(); orCreateState.sentMaxGradeCheck = HasSRank(value); orCreateState.sentSnowmanCheck = value.GetSnowmanDestroyed(); orCreateState.sentBonusObjectivesUpTo = value.GetCurrentBonusObjectiveIndex(); CollectedPickupsForState(orCreateState, key); } } public static void FillAllLevels() { ProgressManager val = GameManager.instance?.progressManager; if ((Object)(object)val == (Object)null) { return; } AllLevels.Clear(); LevelCollection[] array = Resources.FindObjectsOfTypeAll(); LevelCollection[] array2 = array; foreach (LevelCollection val2 in array2) { LevelInformation[] allLevels = val2.GetAllLevels(); foreach (LevelInformation val3 in allLevels) { LevelData levelData = val.GetLevelData(val3); if (levelData != null) { LevelKey key = new LevelKey(levelData.GetCategory(), levelData.GetID()); if (key.category == "Main" && key.id == 27) { Plugin.Log.LogInfo((object)("Found Main 27: " + $"Completed={levelData.GetLevelCompleted()}, " + $"Attempted={levelData.GetLevelAttempted()}, " + $"Grade={levelData.GetCurrentGrade()}, " + $"Bonus={levelData.GetCurrentBonusObjectiveIndex()}, " + $"BestTime={levelData.GetBestTime()}, " + $"Snowman={levelData.GetSnowmanDestroyed()}")); } AllLevels[key] = levelData; } } } } public static void SendIndividualPickupCheck(int index, LevelKey key) { Plugin.Log.LogInfo((object)$"SendPickupCheck: [{key.category}] {key.id}, Pickup {index}"); LevelState orCreateState = GetOrCreateState(key); if (orCreateState.sentPickups.Add(index)) { Plugin.Log.LogInfo((object)"Pickup not previously sent. Sending check."); ArchipelagoManager.SendCheck(ItemTranslator.ParseLevelKeyToIndividualPickup(key, index)); } else { Plugin.Log.LogInfo((object)"Pickup already sent."); } } public static void SendGroupedPickupCheck(LevelKey key) { LevelState orCreateState = GetOrCreateState(key); if (orCreateState.completedAllPickups) { Plugin.Log.LogInfo((object)"Pickup already sent."); return; } Plugin.Log.LogInfo((object)"Pickup not previously sent. Sending check."); orCreateState.completedAllPickups = true; ArchipelagoManager.SendCheck(ItemTranslator.ParseLevelKeyToGroupedPickup(key)); } public static bool IsPickupComplete(int index, LevelKey key) { LevelState orCreateState = GetOrCreateState(key); if (SlotData.PickupLocations == "individual") { bool flag = orCreateState.sentPickups.Contains(index); Plugin.Log.LogInfo((object)$"IsPickupComplete: [{key.category}] {key.id}, Pickup {index} = {flag}"); return flag; } if (SlotData.PickupLocations == "grouped") { return orCreateState.completedAllPickups; } return true; } public static void SetAllLocationsChecked(ReadOnlyCollection allLocations) { AllCheckedLocations = allLocations; } public static void CollectedPickupsForState(LevelState state, LevelKey key) { if (SlotData.PickupLocations == "individual") { HashSet hashSet = new HashSet(); foreach (long allCheckedLocation in AllCheckedLocations) { string text = ArchipelagoManager.ArchipelagoIdToName(allCheckedLocation); LevelKey levelKey = ItemTranslator.ParseApIdToLevelKey(allCheckedLocation); Plugin.Log.LogInfo((object)$"Checking AP location {allCheckedLocation}: '{text}' -> [{levelKey.category}] {levelKey.id}"); if (key == levelKey) { int num = ItemTranslator.ParseApToPickupIndex(allCheckedLocation); if (num != -1) { hashSet.Add(num); Plugin.Log.LogInfo((object)$"Matched! Adding Pickup {num}"); } } } Plugin.Log.LogInfo((object)$"Collected {hashSet.Count} pickups for [{key.category}] {key.id}"); state.sentPickups = hashSet; } else { if (!(SlotData.PickupLocations == "grouped")) { return; } foreach (long allCheckedLocation2 in AllCheckedLocations) { string text2 = ArchipelagoManager.ArchipelagoIdToName(allCheckedLocation2); LevelKey levelKey2 = ItemTranslator.ParseApIdToLevelKey(allCheckedLocation2); if (key == levelKey2 && ItemTranslator.ParseApToPickupComplete(allCheckedLocation2)) { state.completedAllPickups = true; } } } } } public static class WeaponTracker { public static Dictionary isWeaponUnlocked = new Dictionary { { "Tree Bark", true }, { "Kick", false }, { "Combat Knife", false }, { "Pistol", false }, { "Shotgun", false }, { "Assault Rifle", false }, { "Sniper Rifle", false }, { "Bear Trap", false }, { "RPG", false }, { "Claymore Mine", false } }; public static void UnlockWeapon(string weaponName) { if (isWeaponUnlocked.ContainsKey(weaponName)) { isWeaponUnlocked[weaponName] = true; } } public static bool IsWeaponUnlocked(string name) { if (name == "Kick" && !SlotData.IsKickUnlock) { return true; } if (!SlotData.AreWeaponsUnlockable) { return true; } if (!isWeaponUnlocked.TryGetValue(name, out var value)) { return true; } return value; } } public enum TrapType { BleedTrap, SuperStrength, DisarmTrap, ImmobilizerTrap, AirStrikeTrap } public static class ArchipelagoTrapManager { private static int pendingBleedTraps; private static bool pendingSuperStrength; private static int pendingDisarmTraps; private const float ImmobilizeDamage = 0.25f; private const float ImmobilizeDuration = 3f; private static bool bleedCoroutineRunning; private static ManualLogSource Log => Plugin.Log; public static void QueueTrap(TrapType trap) { if (PlayerHelper.IsPlayerActivelyInLevel()) { ApplyTrapNow(trap, GameManager.instance.player); return; } switch (trap) { case TrapType.BleedTrap: pendingBleedTraps++; break; case TrapType.SuperStrength: pendingSuperStrength = true; break; case TrapType.DisarmTrap: pendingDisarmTraps++; break; } } private static void ApplyTrapNow(TrapType trap, Player player) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) switch (trap) { case TrapType.SuperStrength: player.SetSuperStrength(true); break; case TrapType.BleedTrap: pendingBleedTraps++; EnsureBleedCoroutineRunning(); break; case TrapType.DisarmTrap: ((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(ApplyDisarmNextFrame(player)); break; case TrapType.ImmobilizerTrap: { PlayerMovement movementScript = player.GetMovementScript(); movementScript.TriggerTimedLockOn(player.GetPosition(), 0.25f, false); player.GetHealthManager().Damage(0.25f, true); movementScript.EndSprint(); PlayerImmobilizerSource source = player.GetImmobilizer().AddImmobilizer(((Component)CoroutineRunner.Instance).gameObject, true, false, false, false); movementScript.ResetUprightMovement(); ((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(ReleaseImmobilizerAfterDelay(player, source, 3f)); break; } case TrapType.AirStrikeTrap: StartAirStrike(); break; } } public static void ApplyPendingTraps(Player player) { if (!((Object)(object)player == (Object)null)) { if (pendingSuperStrength) { player.SetSuperStrength(true); pendingSuperStrength = false; } if (pendingBleedTraps > 0) { EnsureBleedCoroutineRunning(); } } } public static void NotifyWeaponEquipped(WeaponPickup pickup) { if (!((Object)(object)pickup == (Object)null) && pendingDisarmTraps > 0) { pickup.SetLimitedUse(); pendingDisarmTraps--; } } private static void EnsureBleedCoroutineRunning() { if (!bleedCoroutineRunning) { bleedCoroutineRunning = true; ((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(ApplyStackedBleed()); } } private static IEnumerator ApplyStackedBleed() { while (pendingBleedTraps > 0) { Player player = GameManager.instance?.player; if ((Object)(object)player == (Object)null || (Object)(object)player.GetHealthManager() == (Object)null || player.GetHealthManager().IsDead()) { pendingBleedTraps = 0; bleedCoroutineRunning = false; yield break; } pendingBleedTraps--; player.GetHealthManager().StartBleeding(false); yield return (object)new WaitForSeconds(10f); } bleedCoroutineRunning = false; } private static IEnumerator ReleaseImmobilizerAfterDelay(Player player, PlayerImmobilizerSource source, float delay) { yield return (object)new WaitForSeconds(delay); Player currentPlayer = GameManager.instance?.player; if ((Object)(object)currentPlayer == (Object)(object)player && (Object)(object)player.GetImmobilizer() != (Object)null) { player.GetImmobilizer().ReduceImmobilizer(source); } } private static IEnumerator ApplyDisarmNextFrame(Player player) { yield return null; if (!player.GetArmScript().IsWeaponEquipped()) { pendingDisarmTraps++; yield break; } WeaponPickup currentWeapon = player.GetArmScript().GetEquippedWeapon(); player.GetArmScript().TossWeapon(currentWeapon); } public static void ResetTraps() { pendingBleedTraps = 0; pendingSuperStrength = false; pendingDisarmTraps = 0; } public static void StartAirStrike() { LevelController val = GameManager.instance?.levelController; if (!((Object)(object)val == (Object)null)) { AirStrikeController airStrikeController = val.GetAirStrikeController(); if (!((Object)(object)airStrikeController == (Object)null) && !((LevelThreatController)airStrikeController).IsEnabled() && !AirStrikePatches.IsAirStrikeEnabled) { AirStrikePatches.SetAirStrikeEnabled(enabled: true); ((LevelThreatController)airStrikeController).Start(); ((LevelThreatController)airStrikeController).StartSpawnTimer(); } } } } public class HealItem { public string APName; public float baseAmount; public float slowAmount; public HealthType healthType; } public static class HealthManager { public static List healItems = new List { new HealItem { APName = "Poultice Bush", baseAmount = 0.3f, slowAmount = 1.2f, healthType = (HealthType)0 }, new HealItem { APName = "Health Pack", baseAmount = 1.5f, slowAmount = 0f, healthType = (HealthType)0 }, new HealItem { APName = "Helmet", baseAmount = 1f, slowAmount = 0f, healthType = (HealthType)1 }, new HealItem { APName = "Bulletproof Vest", baseAmount = 2f, slowAmount = 0f, healthType = (HealthType)1 } }; public static bool isDeathLinkDeath = false; public static bool pendingDeathLinkKill = false; public static int deathCount = 0; public static void ApplyHeal(string name) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!PlayerHelper.IsPlayerActivelyInLevel()) { Plugin.Log.LogInfo((object)("Player is not currently in a level. Skipping " + name + " heal.")); return; } foreach (HealItem healItem in healItems) { if (healItem.APName == name) { Player val = GameManager.instance?.player; val.GetHealthManager().IncreaseHealth(healItem.healthType, healItem.baseAmount, true); if (healItem.slowAmount > 0f) { val.GetHealthManager().AddToSlowHealthRegen(healItem.slowAmount); } break; } } } public static void KillPlayer() { isDeathLinkDeath = true; if (!PlayerHelper.IsPlayerActivelyInLevel()) { isDeathLinkDeath = false; return; } Player val = GameManager.instance?.player; val.GetHealthManager().Damage(999f, true); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }