Decompiled source of Pantheon Of Pharloom v1.2.0
PantheonOfPharloom.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; 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 BepInEx; using GlobalEnums; using HarmonyLib; using HutongGames.PlayMaker; using HutongGames.PlayMaker.Actions; using InControl; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using PantheonOfPharloom.Actions; using TMProOld; using TeamCherry.Localization; using TeamCherry.NestedFadeGroup; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PantheonOfPharloom")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+f23fd608e16d580bb6b558662db10d0111a44789")] [assembly: AssemblyProduct("PantheonOfPharloom")] [assembly: AssemblyTitle("PantheonOfPharloom")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } internal static class IsExternalInit { } } namespace PantheonOfPharloom { internal class UserState { public string Scene { get; init; } public string Marker { get; init; } public HeroItemsState Items { get; init; } } public static class FadeSceneInHook { private static Hook _hook; private static bool _enabled = true; public static void Init() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown _hook = new Hook((MethodBase)typeof(GameManager).GetMethod("FadeSceneIn", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), (Delegate)new Action<Action<GameManager>, GameManager>(FadeSceneInDetour)); } public static void SetEnabled(bool enabled) { _enabled = enabled; } private static void FadeSceneInDetour(Action<GameManager> orig, GameManager self) { if (!_enabled) { orig(self); PopLogger.Log("[FadeSceneInHook] Forcing fade-in."); } else { PopLogger.Log("[FadeSceneInHook] Skipping fade-in."); } } public static void ForceCall() { SetEnabled(enabled: false); GameManager.instance.FadeSceneIn(); SetEnabled(enabled: true); } public static void Unload() { Hook hook = _hook; if (hook != null) { hook.Dispose(); } _hook = null; } } public class BossRushController : MonoBehaviour { private static readonly bool DO_TELEPORT = true; private List<Encounter> _encounters; private int _encounterIndex = -1; private bool _isActive; public static BossRushController Instance; private readonly bool _debug; private UserState _userState; public static Dictionary<string, bool> _playerDataBools = new Dictionary<string, bool>(); private static HashSet<string> _excludeList = new HashSet<string> { "hasDash", "hasBrolly", "hasSuperJump", "HasSeenEvaHeal", "hasHarpoonDash", "hasChargeSlash", "hasNeedolin", "hasWalljump", "hasDoubleJump", "hasNeedolinMemoryPowerup", "HasBoundCrestUpgrader", "UnlockedExtraBlueSlot", "UnlockedExtraYellowSlot", "UnlockedFastTravel", "UnlockedFastTravelTeleport", "hasQuill", "mapAllRooms", "HasAllMaps", "HasWhiteFlower", "completedTutorial", "SeenBindPrompt", "seenDreamNailPrompt", "SeenToolGetPrompt", "SeenToolWeaponGetPrompt", "SeenToolEquipPrompt", "SeenToolUsePrompt", "LightningToolToggle" }; public bool AllowUI { get { if (_isActive) { return _debug; } return true; } } public bool IsActive => _isActive; public Encounter CurrentEncounter => _encounters[_encounterIndex]; public Encounter NextEncounter => _encounters[_encounterIndex + 1]; private void Awake() { Instance = this; } private static void PatchPlayerData() { _playerDataBools = new Dictionary<string, bool>(); string[] array = (from x in typeof(PlayerData).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) select x.Name into x where !_excludeList.Contains(x) select x).ToArray(); CacheUtils.CachePlayerDataBools(array); string[] array2 = array; foreach (string text in array2) { _playerDataBools[text] = PlayerData.instance.GetBool(text); PlayerData.instance.SetBool(text, text.StartsWith("encountered", StringComparison.InvariantCulture)); } } private static void RestorePlayerData() { if (PlayerData.instance != null) { CacheUtils.Restore(); } } private void RestoreSpawnScene() { PlayerData.instance.respawnScene = _userState.Scene; PlayerData.instance.respawnMarkerName = _userState.Marker; PlayerData.instance.tempRespawnScene = ""; PlayerData.instance.tempRespawnMarker = ""; PopLogger.Log("restoring scene and stuff: " + PlayerData.instance.tempRespawnScene + ", " + PlayerData.instance.tempRespawnMarker); } private void AfterDeathOrCompletion() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) Reset(); HeroItemsState items = _userState.Items; ((HeroItemsState)(ref items)).Apply(HeroController.instance); } private void OnHornetDeath() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown if (_userState != null) { RestoreSpawnScene(); } _encounters[_encounterIndex].OnExit?.Invoke(); GameManager.instance.OnFinishedEnteringScene -= new EnterSceneEvent(OnNewEncounterLoad); GameManager.instance.OnFinishedEnteringScene += new EnterSceneEvent(Once); void Once() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown PopLogger.Log("called once..."); AfterDeathOrCompletion(); if (!string.IsNullOrEmpty(PlayerData.instance.HeroCorpseScene)) { HeroController.instance.CocoonBroken(); EventRegister.SendEvent(EventRegisterEvents.BreakHeroCorpse, (GameObject)null); } GameManager.instance.OnFinishedEnteringScene -= new EnterSceneEvent(Once); } } public static void SetupNewSequence(List<Encounter> encounters, bool transition, bool recordState = true) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) if (encounters.Count == 0) { PopLogger.LogError("Cannot start boss rush with 0 encounters."); return; } if (Instance._isActive) { Instance.Reset(); PopLogger.LogError("Active sequence already exists, thsi should not happen..."); } if (recordState) { PopLogger.Log("recording: " + PlayerData.instance.respawnScene + ", " + PlayerData.instance.respawnMarkerName); Instance._userState = new UserState { Scene = PlayerData.instance.respawnScene, Marker = PlayerData.instance.respawnMarkerName, Items = HeroItemsState.Record(HeroController.instance) }; } PopLogger.Log($"Starting new boss sequence of length {encounters.Count}"); HeroController.instance.OnDeath += Instance.OnHornetDeath; Instance._encounters = encounters; Instance._isActive = true; PatchPlayerData(); FadeSceneInHook.Init(); FadeSceneInHook.SetEnabled(enabled: true); if (transition) { Instance.NextBoss(); } } private void BeginBossRushCompletion(float delay, IEnumerator finishCallback) { //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) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown PopLogger.Log("Completed boss rush!"); FadeSceneInHook.SetEnabled(enabled: false); if (_userState != null) { RestoreSpawnScene(); } string sceneName = default(string); string entryGateName = default(string); GameManager.instance.GetRespawnInfo(ref sceneName, ref entryGateName); StartTransitionWithCoroutine(new SceneLoadInfo { SceneName = sceneName, EntryGateName = entryGateName, PreventCameraFadeOut = true, AlwaysUnloadUnusedAssets = true }, delay, finishCallback, delegate { GameManager.instance.RespawningHero = true; }); } private void NextBoss() { if (_encounterIndex >= 0) { CurrentEncounter.OnExit?.Invoke(); } _encounterIndex++; PopLogger.Log("calling NextBoss."); if (_encounterIndex == _encounters.Count) { PopLogger.Log("end reached"); BeginBossRushCompletion(_encounters[_encounterIndex - 1].TransitionDelay, SceneAfterFinish()); return; } Encounter encounter = _encounters[_encounterIndex]; encounter.BeforeEnter?.Invoke(); PopLogger.Log($"Starting next boss scene: {encounter.SceneInfo}"); StartTransitionWithCallback(encounter.SceneInfo, (_encounterIndex == 0) ? 0f : _encounters[_encounterIndex - 1].TransitionDelay, OnNewEncounterLoad); IEnumerator SceneAfterFinish() { _encounters[_encounterIndex - 1].AfterExit?.Invoke(); AfterDeathOrCompletion(); yield return null; PopLogger.Log("created fireworks"); } } private void TransitionFromBench() { CurrentEncounter.OnExit?.Invoke(); _encounterIndex++; Encounter encounter = _encounters[_encounterIndex]; encounter.BeforeEnter?.Invoke(); StartTransitionWithCallback(encounter.SceneInfo, 0f, OnNewEncounterLoad, doTransition: false); } private void PatchBadStates() { GameManager.instance.SetTimeScale(1f); FSMUtility.LocateMyFSM(((Component)((Component)GameCameras.instance.hudCamera).transform.Find("In-game/Anchor TL/Hud Canvas Offset/Hud Canvas")).gameObject, "Slide Out").SendEvent("IN"); EventRegister.SendEvent("SHOW HP", (GameObject)null); } private void TeleportPlayerToCustomSpawn(Vector3 position) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Extensions.SetPosition2D(HeroController.instance.transform, Vector2.op_Implicit(position)); Vector3 position2 = HeroController.instance.transform.position; GameManager.instance.cameraCtrl.SnapTo(position2.x, position2.y); } private void OnNewEncounterLoad() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) PopLogger.Log("Encounter loaded..."); if (_encounterIndex > 0) { _encounters[_encounterIndex - 1].AfterExit?.Invoke(); } CurrentEncounter.AfterEnter?.Invoke(); PatchBadStates(); IEncounterCompletedNotification encounterCompletedNotification = EncounterCompletionRegistry.AddEncounterCompletion(Object.Instantiate<GameObject>(new GameObject("BossRushController")), CurrentEncounter); if (encounterCompletedNotification is BenchTransitionNotification benchTransitionNotification) { benchTransitionNotification.nextScene = NextEncounter.SceneInfo.SceneName; benchTransitionNotification.nextGate = NextEncounter.SceneInfo.EntryGateName; encounterCompletedNotification.OnEncounterCompleted += delegate { PopLogger.Log("Transitioning from bench...."); TransitionFromBench(); }; ((MonoBehaviour)GameManager.instance).StartCoroutine(WaitThenFade(0.1f)); return; } HealthManager[] array = BossEncounterCompleteNotification.GetHealthManagers(CurrentEncounter.BossPathFromRoot).ToArray(); if (DO_TELEPORT && !CurrentEncounter.SkipTeleport) { if (CurrentEncounter.CustomSpawnPoint.HasValue) { TeleportPlayerToCustomSpawn(Vector2.op_Implicit(CurrentEncounter.CustomSpawnPoint.Value)); } else if (array.Length != 0) { Vector3 position = HeroController.instance.FindGroundPoint(Vector2.op_Implicit(((Component)array[0]).transform.position), true); TeleportPlayerToCustomSpawn(position); } else { PopLogger.LogError("Could not find boss to teleport to, set custom spawn point"); } } else { PopLogger.Log("skipping teleport"); } HealthManager[] array2 = array; foreach (HealthManager val in array2) { CurrentEncounter.ScaleHealth?.Invoke(val); PopLogger.LogWarning($"Scaled HP for {val}"); } if (TransitionPoint.TransitionPoints != null) { foreach (TransitionPoint transitionPoint in TransitionPoint.TransitionPoints) { if (transitionPoint != null && !((Object)transitionPoint).name.Contains("door")) { transitionPoint.activated = false; if (transitionPoint.collider != null) { transitionPoint.collider.isTrigger = false; } PopLogger.Log($"patched transition: {transitionPoint}"); } } } if (TransitionPoint.TransitionPoints == null) { new List<TransitionPoint>(); } encounterCompletedNotification.OnEncounterCompleted += delegate { PopLogger.Log("calling current encounte exit...."); NextBoss(); }; ((MonoBehaviour)GameManager.instance).StartCoroutine(WaitThenFade(0.3f)); static IEnumerator WaitThenFade(float delay) { yield return (object)new WaitForSeconds(delay); FadeSceneInHook.ForceCall(); } } private void StartTransitionWithCallback(SceneLoadInfo info, float delay = 0f, Action callback = null, bool doTransition = true) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown if (doTransition) { ((MonoBehaviour)this).StartCoroutine(DoTransition(info, delay)); } GameManager.instance.OnFinishedEnteringScene += new EnterSceneEvent(Wrapper); void Wrapper() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown GameManager.instance.OnFinishedEnteringScene -= new EnterSceneEvent(Wrapper); callback?.Invoke(); HeroController.instance.acceptingInput = true; } } private void StartTransitionWithCoroutine(SceneLoadInfo info, float delay = 0f, IEnumerator callback = null, Action beforeTransition = null) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown ((MonoBehaviour)this).StartCoroutine(DoTransition(info, delay, beforeTransition)); GameManager.instance.OnFinishedEnteringScene += new EnterSceneEvent(Wrapper); void Wrapper() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown GameManager.instance.OnFinishedEnteringScene -= new EnterSceneEvent(Wrapper); if (callback != null) { ((MonoBehaviour)GameManager.instance).StartCoroutine(callback); } HeroController.instance.acceptingInput = true; } } private IEnumerator DoTransition(SceneLoadInfo info, float delay = 0f, Action beforeTransition = null) { yield return (object)new WaitForSeconds(delay); ScreenFaderUtils.Fade(ScreenFaderUtils.GetColour(), Color.black, 1.5f); yield return (object)new WaitForSeconds(1.5f); yield return (object)new WaitUntil((Func<bool>)(() => !GameManager.instance.IsInSceneTransition && !GameManager.instance.IsLoadingSceneTransition)); HeroController.instance.acceptingInput = false; beforeTransition?.Invoke(); GameManager.instance.BeginSceneTransition(info); } private void OnDestroy() { Instance = null; } public void Reset(bool patch = true) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown _encounterIndex = -1; _encounters = null; _isActive = false; FadeSceneInHook.Unload(); if (patch) { RestorePlayerData(); HeroController.instance.OnDeath -= OnHornetDeath; GameManager.instance.OnFinishedEnteringScene -= new EnterSceneEvent(OnNewEncounterLoad); } } } internal class BenchTransitionNotification : MonoBehaviour, IEncounterCompletedNotification { public string nextScene; public string nextGate; public event Action OnEncounterCompleted; private void Start() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown TransitionPoint component = GameObject.Find("left1").GetComponent<TransitionPoint>(); component.targetScene = nextScene; component.entryPoint = nextGate; component.OnBeforeTransition += (BeforeTransitionEvent)delegate { this.OnEncounterCompleted?.Invoke(); }; } } public class BossDeathNotification : BossEncounterCompleteNotification { private int _bossesLeft; private void Start() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown HealthManager[] array = BossEncounterCompleteNotification.GetHealthManagers(bossPaths).ToArray(); _bossesLeft = array.Length; HealthManager[] array2 = array; foreach (HealthManager val in array2) { val.OnDeath += (DeathEvent)delegate { _bossesLeft--; PopLogger.Log("Boss death event received...."); if (_bossesLeft == 0) { BossDead(); } }; PopLogger.Log($"Added received death hook for {val}"); } } } public class BossEncounterCompleteNotification : MonoBehaviour, IEncounterCompletedNotification { public string[] bossPaths; public event Action OnEncounterCompleted; private static IEnumerable<HealthManager> FindBossesAutomatic() { IGrouping<int, HealthManager> grouping = (from x in Object.FindObjectsByType<HealthManager>((FindObjectsSortMode)0) orderby x.hp descending group x by x.hp).FirstOrDefault(); if (grouping == null) { PopLogger.LogError("Could not automatically find boss, set the boss path."); return Array.Empty<HealthManager>(); } PopLogger.Log("Found boss automatically: " + string.Join(",", grouping.Select((HealthManager x) => ((Object)x).name))); return grouping; } public static IEnumerable<HealthManager> GetHealthManagers(string[] bossPaths) { if (bossPaths.Length == 0) { PopLogger.Log("Boss paths were empty, trying to find automatically..."); return FindBossesAutomatic(); } return bossPaths.GetComponenFromPaths<HealthManager>(); } protected void BossDead() { PopLogger.Log("called BossDead()"); this.OnEncounterCompleted?.Invoke(); } } public class BossZeroHPNotification : BossEncounterCompleteNotification { private HealthManager[] _bosses; private bool _triggerd; private void Start() { _bosses = BossEncounterCompleteNotification.GetHealthManagers(bossPaths).ToArray(); } private void Update() { if (_triggerd) { return; } bool flag = true; HealthManager[] bosses = _bosses; for (int i = 0; i < bosses.Length; i++) { if (bosses[i].hp > 0) { flag = false; break; } } if (flag) { _triggerd = true; PopLogger.Log("Bosses reached zero hp...."); BossDead(); } } } internal class BelleaterDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObjectUtil.FindGameObjectFromScene("Boss Scene/Centipede Control"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); if (val == null) { PopLogger.LogError("Could not find cetipede control"); return; } val.GetState("Bell Best Appear").InsertMethod(0, base.BossDead); PopLogger.Log("Patched bellwater"); } } internal class CloverDancersDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObjectUtil.FindGameObjectFromScene("Boss Scene/Dancer Control/Dancer A/Corpse Green Prince(Clone)"); PlayMakerFSM obj2 = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Death") : null); if (obj2 == null) { PopLogger.Log("could not find corpse control for clover dancers"); } FsmState state = ((RunFSMAction)obj2.GetState("Heart Death").GetAction<RunFSM>()).runFsm.GetState("Return"); state.RemoveAction<BeginSceneTransition>(); state.AddMethod(base.BossDead); } } internal class CogworkDancersDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObjectUtil.FindGameObjectFromScene("Dancer Control"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); if (val == null) { PopLogger.LogError("Could not find last judge corpse fsm"); return; } val.GetState("End").InsertMethod(0, base.BossDead); PopLogger.Log("patched cogwork dancers"); } } internal class ConchflyDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObject.Find("Boss Scene"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); if (val == null) { PopLogger.Log("Could not find control for conchfly boss scene"); return; } val.GetState("Battle End S").InsertMethod(0, base.BossDead); val.GetState("Battle End").InsertMethod(0, base.BossDead); PopLogger.Log("Patch conchflies"); } } internal class FatherDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObject.Find("Boss Scene/Wisp Pyre Effigy"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Summon Control") : null); if (val == null) { PopLogger.Log("could not find father"); return; } val.GetState("End").InsertMethod(0, base.BossDead); PopLogger.Log("patched father"); } } internal class FirstSinnerDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObjectUtil.FindGameObjectFromScene("Boss Scene/Shrine First Weaver NPC"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Inspection") : null); if (val == null) { PopLogger.LogError("could not finnd first sinner npc"); return; } FsmState state = val.GetState("To First Sinner Memory"); state.Actions = Array.Empty<FsmStateAction>(); state.InsertMethod(0, base.BossDead); PopLogger.Log("patched weaver fsm"); } } internal class GrandmotherDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObject.Find("Boss Scene/Death Sequence"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); GameObject obj2 = GameObject.Find("Boss Scene/Death Sequence Cursed"); PlayMakerFSM val2 = ((obj2 != null) ? FSMUtility.LocateMyFSM(obj2, "Contorl") : null); if (val == null || val2 == null) { PopLogger.LogError("could not find a eath sequence control"); return; } val.CreateState("Custom Boss Dead").InsertMethod(0, base.BossDead); FsmState state = val.GetState("Idle"); state.Transitions = Array.Empty<FsmTransition>(); state.AddTransition("DEATH START", "Custom Boss Dead"); PopLogger.Log("patched grandmother silk 3"); } } internal class LastJudgeDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObjectUtil.FindGameObjectFromScene("Boss Scene/Last Judge/Corpse Last Judge(Clone)"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); if (val == null) { PopLogger.LogError("Could not find last judge corpse fsm"); return; } val.GetState("Break 4").InsertMethod(0, base.BossDead); PopLogger.Log("patched last judge"); } } internal class LostLaceDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObject.Find("Boss Control/Superjump Sequence"); PlayMakerFSM fsm = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); fsm.CreateState("Custom Boss Dead").InsertMethod(0, base.BossDead); FsmState state = fsm.GetState("Crash"); state.Transitions = Array.Empty<FsmTransition>(); state.AddTransition("FINISHED", "Custom Boss Dead"); PopLogger.Log("patched lost lace"); } } internal class PhantomDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObject.Find("Boss Scene/Phantom"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); if (val == null) { PopLogger.LogError("could not finnd phantom"); return; } FsmState state = val.GetState("Fade To Black"); state.GetAction<Wait>().time = FsmFloat.op_Implicit(0f); val.CreateState("Custom Boss Dead").InsertMethod(0, base.BossDead); state.Transitions = Array.Empty<FsmTransition>(); state.AddTransition("FINISHED", "Custom Boss Dead"); PopLogger.Log("patched fsm"); } } internal class ShakraDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObjectUtil.FindGameObjectFromScene("Mapper Spar NPC"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Dialogue") : null); if (val == null) { PopLogger.LogError("couldnt find dialouge fsm for shakra"); return; } FsmState state = val.GetState("Away"); state.InsertMethod(state.Actions.Length - 1, base.BossDead); PopLogger.Log("Patched Unravelled"); } } internal class UnravelledDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObject.Find("Boss Scene/Conductor Boss"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); if (val == null) { PopLogger.LogError("Could not find control for Unravelled"); return; } FsmState state = val.GetState("Death Blow"); state.InsertMethod(state.Actions.Length - 1, base.BossDead); PopLogger.Log("Patched Unravelled"); } } internal class WidowDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObject.Find("Boss Scene/Spinner Boss"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Control") : null); if (val == null) { PopLogger.LogError("could not finnd window"); return; } FsmState state = val.GetState("Fade To Black"); state.GetAction<Wait>(6).time = FsmFloat.op_Implicit(0f); val.GetState("Fade").GetAction<Wait>().time = FsmFloat.op_Implicit(0f); val.CreateState("Custom Boss Dead").InsertMethod(0, base.BossDead); state.Transitions = Array.Empty<FsmTransition>(); state.AddTransition("FINISHED", "Custom Boss Dead"); PopLogger.Log("patched fssm"); } } public static class EncounterCompletionRegistry { private static readonly Dictionary<string, Type> _customNotifications = new Dictionary<string, Type> { { "Widow", typeof(WidowDeadNotification) }, { "Phantom", typeof(PhantomDeadNotification) }, { "Last Judge", typeof(LastJudgeDeadNotification) }, { "Cogwork Dancers", typeof(CogworkDancersDeadNotification) }, { "Double Conchfly", typeof(ConchflyDeadNotification) }, { "Unravelled", typeof(UnravelledDeadNotification) }, { "First Sinner", typeof(FirstSinnerDeadNotification) }, { "Grandmother", typeof(GrandmotherDeadNotification) }, { "Father of Flame", typeof(FatherDeadNotification) }, { "Bell Eater", typeof(BelleaterDeadNotification) }, { "Clover Dancer", typeof(CloverDancersDeadNotification) }, { "Lost Lace", typeof(LostLaceDeadNotification) }, { "Bench", typeof(BenchTransitionNotification) }, { "Shakra", typeof(ShakraDeadNotification) } }; public static IEncounterCompletedNotification AddEncounterCompletion(GameObject root, Encounter encounter) { IEncounterCompletedNotification encounterCompletedNotification = null; if (_customNotifications.TryGetValue(encounter.Name, out var value)) { return root.AddComponent(value) as IEncounterCompletedNotification; } if (encounter.SpecialDeath) { BossZeroHPNotification bossZeroHPNotification = root.AddComponent<BossZeroHPNotification>(); bossZeroHPNotification.bossPaths = encounter.BossPathFromRoot; return bossZeroHPNotification; } BossDeathNotification bossDeathNotification = root.AddComponent<BossDeathNotification>(); bossDeathNotification.bossPaths = encounter.BossPathFromRoot; return bossDeathNotification; } } public interface IEncounterCompletedNotification { event Action OnEncounterCompleted; } public static class BossLists { private static readonly string BossListsDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "boss_list"); private static readonly string[] _defaultPharloomBosses = new string[13] { "Moss Mother", "Skull Tyrant", "Bell Beast", "Savage Beastfly", "Fourth Chorus", "Fire Lace", "Bench", "Double Conchfly", "Moorwing", "Sister Splinter", "Widow", "Phantom", "Last Judge" }; private static readonly string[] _defaultCitadelBosses = new string[20] { "Garmond and Zaza", "Cogwork Dancers", "Trobbio", "Chef Lugoli", "Broodmother", "Groal", "Bench", "Moss Mother 2", "Single Conchfly", "Zango", "Voltvyrm", "Savage Beastfly 2", "Shakra", "Bench", "Father of Flame", "Signis & Gron", "Second Sentinel", "Unravelled", "Flower Lace", "First Sinner" }; private static readonly string[] _defaultAbyssBosses = new string[17] { "Bell Eater", "Crawfather", "Gurr", "Lost Garmond", "Pinstress", "Watcher", "Tormented Trobbio", "Bench", "Palestag", "Clover Dancer", "Seth", "Nyleth", "Khann", "Kramelita", "Bench", "Grandmother", "Lost Lace" }; private static string[] PharloomBosses; private static string[] CitadelBosses; private static string[] AbyssBosses; private static string[] SilksongBosses; public static Encounter[] PharloomEncounters => PharloomBosses.Select((string x) => BossRegistry.EncounterByName[x]).ToArray(); public static Encounter[] CitadelEncounters => CitadelBosses.Select((string x) => BossRegistry.EncounterByName[x]).ToArray(); public static Encounter[] AbyssEncounters => AbyssBosses.Select((string x) => BossRegistry.EncounterByName[x]).ToArray(); public static Encounter[] SilksongEncounters => SilksongBosses.Select((string x) => BossRegistry.EncounterByName[x]).ToArray(); public static void Initialize() { PharloomBosses = LoadBossList("act1.txt", _defaultPharloomBosses); CitadelBosses = LoadBossList("act2.txt", _defaultCitadelBosses); AbyssBosses = LoadBossList("act3.txt", _defaultAbyssBosses); SilksongBosses = PharloomBosses.Concat(new string[1] { "Bench" }).Concat(CitadelBosses).Concat(new string[1] { "Bench" }) .Concat(AbyssBosses) .ToArray(); } private static string[] LoadBossList(string fileName, string[] fallback) { string text = Path.Combine(BossListsDir, fileName); PopLogger.Log("trying to find file path: " + text); if (!File.Exists(text)) { return fallback; } try { string[] array = (from l in File.ReadAllLines(text) select l.Trim() into l where !string.IsNullOrEmpty(l) && !l.StartsWith("#") select l).ToArray(); return (array.Length != 0) ? array : fallback; } catch { return fallback; } } } public struct Encounter { public string Name { get; init; } public SceneLoadInfo SceneInfo { get; init; } public Action BeforeEnter { get; init; } public Action AfterEnter { get; init; } public Action OnExit { get; init; } public Action AfterExit { get; init; } public bool IsSafe { get; init; } public string[] BossPathFromRoot { get; init; } public bool SpecialDeath { get; init; } public float TransitionDelay { get; init; } public Vector2? CustomSpawnPoint { get; init; } public bool SkipTeleport { get; init; } public Action<HealthManager> ScaleHealth { get; init; } public Encounter() { Name = null; SceneInfo = null; BeforeEnter = null; AfterEnter = null; OnExit = null; AfterExit = null; IsSafe = false; CustomSpawnPoint = null; ScaleHealth = null; BossPathFromRoot = new string[0]; SpecialDeath = false; TransitionDelay = 5f; SkipTeleport = false; } } public struct BossInfo { public string Name { get; init; } public string JournalRecordName { get; init; } public List<Encounter> Encounters { get; init; } } public static class BossRegistry { private enum NailType { Old, Sharpened, Shining, Hivesteel, Palesteel } private static Action<HealthManager> ScaleToOldNail = delegate(HealthManager hm) { ScaleToNail(hm, NailType.Old); }; private static Action<HealthManager> ScaleToSharpenedNail = delegate(HealthManager hm) { ScaleToNail(hm, NailType.Sharpened); }; private static Action<HealthManager> ScaleToShiningNail = delegate(HealthManager hm) { ScaleToNail(hm, NailType.Shining); }; private static Action<HealthManager> ScaleToHivesteelNail = delegate(HealthManager hm) { ScaleToNail(hm, NailType.Hivesteel); }; public static List<BossInfo> BossInfos = new List<BossInfo> { new BossInfo { Name = "Mossbone Mother", JournalRecordName = "Mossbone Mother", Encounters = new List<Encounter> { new Encounter { Name = "Moss Mother", SceneInfo = new SceneLoadInfo { SceneName = "Tut_03", EntryGateName = "right1", Visualization = (SceneLoadVisualizations)2, PreventCameraFadeOut = false }, BeforeEnter = delegate { PlayerData.instance.defeatedMossMother = false; PlayerData.instance.encounteredMossMother = false; }, AfterEnter = delegate { GameObject obj5 = GameObjectUtil.FindGameObjectFromScene("Black Thread States/Normal World/Battle Scene/Wave 1"); if (obj5 != null) { GameObject gameObject2 = obj5.gameObject; if (gameObject2 != null) { gameObject2.SetActive(true); } } }, OnExit = delegate { PlayerData.instance.encounteredMossMother = true; PlayerData.instance.defeatedMossMother = true; }, BossPathFromRoot = new string[1] { "Black Thread States/Normal World/Battle Scene/Wave 1/Mossbone Mother" }, ScaleHealth = ScaleToOldNail }, new Encounter { Name = "Moss Mother 2", SceneInfo = new SceneLoadInfo { SceneName = "Weave_03", EntryGateName = "right1" }, BeforeEnter = delegate { if (((PersistentItemDataCollection<bool, SerializableBoolData>)(object)SceneData.instance.persistentBools).scenes["Weave_03"].TryGetValue("Boss Scene", out var value5)) { value5.Value = false; } }, CustomSpawnPoint = new Vector2(15f, 21f), ScaleHealth = ScaleToSharpenedNail } } }, new BossInfo { Name = "Skull King", JournalRecordName = "Skull King", Encounters = new List<Encounter> { new Encounter { Name = "Skull Tyrant", SceneInfo = new SceneLoadInfo { SceneName = "Bone_15", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Boss Scene/Skull King" }, ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Bone Flyer Giant", JournalRecordName = "Bone Flyer Giant", Encounters = new List<Encounter> { new Encounter { Name = "Savage Beastfly", SceneInfo = new SceneLoadInfo { SceneName = "Ant_19", EntryGateName = "left1", Visualization = (SceneLoadVisualizations)0, PreventCameraFadeOut = false }, BeforeEnter = delegate { PlayerData.instance.defeatedBoneFlyerGiant = false; }, OnExit = delegate { PlayerData.instance.defeatedBoneFlyerGiant = true; }, BossPathFromRoot = new string[1] { "Boss Control/Boss Scene/Bone Flyer Giant" }, CustomSpawnPoint = new Vector2(63f, 34.6f), ScaleHealth = ScaleToSharpenedNail }, new Encounter { Name = "Savage Beastfly 2", SceneInfo = new SceneLoadInfo { SceneName = "Bone_East_08", EntryGateName = "right1" }, BeforeEnter = delegate { //IL_000f: Unknown result type (might be due to invalid IL or missing references) ((SerializableNamedList<Completion, NamedCompletion>)(object)PlayerData.instance.QuestCompletionData).SetData("Beastfly Hunt", QuestCompletionData.Accepted); CacheUtils.CachePlayerDataBools("defeatedBoneFlyerGiantGolemScene", "defeatedSongGolem"); PlayerData.instance.defeatedBoneFlyerGiantGolemScene = false; PlayerData.instance.defeatedSongGolem = true; }, OnExit = delegate { CacheUtils.Restore(); }, BossPathFromRoot = new string[1] { "Boss Scene Beastfly/Beastfly States/Active/Bone Flyer Giant" }, CustomSpawnPoint = new Vector2(82f, 8f), ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Bone Beast", JournalRecordName = "Bone Beast", Encounters = new List<Encounter> { new Encounter { Name = "Bell Beast", SceneInfo = new SceneLoadInfo { SceneName = "Bone_05", EntryGateName = "left1", Visualization = (SceneLoadVisualizations)2, PreventCameraFadeOut = false }, BeforeEnter = delegate { PlayerData.instance.defeatedBellBeast = false; PlayerData.instance.encounteredBellBeast = true; }, OnExit = delegate { PlayerData.instance.defeatedBellBeast = true; }, BossPathFromRoot = new string[1] { "Boss Scene/Bone Beast" }, CustomSpawnPoint = new Vector2(83f, 4f), ScaleHealth = ScaleToOldNail } } }, new BossInfo { Name = "Dock Guard Thrower", JournalRecordName = "Dock Guard Thrower", Encounters = new List<Encounter> { new Encounter { Name = "Signis & Gron", SceneInfo = new SceneLoadInfo { SceneName = "Dock_09", EntryGateName = "right1" }, BeforeEnter = delegate { }, OnExit = delegate { }, BossPathFromRoot = new string[2] { "Boss Scene/Dock Guard Slasher", "Boss Scene/Dock Guard Thrower" }, SpecialDeath = true, CustomSpawnPoint = new Vector2(40f, 8f), ScaleHealth = ScaleToHivesteelNail } } }, new BossInfo { Name = "Song Golem", JournalRecordName = "Song Golem", Encounters = new List<Encounter> { new Encounter { Name = "Fourth Chorus", SceneInfo = new SceneLoadInfo { SceneName = "Bone_East_08", EntryGateName = "right1" }, BeforeEnter = delegate { }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Boss Scene/song_golem/Song_Butt/SG_waist/Torso/SG_head" }, SpecialDeath = true, ScaleHealth = ScaleToOldNail } } }, new BossInfo { Name = "Bone Hunter Trapper", JournalRecordName = "Bone Hunter Trapper", Encounters = new List<Encounter> { new Encounter { Name = "Gurr", SceneInfo = new SceneLoadInfo { SceneName = "Bone_East_18b", EntryGateName = "top1" }, BeforeEnter = delegate { PlayerData.instance.encounteredAntTrapper = true; }, OnExit = delegate { } } } }, new BossInfo { Name = "Hunter Queen", JournalRecordName = "Hunter Queen", Encounters = new List<Encounter> { new Encounter { Name = "Kramelita", SceneInfo = new SceneLoadInfo { SceneName = "Memory_Ant_Queen", EntryGateName = "door_wakeInMemory", Visualization = (SceneLoadVisualizations)2, PreventCameraFadeOut = false }, BeforeEnter = delegate { PlayerData.instance.defeatedAntQueen = false; }, OnExit = delegate { PlayerData.instance.defeatedAntQueen = true; } } } }, new BossInfo { Name = "Vampire Gnat", JournalRecordName = "Vampire Gnat", Encounters = new List<Encounter> { new Encounter { Name = "Moorwing", SceneInfo = new SceneLoadInfo { SceneName = "Greymoor_08", EntryGateName = "top1", Visualization = (SceneLoadVisualizations)0, PreventCameraFadeOut = true }, BeforeEnter = delegate { PlayerData.instance.defeatedVampireGnatBoss = false; }, OnExit = delegate { PlayerData.instance.defeatedVampireGnatBoss = true; }, BossPathFromRoot = new string[1] { "Vampire Gnat Scene/Vampire Gnat" }, ScaleHealth = ScaleToOldNail } } }, new BossInfo { Name = "Wisp Pyre Effigy", JournalRecordName = "Wisp Pyre Effigy", Encounters = new List<Encounter> { new Encounter { Name = "Father of Flame", SceneInfo = new SceneLoadInfo { SceneName = "Belltown_08", EntryGateName = "right1" }, BeforeEnter = delegate { }, OnExit = delegate { }, TransitionDelay = 0f, CustomSpawnPoint = new Vector2(67f, 12f) } } }, new BossInfo { Name = "Crawfather", JournalRecordName = "Crawfather", Encounters = new List<Encounter> { new Encounter { Name = "Crawfather", SceneInfo = new SceneLoadInfo { SceneName = "Room_CrowCourt_02", EntryGateName = "top1" }, BeforeEnter = delegate { PlayerData.instance.encounteredCrowCourt = true; }, OnExit = delegate { } } } }, new BossInfo { Name = "Roachkeeper Chef", JournalRecordName = "Roachkeeper Chef", Encounters = new List<Encounter> { new Encounter { Name = "Chef Lugoli", SceneInfo = new SceneLoadInfo { SceneName = "Dust_Chef", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Swamp Shaman", JournalRecordName = "Swamp Shaman", Encounters = new List<Encounter> { new Encounter { Name = "Groal", SceneInfo = new SceneLoadInfo { SceneName = "Shadow_18", EntryGateName = "right1" }, BeforeEnter = delegate { }, OnExit = delegate { }, SpecialDeath = true, CustomSpawnPoint = new Vector2(55f, 12f) } } }, new BossInfo { Name = "Splinter Queen", JournalRecordName = "Splinter Queen", Encounters = new List<Encounter> { new Encounter { Name = "Sister Splinter", SceneInfo = new SceneLoadInfo { SceneName = "Shellwood_18", EntryGateName = "right1" }, BeforeEnter = delegate { }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Boss Scene Parent/Boss Scene/Splinter Queen" }, ScaleHealth = ScaleToOldNail } } }, new BossInfo { Name = "Seth", JournalRecordName = "Seth", Encounters = new List<Encounter> { new Encounter { Name = "Seth", SceneInfo = new SceneLoadInfo { SceneName = "Shellwood_22", EntryGateName = "right1" }, BeforeEnter = delegate { }, OnExit = delegate { } } } }, new BossInfo { Name = "Flower Queen", JournalRecordName = "Flower Queen", Encounters = new List<Encounter> { new Encounter { Name = "Nyleth", SceneInfo = new SceneLoadInfo { SceneName = "Shellwood_11b_Memory", EntryGateName = "door_wakeInMemory" }, BeforeEnter = delegate { }, OnExit = delegate { }, CustomSpawnPoint = new Vector2(18f, 110f) } } }, new BossInfo { Name = "Last Judge", JournalRecordName = "Last Judge", Encounters = new List<Encounter> { new Encounter { Name = "Last Judge", SceneInfo = new SceneLoadInfo { SceneName = "Coral_Judge_Arena", EntryGateName = "left1" }, BeforeEnter = delegate { GameManager.instance.playerData.bellShrineBellhart = true; GameManager.instance.playerData.bellShrineEnclave = true; GameManager.instance.playerData.bellShrineGreymoor = true; GameManager.instance.playerData.bellShrineShellwood = true; GameManager.instance.playerData.bellShrineWilds = true; GameManager.instance.playerData.bellShrineBoneForest = true; GameManager.instance.playerData.encounteredLastJudge = true; GameManager.instance.playerData.defeatedLastJudge = false; if (((PersistentItemDataCollection<bool, SerializableBoolData>)(object)SceneData.instance.persistentBools).scenes["Coral_Judge_Arena"].TryGetValue("Last Judge", out var value4)) { value4.Value = false; } }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Boss Scene/Last Judge" }, TransitionDelay = 0f, CustomSpawnPoint = new Vector2(25f, 25f), ScaleHealth = ScaleToSharpenedNail } } }, new BossInfo { Name = "Coral Conch Driller Giant", JournalRecordName = "Coral Conch Driller Giant", Encounters = new List<Encounter> { new Encounter { Name = "Single Conchfly", SceneInfo = new SceneLoadInfo { SceneName = "Coral_27", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, CustomSpawnPoint = new Vector2(20f, 34f) }, new Encounter { Name = "Double Conchfly", SceneInfo = new SceneLoadInfo { SceneName = "Coral_11", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, TransitionDelay = 0f, CustomSpawnPoint = new Vector2(60f, 15f), ScaleHealth = ScaleToSharpenedNail } } }, new BossInfo { Name = "Coral Warrior Grey", JournalRecordName = "Coral Warrior Grey", Encounters = new List<Encounter> { new Encounter { Name = "Watcher", SceneInfo = new SceneLoadInfo { SceneName = "Coral_39", EntryGateName = "right1" }, BeforeEnter = delegate { }, OnExit = delegate { } } } }, new BossInfo { Name = "Coral King", JournalRecordName = "Coral King", Encounters = new List<Encounter> { new Encounter { Name = "Khann", SceneInfo = new SceneLoadInfo { SceneName = "Memory_Coral_Tower", EntryGateName = "door_wakeInMemory" }, BeforeEnter = delegate { }, OnExit = delegate { }, SpecialDeath = true } } }, new BossInfo { Name = "Song Knight", JournalRecordName = "Song Knight", Encounters = new List<Encounter> { new Encounter { Name = "Second Sentinel", SceneInfo = new SceneLoadInfo { SceneName = "Hang_17b", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, CustomSpawnPoint = new Vector2(32f, 5f), ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Conductor Boss", JournalRecordName = "Conductor Boss", Encounters = new List<Encounter> { new Encounter { Name = "Unravelled", SceneInfo = new SceneLoadInfo { SceneName = "Ward_02", EntryGateName = "right1" }, BeforeEnter = delegate { GameManager.instance.playerData.collectedWardBossKey = true; }, OnExit = delegate { }, TransitionDelay = 0f } } }, new BossInfo { Name = "Clockwork Dancer", JournalRecordName = "Clockwork Dancer", Encounters = new List<Encounter> { new Encounter { Name = "Cogwork Dancers", SceneInfo = new SceneLoadInfo { SceneName = "Cog_Dancers", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, TransitionDelay = 0f, ScaleHealth = ScaleToSharpenedNail } } }, new BossInfo { Name = "Trobbio", JournalRecordName = "Trobbio", Encounters = new List<Encounter> { new Encounter { Name = "Trobbio", SceneInfo = new SceneLoadInfo { SceneName = "Library_13", EntryGateName = "left1" }, BeforeEnter = delegate { PlayerData.instance.encounteredTrobbio = true; }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Grand Stage Scene/Boss Scene Trobbio/Trobbio" }, SpecialDeath = true, ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Tormented Trobbio", JournalRecordName = "Tormented Trobbio", Encounters = new List<Encounter> { new Encounter { Name = "Tormented Trobbio", SceneInfo = new SceneLoadInfo { SceneName = "Library_13", EntryGateName = "left1" }, BeforeEnter = delegate { PlayerData.instance.blackThreadWorld = true; PlayerData.instance.encounteredTormentedTrobbio = true; }, AfterEnter = delegate { GameObject obj4 = GameObjectUtil.FindGameObjectFromScene("Grand Stage Scene/Boss Scene TormentedTrobbio"); if (obj4 != null) { obj4.SetActive(true); } }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Grand Stage Scene/Boss Scene TormentedTrobbio/Tormented Trobbio" }, CustomSpawnPoint = new Vector2(64f, 15f) } } }, new BossInfo { Name = "Slab Fly Broodmother", JournalRecordName = "Slab Fly Broodmother", Encounters = new List<Encounter> { new Encounter { Name = "Broodmother", SceneInfo = new SceneLoadInfo { SceneName = "Slab_16b", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, CustomSpawnPoint = new Vector2(60f, 6f) } } }, new BossInfo { Name = "Cloverstag White", JournalRecordName = "Cloverstag White", Encounters = new List<Encounter> { new Encounter { Name = "Palestag", SceneInfo = new SceneLoadInfo { SceneName = "Clover_19", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { } } } }, new BossInfo { Name = "Clover Dancer", JournalRecordName = "Clover Dancer", Encounters = new List<Encounter> { new Encounter { Name = "Clover Dancer", SceneInfo = new SceneLoadInfo { SceneName = "Clover_10", EntryGateName = "left1" }, BeforeEnter = delegate { if (((PersistentItemDataCollection<bool, SerializableBoolData>)(object)SceneData.instance.persistentBools).scenes["Clover_10"].TryGetValue("Dancer A", out var value3)) { value3.Value = false; } }, OnExit = delegate { }, TransitionDelay = 0f, BossPathFromRoot = new string[1] { "Boss Scene/Dancer Control/Dancer A" }, CustomSpawnPoint = new Vector2(93f, 38f) } } }, new BossInfo { Name = "Giant Centipede", JournalRecordName = "Giant Centipede", Encounters = new List<Encounter> { new Encounter { Name = "Bell Eater", SceneInfo = new SceneLoadInfo { SceneName = "Bellway_Centipede_Arena", EntryGateName = "top1" }, BeforeEnter = delegate { }, OnExit = delegate { }, BossPathFromRoot = new string[2] { "Boss Scene/Giant Centipede Butt", "Boss Scene/Giant Centipede Head" }, TransitionDelay = 0f } } }, new BossInfo { Name = "Pinstress Boss", JournalRecordName = "Pinstress Boss", Encounters = new List<Encounter> { new Encounter { Name = "Pinstress", SceneInfo = new SceneLoadInfo { SceneName = "Peak_07", EntryGateName = "top2" }, BeforeEnter = delegate { //IL_000f: Unknown result type (might be due to invalid IL or missing references) ((SerializableNamedList<Completion, NamedCompletion>)(object)PlayerData.instance.QuestCompletionData).SetData("Pinstress Battle", QuestCompletionData.Accepted); CacheUtils.CachePlayerDataBools("blackThreadWorld"); PlayerData.instance.blackThreadWorld = true; }, AfterEnter = delegate { GameObject obj3 = GameObjectUtil.FindGameObjectFromScene("Pinstress Control/Pinstress Scene/Pinstress Boss/NPC"); FsmState state = ((obj3 != null) ? FSMUtility.LocateMyFSM(obj3, "NPC Control") : null).GetState("Wake 3"); state.Transitions = Array.Empty<FsmTransition>(); state.AddTransition("FINISHED", "Battle Start"); }, OnExit = delegate { CacheUtils.Restore(); }, SpecialDeath = true, TransitionDelay = 2f } } }, new BossInfo { Name = "Spinner Boss", JournalRecordName = "Spinner Boss", Encounters = new List<Encounter> { new Encounter { Name = "Widow", SceneInfo = new SceneLoadInfo { SceneName = "Belltown_Shrine", EntryGateName = "top1" }, BeforeEnter = delegate { PlayerData.instance.encounteredSpinner = true; PlayerData.instance.bellShrineBellhart = false; if (((PersistentItemDataCollection<int, SerializableIntData>)(object)SceneData.instance.persistentInts).scenes["Belltown_Shrine"].TryGetValue("Bellshrine Sequence Bellhart", out var value2)) { value2.Value = 0; } }, AfterEnter = delegate { }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Black Thread States Thread Only Variant/Normal World/Boss Scene/Spinner Boss" }, TransitionDelay = 0f, CustomSpawnPoint = new Vector2(49f, 28f), ScaleHealth = ScaleToOldNail } } }, new BossInfo { Name = "First Weaver", JournalRecordName = "First Weaver", Encounters = new List<Encounter> { new Encounter { Name = "First Sinner", SceneInfo = new SceneLoadInfo { SceneName = "Slab_10b", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, CustomSpawnPoint = new Vector2(38f, 10f), TransitionDelay = 0f, ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Phantom", JournalRecordName = "Phantom", Encounters = new List<Encounter> { new Encounter { Name = "Phantom", SceneInfo = new SceneLoadInfo { SceneName = "Organ_01", EntryGateName = "left1" }, BeforeEnter = delegate { PlayerData.instance.encounteredPhantom = true; }, OnExit = delegate { PopLogger.Log("repatched time scale"); }, BossPathFromRoot = new string[1] { "Boss Scene/Phantom" }, TransitionDelay = 0f, ScaleHealth = ScaleToSharpenedNail } } }, new BossInfo { Name = "Lace", JournalRecordName = "Lace", Encounters = new List<Encounter> { new Encounter { Name = "Fire Lace", SceneInfo = new SceneLoadInfo { SceneName = "Bone_East_12", EntryGateName = "bot1", Visualization = (SceneLoadVisualizations)2, PreventCameraFadeOut = false }, BeforeEnter = delegate { PlayerData.instance.defeatedLace1 = false; PlayerData.instance.encounteredLace1 = true; PlayerData.instance.encounteredLace1Grotto = false; PlayerData.instance.encounteredLaceBlastedBridge = false; }, OnExit = delegate { PlayerData.instance.defeatedLace1 = true; }, BossPathFromRoot = new string[1] { "Boss Scene/Lace Boss1" }, CustomSpawnPoint = new Vector2(86f, 8f), ScaleHealth = ScaleToOldNail }, new Encounter { Name = "Flower Lace", SceneInfo = new SceneLoadInfo { SceneName = "Song_Tower_01", EntryGateName = "door_cutsceneEndLaceTower" }, BeforeEnter = delegate { PlayerData.instance.encounteredLaceTower = true; }, OnExit = delegate { }, SkipTeleport = true, ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Silk Boss", JournalRecordName = "Silk Boss", Encounters = new List<Encounter> { new Encounter { Name = "Grandmother", SceneInfo = new SceneLoadInfo { SceneName = "Cradle_03", EntryGateName = "right2" }, BeforeEnter = delegate { }, OnExit = delegate { //IL_000a: Unknown result type (might be due to invalid IL or missing references) HeroController.instance.rb2d.linearVelocity = Vector2.zero; }, AfterExit = delegate { FSMUtility.LocateMyFSM(((Component)((Component)GameCameras.instance.hudCamera).transform.Find("In-game/Anchor TL/Hud Canvas Offset/Hud Canvas")).gameObject, "Slide Out").SendEvent("IN"); PlayerData.instance.isInvincible = false; PopLogger.Log("did grandmother changes"); }, TransitionDelay = 0f, CustomSpawnPoint = new Vector2(38f, 134f), ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Lost Lace", JournalRecordName = "Lost Lace", Encounters = new List<Encounter> { new Encounter { Name = "Lost Lace", SceneInfo = new SceneLoadInfo { SceneName = "Abyss_Cocoon", EntryGateName = "door_entry", Visualization = (SceneLoadVisualizations)0, PreventCameraFadeOut = true }, BeforeEnter = delegate { PlayerData.instance.EncounteredLostLace = true; }, OnExit = delegate { Transform obj2 = HeroController.instance.transform.Find("Hornet Dummy"); if (obj2 != null) { GameObject gameObject = ((Component)obj2).gameObject; if (gameObject != null) { gameObject.SetActive(false); } } }, TransitionDelay = 0f } } }, new BossInfo { Name = "Shakra", JournalRecordName = "Shakra", Encounters = new List<Encounter> { new Encounter { Name = "Shakra", SceneInfo = new SceneLoadInfo { SceneName = "Greymoor_08", EntryGateName = "left2" }, BeforeEnter = delegate { PlayerData.instance.mapperMentorConvo = true; PlayerData.instance.mapperSparIntro = true; }, AfterEnter = delegate { EventRegister.SendEvent("MAPPER CALL", (GameObject)null); GameObject obj = GameObjectUtil.FindGameObjectFromScene("Mapper Spar NPC"); PlayMakerFSM fsm = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Dialogue") : null); if (fsm == null) { PopLogger.Log("start was null"); } else { ((MonoBehaviour)GameManager.instance).StartCoroutine(WaitForState()); } IEnumerator WaitForState() { PopLogger.Log("waiting for state...."); yield return (object)new WaitUntil((Func<bool>)(() => fsm.ActiveStateName == "Idle")); yield return (object)new WaitForEndOfFrame(); fsm.SetState("Start Battle"); } }, SpecialDeath = true, TransitionDelay = 0f, ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Zap Core Enemy", JournalRecordName = "Zap Core Enemy", Encounters = new List<Encounter> { new Encounter { Name = "Voltvyrm", SceneInfo = new SceneLoadInfo { SceneName = "Coral_29", EntryGateName = "left1" }, SpecialDeath = true, ScaleHealth = ScaleToHivesteelNail } } }, new BossInfo { Name = "Garmond", JournalRecordName = "Garmond", Encounters = new List<Encounter> { new Encounter { Name = "Garmond and Zaza", SceneInfo = new SceneLoadInfo { SceneName = "Library_09", EntryGateName = "left1" }, AfterEnter = delegate { ((MonoBehaviour)GameManager.instance).StartCoroutine(Wait()); static IEnumerator Wait() { GameObject go = GameObjectUtil.FindGameObjectFromScene("Black Thread States/Normal World/Scene Control/Garmond Scene/Garmond Fighter/Citadel Library NPC"); if (go == null) { PopLogger.Log("garmond go was null"); } else { yield return (object)new WaitUntil((Func<bool>)(() => go.activeSelf)); FSMUtility.LocateMyFSM(go, "Dialogue").SetState("Battle Start"); PopLogger.Log("set fsm to start battle"); } } }, BeforeEnter = delegate { GameManager.instance.playerData.garmondInLibrary = true; }, SpecialDeath = true, TransitionDelay = 2f, ScaleHealth = ScaleToShiningNail }, new Encounter { Name = "Lost Garmond", SceneInfo = new SceneLoadInfo { SceneName = "Coral_33", EntryGateName = "right1" }, BeforeEnter = delegate { CacheUtils.CachePlayerDataBools("blackThreadWorld"); PlayerData.instance.blackThreadWorld = true; }, OnExit = delegate { CacheUtils.Restore(); }, CustomSpawnPoint = new Vector2(41f, 62f) } } }, new BossInfo { Name = "Bench", JournalRecordName = "Bench", Encounters = new List<Encounter> { new Encounter { Name = "Bench", SceneInfo = new SceneLoadInfo { SceneName = "Belltown_Room_Spare", EntryGateName = "left1" }, BeforeEnter = delegate { PlayerData.instance.BelltownFurnishingDesk = true; PlayerData.instance.BelltownFurnishingFairyLights = true; PlayerData.instance.BelltownFurnishingGramaphone = true; PlayerData.instance.BelltownFurnishingSpa = true; PlayerData.instance.BelltownFurnishingSpaAvailable = true; }, TransitionDelay = 0f } } }, new BossInfo { Name = "Blue Assistant", JournalRecordName = "Blue Assistant", Encounters = new List<Encounter> { new Encounter { Name = "Zango", SceneInfo = new SceneLoadInfo { SceneName = "Crawl_10", EntryGateName = "right1" }, BeforeEnter = delegate { CacheUtils.CachePlayerDataBools("BlueScientistDead", "blackThreadWorld"); PlayerData.instance.blackThreadWorld = true; if (((PersistentItemDataCollection<bool, SerializableBoolData>)(object)SceneData.instance.persistentBools).scenes["Crawl_10"].TryGetValue("Blue Assistant", out var value)) { value.Value = false; } }, OnExit = delegate { CacheUtils.Restore(); }, TransitionDelay = 3f } } } }; public static Dictionary<string, BossInfo> BossInfoByName = BossInfos.ToDictionary((BossInfo x) => x.Name, (BossInfo x) => x); public static Dictionary<string, Encounter> EncounterByName = AllEncounter.ToDictionary((Encounter x) => x.Name, (Encounter x) => x); public static HashSet<string> ValidRecords => BossInfos.Select((BossInfo x) => x.JournalRecordName).ToHashSet(); public static List<Encounter> AllEncounter => BossInfos.SelectMany((BossInfo x) => x.Encounters).ToList(); private static int GetNailDamage(NailType type) { return type switch { NailType.Old => 5, NailType.Sharpened => 9, NailType.Shining => 13, NailType.Hivesteel => 17, NailType.Palesteel => 21, _ => throw new NotImplementedException(), }; } private static void ScaleToNail(HealthManager hm, NailType type) { hm.hp *= Math.Max(1, Mathf.CeilToInt((float)(GetNailDamage(NailType.Palesteel) / GetNailDamage(type))) - 1); } internal static bool HasSecondEncounter(string name) { return name switch { "Mossbone Mother" => true, "Lace" => true, "Coral Conch Driller Giant" => true, "Garmond" => true, "Bone Flyer Giant" => true, _ => false, }; } internal static (bool, bool) GetMultipleEncounterInfo(string name) { if (PlayerData.instance == null) { PopLogger.LogError("player data instance was null while looking up " + name); return (false, false); } return name switch { "Mossbone Mother" => (PlayerData.instance.defeatedMossMother, true), "Lace" => (PlayerData.instance.defeatedLace1, PlayerData.instance.defeatedLaceTower), "Coral Conch Driller Giant" => (PlayerData.instance.defeatedCoralDrillerSolo, PlayerData.instance.defeatedCoralDrillers), "Garmond" => (true, PlayerData.instance.garmondBlackThreadDefeated), "Bone Flyer Giant" => (PlayerData.instance.defeatedBoneFlyerGiant, PlayerData.instance.defeatedBoneFlyerGiantGolemScene), _ => (false, false), }; } } public class Fireworks : MonoBehaviour { public float Size = 1f; public Color Color = Color.white; private ParticleSystem ps; public static GameObject CreateFirework(Vector3 position, float size, Color color, Transform parent = null) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("CodeFirework"); if ((Object)(object)parent != (Object)null) { val.transform.SetParent(parent, true); } val.transform.position = position; Fireworks fireworks = val.AddComponent<Fireworks>(); fireworks.Size = Mathf.Max(0.01f, size); fireworks.Color = color; return val; } private void Awake() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Expected O, but got Unknown //IL_02f4: Unknown result type (might be due to invalid IL or missing references) ps = ((Component)this).gameObject.AddComponent<ParticleSystem>(); ParticleSystemRenderer component = ((Component)this).gameObject.GetComponent<ParticleSystemRenderer>(); component.renderMode = (ParticleSystemRenderMode)0; component.alignment = (ParticleSystemRenderSpace)1; component.sortMode = (ParticleSystemSortMode)2; MainModule main = ps.main; ((MainModule)(ref main)).loop = false; ((MainModule)(ref main)).duration = 1.2f; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.8f, 1.6f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(4f * Size, 8f * Size); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.06f * Size, 0.18f * Size); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Color); ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0f); ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).maxParticles = 1000; EmissionModule emission = ps.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); ((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1] { new Burst(0f, (short)(60f * Size), (short)(120f * Size), 1, 0f) }); ShapeModule shape = ps.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = 0.1f * Size; ColorOverLifetimeModule colorOverLifetime = ps.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val = new Gradient(); val.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Color, 0f), new GradientColorKey(Color, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[2] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val); TrailModule trails = ps.trails; ((TrailModule)(ref trails)).enabled = true; ((TrailModule)(ref trails)).mode = (ParticleSystemTrailMode)1; ((TrailModule)(ref trails)).ratio = 1f; ((TrailModule)(ref trails)).lifetime = MinMaxCurve.op_Implicit(0.35f * Size); VelocityOverLifetimeModule velocityOverLifetime = ps.velocityOverLifetime; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)0; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).x = new MinMaxCurve(-2f * Size, 2f * Size); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = new MinMaxCurve(-2f * Size, 2f * Size); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).z = new MinMaxCurve(-2f * Size, 2f * Size); try { Material val2 = new Material(Shader.Find("Sprites/Default")); val2.SetFloat("_Mode", 0f); val2.SetColor("_TintColor", Color); ((Renderer)component).material = val2; } catch { } } private IEnumerator Start() { yield return null; if (!((Object)(object)ps == (Object)null)) { MainModule main = ps.main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Color); ps.Play(); while ((Object)(object)ps != (Object)null && ps.IsAlive(true)) { yield return null; } Object.Destroy((Object)(object)((Component)this).gameObject); } } public static Color ParseColor(string htmlColor, Color fallback) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(htmlColor)) { return fallback; } Color result = default(Color); if (ColorUtility.TryParseHtmlString(htmlColor, ref result)) { return result; } return fallback; } } public static class PopLogger { public static void Log(object message) { } public static void LogWarning(object message) { } public static void LogError(object message) { } } [BepInPlugin("momochi003.pop", "Pantheon of Pharloom", "1.2.0")] public sealed class PantheonOfPharloom : BaseUnityPlugin { [HarmonyPatch(typeof(JournalItemManager), "GetItems")] internal static class Patch_GetItems { [HarmonyPrefix] private static bool Prefix(JournalItemManager __instance, ref List<EnemyJournalRecord> __result) { if (((Object)((Component)__instance).gameObject).name == "Bosses") { __result = (from x in EnemyJournalManager.GetAllEnemies() where BossRegistry.ValidRecords.Contains(((Object)x).name) select x).ToList(); return false; } return true; } } [HarmonyPatch(typeof(InventoryItemCollectableManager), "GetItems")] internal static class PatchInventory_GetItems { [HarmonyPrefix] private static bool Prefix(InventoryItemCollectableManager __instance, ref List<CollectableItem> __result) { if (((Object)((Component)__instance).gameObject).name == "BossRush") { __result = new List<CollectableItem>(); return false; } return true; } } [HarmonyPatch(typeof(JournalItemManager), "SetDisplay", new Type[] { typeof(InventoryItemSelectable) })] internal static class Patch_SetDisplay { [HarmonyPrefix] private static bool Prefix(JournalItemManager __instance, InventoryItemSelectable selectable) { if ((Object)(object)__instance == (Object)null || (Object)(object)selectable == (Object)null) { return true; } if ((Object)(object)((Component)__instance).gameObject == (Object)null) { return true; } if (((Object)((Component)__instance).gameObject).name == "Bosses") { PopLogger.Log(selectable); ((Component)__instance).gameObject.GetComponent<BossesUIController>().BossItemSelected?.Invoke(selectable); } return true; } } [HarmonyPatch(typeof(GameManager), "ReadyForRespawn", new Type[] { typeof(bool) })] internal static class Patch_ReadyForRespawn { [HarmonyPostfix] private static void Postfix(bool isFirstLevelForPlayer) { if (isFirstLevelForPlayer) { PopLogger.Log("called game loaded...."); Instance.GameLoaded(); } } } [HarmonyPatch(typeof(GameManager), "SaveGame", new Type[] { typeof(int), typeof(Action<bool>), typeof(bool), typeof(AutoSaveName) })] internal static class Patch_SaveGame { private static bool Prefix(int saveSlot, Action<bool> ogCallback, bool withAutoSave, AutoSaveName autoSaveName) { ogCallback?.Invoke(obj: true); return false; } } private static bool _initializingMenu = false; private static bool _initialized = false; public bool CusorEnabled { get; set; } public static PantheonOfPharloom Instance { get; private set; } public static Dictionary<string, GameObject> PreloadedObjects { get; } = new Dictionary<string, GameObject>(); public event Action GameLoaded; private GameObject CreatePrefab(GameObject original) { GameObject val = Object.Instantiate<GameObject>(original); Object.DontDestroyOnLoad((Object)(object)val); val.SetActive(false); PopLogger.Log($"Created new game object: {val}"); return val; } private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) new Harmony("patcher").PatchAll(); Instance = this; SceneManager.activeSceneChanged += delegate(Scene from, Scene to) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if (((Scene)(ref to)).name == "Menu_Title" && !_initialized) { new Hook((MethodBase)typeof(Language).GetMethod("Get", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(string) }, null), (Delegate)(Func<Func<string, string, string>, string, string, string>)((Func<string, string, string> orig, string key, string sheetTitle) => (key == "Hacky") ? sheetTitle : orig(key, sheetTitle))).Apply(); new Hook((MethodBase)typeof(Language).GetMethod("Has", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(string) }, null), (Delegate)(Func<Func<string, string, bool>, string, string, bool>)((Func<string, string, bool> orig, string key, string sheetTitle) => key == "Hacky" || orig(key, sheetTitle))).Apply(); _initialized = true; } }; GameLoaded += delegate { if (!_initializingMenu) { PopLogger.Log("trying to initialize menu...."); if (BossRushController.Instance == null) { ((Component)GameManager.instance).gameObject.AddComponent<BossRushController>(); } BossRushController.Instance.Reset(patch: false); _initializingMenu = true; ((MonoBehaviour)this).StartCoroutine(InitializeMenu()); } }; BossLists.Initialize(); } private GameObject CreateVerticalButtonGroup(string name) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown GameObject val = new GameObject(name); val.AddComponent<ChildArranger>().spacing = 2.5f; return val; } public static void PatchInventoryProxy(InventoryUIController controller, PlayMakerFSM fsm) { FsmState state = fsm.GetState("Move Pane L"); PopLogger.Log(state.Actions.Length); state.InsertAction(0, (FsmStateAction)(object)new InventoryToggleAction(controller, InventoryToggleAction.MoveDirection.Left)); PopLogger.Log(state.Actions.Length); FsmState state2 = fsm.GetState("Move Pane R"); PopLogger.Log(state2.Actions.Length); state2.InsertAction(0, (FsmStateAction)(object)new InventoryToggleAction(controller, InventoryToggleAction.MoveDirection.Right)); PopLogger.Log(state2.Actions.Length); PopLogger.Log("Patched Inventory Proxy"); } private GameObject CreateButtonFromQuest(GameObject quest_template, string name, string topText, string bottomText, Transform parent, Color? color = null, string overrideQuestName = null) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(quest_template, parent); ((Object)val).name = name; Object.Destroy((Object)(object)val.GetComponent<InventoryItemMainQuest>()); Object.Destroy((Object)(object)val.GetComponent<InventoryItemExtraDescription>()); Object.Destroy((Object)(object)((Component)val.transform.Find("Sub Quests Layout")).gameObject); ((Component)val.transform.Find("Main Quest/Group/Amount Icons")).gameObject.SetActive(false); ((Component)val.transform.Find("Main Quest/Group/New Item Orb")).gameObject.SetActive(false); ((TMP_Text)((Component)val.transform.Find("Main Quest/Group/Text Type")).gameObject.GetComponent<TextMeshPro>()).text = topText; if (color.HasValue) { ((Graphic)((Component)val.transform.Find("Main Quest/Group/Text Type")).gameObject.GetComponent<TextMeshPro>()).color = color.Value; } if (overrideQuestName != null) { Sprite icon = ((BasicQuestBase)QuestManager.GetQuest(overrideQuestName)).QuestType.Icon; ((Component)val.transform.Find("Main Quest/Group/Icon")).GetComponent<SpriteRenderer>().sprite = icon; } ((TMP_Text)((Component)val.transform.Find("Main Quest/Group/Text Name")).gameObject.GetComponent<TextMeshPro>()).text = bottomText; return val; } private void CloneMemoryUseMsg(GameObject memory_use, GameObject parent) { GameObject obj = Object.Instantiate<GameObject>(memory_use, parent.transform); Transform val = obj.transform.Find("Text"); ((Object)obj).name = "Disabled Overlay"; Object.Destroy((Object)(object)((Component)val).GetComponent<SetTextMeshProGameText>()); ((TMP_Text)((Component)val).GetComponent<TextMeshPro>()).text = "Cannot use this menu when boss rush is active."; } private IEnumerator InitializeMenu() { _initializingMenu = true; yield return (object)new WaitForEndOfFrame(); yield return (object)new WaitForEndOfFrame(); GameObject inv = GameObject.Find("_GameCameras/HudCamera/In-game/Inventory"); GameObject val = GameObject.Find("_GameCameras/HudCamera/In-game/Inventory/Journal"); GameObject obj = GameObject.Find("_GameCameras/HudCamera/In-game/Inventory/Inv"); GameObject obj2 = GameObject.Find("_GameCameras/HudCamera/In-game/Inventory/Border"); GameObject quest_template = GameObject.Find("_GameCameras/HudCamera/In-game/Inventory/Quests/Quest List/Main Quests Layout/Template Main Quest Item"); GameObject val2 = Object.Instantiate<GameObject>(obj2, inv.transform); GameObject val3 = Object.Instantiate<GameObject>(val, inv.transform); GameObject val4 = Object.Instantiate<GameObject>(obj, inv.transform); Transform val5 = val3.transform.Find("Notes Desc"); GameObject val6 = Object.Instantiate<GameObject>(CreateVerticalButtonGroup("Challenge Buttons"), ((Component)val5).transform.position, Quaternion.identity, val3.transform); GameObject item = CreateButtonFromQuest(quest_template, "Challenge Button 1", "CHALLENGE", "", val6.transform); GameObject item2 = CreateButtonFromQuest(quest_template, "Challenge Button 2", "CHALLENGE", "", val6.transform); SelectableButtonList selectableButtonList = val6.AddComponent<SelectableButtonList>(); selectableButtonList.Buttons = new List<GameObject> { item, item2 }; ((Behaviour)selectableButtonList).enabled = false; val6.GetComponent<ChildArranger>().ArrangeChildrenVertical(); PopLogger.Log("GOT EHRE>...."); Object.Destroy((Object)(object)((Component)val5).gameObject); ((Component)val3.transform.Find("Text Completion")).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)val2.transform.Find("PaneListDisplay")).gameObject); GameObject val7 = Object.Instantiate<GameObject>(CreateVerticalButtonGroup("Act Buttons"), val4.transform.position + new Vector3(4f, -2.5f, 0f), Quaternion.identity, val4.transform); GameObject val8 = CreateButtonFromQuest(quest_template, "Act 1", "SYMPHONY NO.I", "Judge", val7.transform, Colors.Pharloom, "Grand Gate Bellshrines"); GameObject val9 = CreateButtonFromQuest(quest_template, "Act 2", "SYMPHONY NO.II", "Sinner", val7.transform, Colors.Citadel, "Citadel Investigate"); GameObject val10 = CreateButtonFromQuest(quest_template, "Act 3", "SYMPHONY NO.III", "Void", val7.transform, Colors.Abyss, "Black Thread Pt6 Flower"); GameObject obj3 = CreateButtonFromQuest(quest_template, "Pharloom", "FINAL SYMPHONY", "Silk & Song", val7.transform, Colors.Final, "Save the Fleas"); InventoryItemParent component = ((Component)val4.transform.Find("Inv_Items/Needle Shift/Spool Group")).gameObject.GetComponent<InventoryItemParent>(); InventoryItemSpoolPieces component2 = ((Component)val4.transform.Find("Inv_Items/Needle Shift/Spool Pieces")).gameObject.GetComponent<InventoryItemSpoolPieces>(); InventorySeletableWithName inventorySeletableWithName = val8.AddComponent<InventorySeletableWithName>(); inventorySeletableWithName.displayName = "Symphony of the Judge"; inventorySeletableWithName.description = "Face the Judge's harsh trial"; inventorySeletableWithName.cursorGlow = Colors.Pharloom; InventorySeletableWithName inventorySeletableWithName2 = val9.AddComponent<InventorySeletableWithName>(); inventorySeletableWithName2.displayName = "Symphony of the Sinner"; inventorySeletableWithName2.description = "Walk the path of a Sinner"; inventorySeletableWithName2.cursorGlow = Colors.Citadel; InventorySeletableWithName inventorySeletableWithName3 = val10.AddComponent<InventorySeletableWithName>(); inventorySeletableWithName3.displayName = "Symphony of the Void"; inventorySeletableWithName3.description = "Face what the Void has claimed"; inventorySeletableWithName3.cursorGlow = Colors.Abyss; InventorySeletableWithName inventorySeletableWithName4 = obj3.AddComponent<InventorySeletableWithName>(); inventorySeletableWithName4.displayName = "Symphony of Silk & Song"; inventorySeletableWithName4.description = "The final trial. Sounds of every battle wovenn into one"; inventorySeletableWithName4.cursorGlow = Colors.Final; ((InventoryItemSelectableDirectional)inventorySeletableWithName).Selectables = (InventoryItemSelectable[])(object)new InventoryItemSelectable[4] { default(InventoryItemSelectable), (InventoryItemSelectable)inventorySeletableWithName2, (InventoryItemSelectable)component2, default(InventoryItemSelectable) }; ((InventoryItemSelectableDirectional)inventorySeletableWithName2).Selectables = (InventoryItemSelectable[])(object)new InventoryItemSelectable[4] { (InventoryItemSelectable)inventorySeletableWithName, (InventoryItemSelectable)inventorySeletableWithName3, (InventoryItemSelectable)component2, default(InventoryItemSelectable) }; ((InventoryItemSelectableDirectional)inventorySeletableWithName3).Selectables = (InventoryItemSelectable[])(object)new InventoryItemSelectable[4] { (InventoryItemSelectable)inventorySeletableWithName2, (InventoryItemSelectable)inventorySeletableWithName4, (InventoryItemSelectable)component, default(InventoryItemSelectable) }; ((InventoryItemSelectableDirectional)inventorySeletableWithName4).Selectables = (InventoryItemSelectable[])(object)new InventoryItemSelectable[4] { (InventoryItemSelectable)inventorySeletableWithName3, default(InventoryItemSelectable), (InventoryItemSelectable)component, default(InventoryItemSelectable) }; SelectableList val11 = new SelectableList { Selectables = new List<InventoryItemSelectable>() }; ((InventoryItemSelectableDirectional)inventorySeletableWithName).FallbackSelectables = (SelectableList[])(object)new SelectableList[4] { val11, val11, val11, val11 }; ((InventoryItemSelectableDirectional)inventorySeletableWithName2).FallbackSelectables = (SelectableList[])(object)new SelectableList[4] { val11, val11, val11, val11 }; ((InventoryItemSelectableDirectional)inventorySeletableWithName3).FallbackSelectables = (SelectableList[])(object)new SelectableList[4] { val11, val11, val11, val11 }; ((InventoryItemSelectableDirectional)inventorySeletableWithName4).FallbackSelectables = (SelectableList[])(object)new SelectableList[4] { val11, val11, val11, val11 }; ((InventoryItemSelectableDirectional)component).Selectables[3] = (InventoryItemSelectable)(object)inventorySeletableWithName; ((InventoryItemSelectableDirectional)component2).Selectables[3] = (InventoryItemSelectable)(object)inventorySeletableWithName; ((InventoryItemManager)val4.GetComponent<InventoryItemCollectableManager>()).rightMostSelectables[0] = (InventoryItemSelectable)(object)inventorySeletableWithName4; GameObject gameObject = ((Component)val4.transform.Find("Memory Use Msg")).gameObject; CloneMemoryUseMsg(gameObject, val4); CloneMemoryUseMsg(gameObject, val3); val4.AddComponent<BossRushUIController>(); val4.AddComponent<DisableInventory>(); ((Object)val4).name = "BossRush"; val3.AddComponent<BossesUIController>(); val3.AddComponent<DisableInventory>(); ((Object)val3).name = "Bosses"; InventoryUIController inventoryUIController = inv.AddComponent<InventoryUIController>(); val3.SetActive(false); val4.SetActive(false); inventoryUIController.Border = val2; Activator activator = inv.AddComponent<Activator>(); inventoryUIController.ScreenPlane = ((Component)val2.transform.Find("Inventory ScreenPlane")).gameObject; inventoryUIController.RegisterEntry(InventoryType.BossRush, val4, setActive: true); inventoryUIController.RegisterEntry(InventoryType.Bosses, val3); PopLogger.Log($"done new {inv}, {val}, {val3}, {val2}, {inventoryUIController.ScreenPlane}, {val6}"); activator.OnActivate = delegate { inv.GetComponent<InventoryUIController>().EnableUI(); }; activator.OnDeactivate = delegate { inv.GetComponent<InventoryUIController>().DisableUI(); }; _initializingMenu = false; } } internal class Activator : MonoBehaviour { private PlayerAction _action; private bool _activated; public GameObject Target { get; set; } public Action<GameObject> OnActivate { get; set; } public Action<GameObject> OnDeactivate { get; set; } private void Start() { HeroActions inputActions = GameManager.instance.inputHandler.inputActions; _action = ((PlayerActionSet)inputActions).CreatePlayerAction("Bosses"); _action.AddDefaultBinding((Key[])(object)new Key[1] { (Key)37 }); } private void Update() { if ((!PlayerData.instance.isInventoryOpen || _activated) && !PlayerData.instance.disableInventory && !GameManager.instance.isPaused && GameManager.instance.hasFinishedEnteringScene && ((OneAxisInputControl)((PlayerActionSet)GameManager.instance.inputHandler.inputActions).GetPlayerActionByName("Bosses")).WasPressed) { if (!Target.activeInHierarchy) { OnActivate(Target); _activated = true; } else { OnDeactivate(Target); _activated = false; } } } } internal class AbilityToggleAction : ToggleAction { public string abilityBoolName; private SpriteRenderer _sprite; public override IEnumerator Toggle() { bool enabled = !PlayerData.instance.GetBool(abilityBoolName); PlayerData.instance.SetBool(abilityBoolName, enabled); PopLogger.Log($"toggled {abilityBoolName} from {enabled} to {!enabled}"); float num = 0.1f; _ = ((Component)this).transform.localPosition; iTween.ShakePosition(((Component)this).gameObject, iTween.Hash(new object[6] { "amount", (object)new Vector3(0.1f, 0f, 0f), "time", num, "ignoretimescale", true })); yield return (object)new WaitForSecondsRealtime(num); _sprite.color = (enabled ? new Color(1f, 1f, 1f) : new Color(0.5f, 0.5f, 0.5f, 1f)); PopLogger.Log("returning hjere"); } private void ResetShakePosition(Vector3 originalPos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Component)this).transform.localPosition = originalPos; } private void Awake() { if (_sprite == null) { _sprite = ((Component)this).gameObject.GetComponent<SpriteRenderer>(); } } } internal class ChangeNeedleToggleAction : ToggleAction { private const int TOTAL_NAILS = 5; private InventoryItemNail inventoryItemNail; private InventoryItemCollectableManager manager; public override IEnumerator Toggle() { int nailUpgrades = PlayerData.instance.nailUpgrades; int num = (nailUpgrades + 1) % 5; PlayerData.instance.nailUpgrades = num; DisplayState[] displayStates = inventoryItemNail.displayStates; GameObject displayObject = displayStates[nailUpgrades].DisplayObject; GameObject displayObject2 = displayStates[num].DisplayObject; yield return AnimationUtil.TweenHorizontal(displayObject, displayObject2, toRight: true, 0.2f, 1f); inventoryItemNail.UpdateState(); } public override IEnumerator Extra() { yield return null; } private void InfiniteNailDamage() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) new Hook((MethodBase)AccessTools.DeclaredPropertyGetter(typeof(PlayerData), "nailDamage"), (Delegate)new Func<PlayerData, int>(OverrideNailDamange)).Apply(); static int OverrideNailDamange(PlayerData self) { return 99999; } } private void Awake() { if ((Object)(object)inventoryItemNail == (Object)null) { PopLogger.Log("trying to find nail"); inventoryItemNail = ((Component)this).gameObject.GetComponent<InventoryItemNail>(); PopLogger.Log($"{inventoryItemNail} to find nail"); } if ((Object)(object)manager == (Object)null) { manager = ((Component)this).gameObject.GetComponentInParent<InventoryItemCollectableManager>(); } } } internal class DisableInventory : MonoBehaviour { private GameObject _msg; private TextMeshPro _displayText; private PlayMakerFSM _inventoryProxy; private void Awake() { _msg = ((Component)((Component)this).transform.Find("Disabled Overlay")).gameObject; _displayText = ((Component)_msg.transform.Find("Text")).GetComponent<TextMeshPro>(); _inventoryProxy = FSMUtility.LocateMyFSM(((Component)this).gameObject, "Inventory Proxy"); } private void OnEnable() { if (!BossRushController.Instance.AllowUI) { _msg.SetActive(true); ((Behaviour)_inventoryProxy).enabled = false; } } private void OnDisable() { ((Behaviour)_inventoryProxy).enabled = true; _msg.SetActive(false); } } internal enum PantheonType { Pharloom, Citadel, Abyss, Silksong } internal class PantheonChallengeAction : ToggleAction { public PantheonType pantheonType; public override bool CloseUI => true; public override IEnumerator Toggle() { switch (pantheonType) { case PantheonType.Pharloom: BossRushController.SetupNewSequence(BossLists.PharloomEncounters.ToList(), transition: true); break; case PantheonType.Citadel: BossRushController.SetupNewSequence(BossLists.CitadelEncounters.ToList(), transition: true); break; case PantheonType.Abyss: BossRushController.SetupNewSequence(BossLists.AbyssEncounters.ToList(), transition: true); break; case PantheonType.Silksong: BossRushController.SetupNewSequence(BossLists.SilksongEncounters.ToList(), transition: true); break; } yield return null; } } public class SelectableButtonList : MonoBehaviour { public InventoryCursor InventoryCursor; public List<GameObject> Buttons = new List<GameObject>(); public int SelectedIndex { get; private set; } = -1; public int ButtonCount => Buttons.Count; public GameObject SelectedButton { get { if (SelectedIndex < 0 || SelectedIndex >= Buttons.Count) { return null; } return Buttons[SelectedIndex]; } } private void Update() { if (((OneAxisInputControl)GameManager.instance.inputHandler.inputActions.Down).WasPressed) { Next(); } if (((OneAxisInputControl)GameManager.instance.inputHandler.inputActions.Up).WasPressed) { Previous(); } } public void Select() { for (int i = 0; i < Buttons.Count; i++) { if (Buttons[i].activeInHierarchy) { Select(i); break; } } } public void Select(int index) { if (index >= 0 && index < Buttons.Count) { SelectedIndex = index; InventoryCursor.ResetClampedPos(); InventoryCursor.SetTarget(Buttons[SelectedIndex].transform); } } public void Next() { if (Buttons.Count != 0) { int selectedIndex = SelectedIndex; int num = (SelectedIndex + 1) % Buttons.Count; while (num != selectedIndex && !Buttons[num].activeInHierarchy) { num = (num + 1) % Buttons.Count; } if (num != selectedIndex) { Select(num); } } } public void Previous() { if (Buttons.Count != 0) { int selectedIndex = SelectedIndex; int num = (SelectedIndex - 1 + Buttons.Count) % Buttons.Count; while (num != selectedIndex && !Buttons[num].activeInHierarchy) { num = (num - 1 + Buttons.Count) % Buttons.Count; } if (num != selectedIndex) { Select(num); } } } } internal abstract class ToggleAction : MonoBehaviour { public virtual bool CloseUI { get; set; } public abstract IEnumerator Toggle(); public virtual IEnumerator Extra() { yield return null; } } public class ChildArranger : MonoBehaviour { [SerializeField] public float spacing = 1f; [SerializeField] public bool arrangeOnStart = true; public void ArrangeChildrenVertical() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) float num = 0f; for (int i = 0; i < ((Component)this).transform.childCount; i++) { ((Component)this).transform.GetChild(i).localPosition = new Vector3(0f, 0f - num, 0f); num += spacing; } } public void ArrangeChildrenHorizontal() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) float num = 0f; for (int i = 0; i < ((Component)this).transform.childCount; i++) { ((Component)this).transform.GetChild(i).localPosition = new Vector3(num, 0f, 0f); num -= spacing; } } private void Start() { if (arrangeOnStart) { ArrangeChildrenVertical(); } } } public enum InventoryType { Bosses, BossRush } public class InventoryUIController : MonoBehaviour { public class InventoryEntry { private string ProxyFSMName = "Inventory Proxy"; public InventoryType Type { get; } public GameObject Root { get; } private string ControlFSMName { get { if (Type != 0) { return "UI Inventory"; } return "UI Journal"; } } public InventoryEntry(InventoryType type, GameObject root) { Type = type; Root = root; } public void SetupFSMEnable(SelectedActionType select = 3) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_0051