Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Pantheon Of Pharloom v1.3.2
PantheonOfPharloom.dll
Decompiled 6 months 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 GlobalSettings; 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+b3d1a911a7e4c2c15f63eddf66dc13c6e87c03af")] [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 BossRushSequence _sequence; 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 => _sequence.Current(); 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) { if (!(text == "visitedGreymoor") && !(text == "visitedCoral")) { _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.respawnScene + ", " + PlayerData.instance.respawnMarkerName + ", " + PlayerData.instance.tempRespawnScene + ", " + PlayerData.instance.tempRespawnMarker); } private void AfterDeathOrCompletion() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (_sequence == null) { PopLogger.LogError("Sequence was null here should never happen"); } _sequence.Cleanup?.Invoke(); Reset(); PlayerData.instance.respawnScene = _userState.Scene; PlayerData.instance.respawnMarkerName = _userState.Marker; PopLogger.Log("Setting after death or completion: " + PlayerData.instance.respawnScene + ", " + PlayerData.instance.respawnMarkerName); HeroItemsState items = _userState.Items; ((HeroItemsState)(ref items)).Apply(HeroController.instance); } private void OnHornetDeath() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown if (_userState != null) { RestoreSpawnScene(); } CurrentEncounter.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, Action beforeEncounter = null, Action cleanup = null) { //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._sequence = new BossRushSequence(encounters, beforeEncounter, null, cleanup); Instance._isActive = true; PatchPlayerData(); FadeSceneInHook.Init(); FadeSceneInHook.SetEnabled(enabled: true); if (transition) { Instance.NextBoss(); } } private void BeginBossRushCompletion(float delay) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown PopLogger.Log("end reached"); 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, SceneAfterFinish(), delegate { GameManager.instance.RespawningHero = true; }); IEnumerator SceneAfterFinish() { _sequence.Previous().AfterExit?.Invoke(); AfterDeathOrCompletion(); yield return null; PopLogger.Log("created fireworks"); } } private void NextBoss() { if (!_sequence.TryGetNext(out var next)) { BeginBossRushCompletion(_sequence.Previous().TransitionDelay); return; } PopLogger.Log("calling NextBoss."); if (!_sequence.IsFirstInSequence) { _sequence.Previous().OnExit?.Invoke(); _sequence.AfterEncounter?.Invoke(); } _sequence.BeforeEncounter?.Invoke(); next.BeforeEnter?.Invoke(); PopLogger.Log($"Starting next boss scene: {next.SceneInfo}"); StartTransitionWithCallback(next.SceneInfo, _sequence.IsFirstInSequence ? 0f : _sequence.Previous().TransitionDelay, OnNewEncounterLoad, doTransition: true, delegate { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) string sceneName = CurrentEncounter.SceneInfo.SceneName; Scene activeScene = SceneManager.GetActiveScene(); return sceneName == ((Scene)(ref activeScene)).name; }); } private void TransitionFromBench() { if (!_sequence.TryGetNext(out var next)) { BeginBossRushCompletion(_sequence.Previous().TransitionDelay); return; } if (!_sequence.IsFirstInSequence) { _sequence.Previous().OnExit?.Invoke(); } next.BeforeEnter?.Invoke(); StartTransitionWithCallback(next.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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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 (!_sequence.IsFirstInSequence) { _sequence.Previous().AfterExit?.Invoke(); } CurrentEncounter.AfterEnter?.Invoke(); PatchBadStates(); IEncounterCompletedNotification encounterCompletedNotification = EncounterCompletionRegistry.AddEncounterCompletion(Object.Instantiate<GameObject>(new GameObject("BossRushController")), CurrentEncounter); if (encounterCompletedNotification is BenchTransitionNotification benchTransitionNotification) { if (_sequence.TryPeekNext(out var next)) { benchTransitionNotification.nextScene = next.SceneInfo.SceneName; benchTransitionNotification.nextGate = next.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, Func<bool> predicate = null) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if (doTransition) { ((MonoBehaviour)this).StartCoroutine(DoTransition(info, delay)); } GameManager.instance.OnFinishedEnteringScene += new EnterSceneEvent(Wrapper); void Wrapper() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown if (predicate != null && !predicate()) { PopLogger.Log("did not satisfy condition...."); } else { 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown _sequence = null; _isActive = false; FadeSceneInHook.Unload(); if (patch) { RestorePlayerData(); HeroController.instance.OnDeath -= OnHornetDeath; GameManager.instance.OnFinishedEnteringScene -= new EnterSceneEvent(OnNewEncounterLoad); } } } public class BossRushSequence { private List<Encounter> _encounters = new List<Encounter>(encounters); public readonly Action BeforeEncounter; public readonly Action AfterEncounter; public readonly Action Cleanup; private int _encounterIndex; public bool IsFirstInSequence => _encounterIndex == 0; public BossRushSequence(IEnumerable<Encounter> encounters, Action beforeEncounter = null, Action afterEncounter = null, Action cleanup = null) { BeforeEncounter = beforeEncounter; AfterEncounter = afterEncounter; Cleanup = cleanup; _encounterIndex = -1; base..ctor(); } public bool TryGetNext([MaybeNullWhen(false)] out Encounter next) { _encounterIndex++; if (_encounterIndex == _encounters.Count) { next = default(Encounter); return false; } next = _encounters[_encounterIndex]; return true; } public bool TryPeekNext([MaybeNullWhen(false)] out Encounter next) { if (_encounterIndex + 1 >= _encounters.Count) { next = default(Encounter); return false; } next = _encounters[_encounterIndex + 1]; return true; } public Encounter Previous() { return _encounters[_encounterIndex - 1]; } public Encounter Current() { return _encounters[_encounterIndex]; } } 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 SingleConchflyDeadNotification : BossEncounterCompleteNotification { private void Start() { GameObject obj = GameObjectUtil.FindGameObjectFromScene("Battle Scene/Wave 1/Coral Conch Driller Giant Solo/Corpse Coral Conch Driller Giant Solo(Clone)"); PlayMakerFSM val = ((obj != null) ? FSMUtility.LocateMyFSM(obj, "Death") : null); if (val == null) { PopLogger.LogError("Could not find conch corpse fsm"); return; } val.GetState("Stagger").InsertMethod(0, base.BossDead); PopLogger.Log("patched single conchfly"); } } 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) }, { "Single Conchfly", typeof(SingleConchflyDeadNotification) }, { "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 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 Encounter GetEncounterByName(string name, bool is_void) { if (is_void && BossRegistry.EncounterByName.TryGetValue(name + " (Void)", out var value)) { return value; } return BossRegistry.EncounterByName[name]; } 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 static Encounter[] PharloomEncounters(bool is_void) { return PharloomBosses.Select((string x) => GetEncounterByName(x, is_void)).ToArray(); } public static Encounter[] CitadelEncounters(bool is_void) { return CitadelBosses.Select((string x) => GetEncounterByName(x, is_void)).ToArray(); } public static Encounter[] AbyssEncounters(bool is_void) { return AbyssBosses.Select((string x) => GetEncounterByName(x, is_void)).ToArray(); } public static Encounter[] SilksongEncounters(bool is_void) { return SilksongBosses.Select((string x) => GetEncounterByName(x, is_void)).ToArray(); } } 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 obj7 = GameObjectUtil.FindGameObjectFromScene("Black Thread States/Normal World/Battle Scene/Wave 1"); if (obj7 != null) { GameObject gameObject = obj7.gameObject; if (gameObject != null) { gameObject.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.TryGetValue("Weave_03", out var value9) && value9.TryGetValue("Boss Scene", out var value10)) { value10.Value = false; } }, AfterEnter = delegate { ScaleTransitionHP("Mossbone Mother A", "Control", NailType.Sharpened, "HP P2", "HP Call Buddy", "HP Half"); }, 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 = ScaleToHivesteelNail }, 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 = ScaleToHivesteelNail }, new Encounter { Name = "Savage Beastfly (Void)", SceneInfo = new SceneLoadInfo { SceneName = "Ant_19", EntryGateName = "left1", Visualization = (SceneLoadVisualizations)0, PreventCameraFadeOut = false }, BeforeEnter = delegate { CacheUtils.CachePlayerDataBools("blackThreadWorld"); PlayerData.instance.defeatedBoneFlyerGiant = false; PlayerData.instance.blackThreadWorld = true; }, OnExit = delegate { CacheUtils.Restore(); PlayerData.instance.defeatedBoneFlyerGiant = true; }, BossPathFromRoot = new string[1] { "Boss Control/Boss Scene/Bone Flyer Giant" }, CustomSpawnPoint = new Vector2(63f, 34.6f) }, new Encounter { Name = "Savage Beastfly 2 (Void)", 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", "blackThreadWorld"); PlayerData.instance.defeatedBoneFlyerGiantGolemScene = false; PlayerData.instance.defeatedSongGolem = true; PlayerData.instance.blackThreadWorld = 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 }, AfterEnter = delegate { ScaleTransitionHP("Boss Scene/Bone Beast", "Control", NailType.Sharpened, "P2 HP"); }, 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 = ScaleToSharpenedNail } } }, 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 { }, AfterEnter = delegate { if (GameObjectUtil.FindGameObjectFromScene("Boss Scene/Dock Guard Slasher") != null) { ScaleTransitionHP("Boss Scene/Dock Guard Slasher", "Control", NailType.Hivesteel, "P2 HP", "P3 HP", "P4 HP"); } }, 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 } } }, 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; }, AfterEnter = delegate { ScaleTransitionHP("Vampire Gnat Scene/Vampire Gnat", "Control", NailType.Sharpened, "P2 HP"); }, OnExit = delegate { PlayerData.instance.defeatedVampireGnatBoss = true; }, BossPathFromRoot = new string[1] { "Vampire Gnat Scene/Vampire Gnat" }, ScaleHealth = ScaleToSharpenedNail } } }, 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 { }, AfterEnter = delegate { ScaleTransitionHP("Boss Scene Parent/Boss Scene/Splinter Queen", "Control", NailType.Sharpened, "HP", "P2 HP", "P3 HP"); }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Boss Scene Parent/Boss Scene/Splinter Queen" }, ScaleHealth = ScaleToSharpenedNail } } }, 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 { }, CustomSpawnPoint = new Vector2(121f, 7f) } } }, 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" }, AfterEnter = delegate { ScaleTransitionHP("Boss Scene/Last Judge", "Control", NailType.Shining, "HP", "HP P2", "HP P3"); }, 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.TryGetValue("Coral_Judge_Arena", out var value7) && value7.TryGetValue("Last Judge", out var value8)) { value8.Value = false; } }, OnExit = delegate { }, BossPathFromRoot = new string[1] { "Boss Scene/Last Judge" }, TransitionDelay = 0f, CustomSpawnPoint = new Vector2(25f, 25f), ScaleHealth = ScaleToShiningNail } } }, new BossInfo { Name = "Coral Conch Driller Giant", JournalRecordName = "Coral Conch Driller Giant", Encounters = new List<Encounter> { 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 = ScaleToShiningNail }, new Encounter { Name = "Single Conchfly", SceneInfo = new SceneLoadInfo { SceneName = "Coral_27", EntryGateName = "left1" }, BeforeEnter = delegate { }, OnExit = delegate { }, CustomSpawnPoint = new Vector2(20f, 34f) } } }, 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, CustomSpawnPoint = new Vector2(35f, 360f) } } }, 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 { }, AfterEnter = delegate { ScaleTransitionHP("Dancer Control", "Control", NailType.Sharpened, "Phase 1 HP", "Phase 2 HP", "Phase 3 HP", "Phase 4 HP"); }, 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" }, AfterEnter = delegate { ScaleTransitionHP("Grand Stage Scene/Boss Scene Trobbio/Trobbio", "Control", NailType.Shining, "P2 HP"); }, 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 obj6 = GameObjectUtil.FindGameObjectFromScene("Grand Stage Scene/Boss Scene TormentedTrobbio"); if (obj6 != null) { obj6.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.TryGetValue("Clover_10", out var value5) && value5.TryGetValue("Dancer A", out var value6)) { value6.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 obj5 = GameObjectUtil.FindGameObjectFromScene("Pinstress Control/Pinstress Scene/Pinstress Boss/NPC"); FsmState state = ((obj5 != null) ? FSMUtility.LocateMyFSM(obj5, "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.TryGetValue("Belltown_Shrine", out var value3) && value3.TryGetValue("Bellshrine Sequence Bellhart", out var value4)) { value4.Value = 0; } }, AfterEnter = delegate { string boss_path = "Black Thread States Thread Only Variant/Normal World/Boss Scene/Spinner Boss"; ScaleTransitionHP(boss_path, "Control", NailType.Old, "P2 HP", "P3 HP"); ScaleTransitionHP(boss_path, "Fake Death", NailType.Old, "P3 HP"); }, AfterExit = delegate { ((MonoBehaviour)GameManager.instance).StartCoroutine(HeroController.instance.Respawn(HeroController.instance.transform)); }, 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 { }, AfterEnter = delegate { ScaleTransitionHP("Boss Scene/First Weaver", "Control", NailType.Shining, "HP", "Can Bind HP", "P2 HP", "Max HP"); }, 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"); }, AfterExit = delegate { ((MonoBehaviour)GameManager.instance).StartCoroutine(HeroController.instance.Respawn(HeroController.instance.transform)); }, BossPathFromRoot = new string[1] { "Boss Scene/Phantom" }, TransitionDelay = 0f, ScaleHealth = ScaleToShiningNail } } }, 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; }, AfterEnter = delegate { ScaleTransitionHP("Boss Scene/Lace Boss1", "Control", NailType.Old, "Rage HP"); }, 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" }, AfterEnter = delegate { ScaleTransitionHP("Boss Scene/Lace Boss2 New", "Control", NailType.Shining, "P2 HP", "P3 HP"); GameObject obj4 = GameObject.Find("Boss Scene/Lace Boss2 New"); PlayMakerFSM val2 = ((obj4 != null) ? FSMUtility.LocateMyFSM(obj4, "Control") : null); if (val2 != null) { val2.SendEvent("BATTLE START REFIGHT"); } }, 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 { }, AfterEnter = delegate { ScaleTransitionHP("Silk Boss", "Phase Control", NailType.Shining, "P1 HP", "P2 HP", "P3 HP", "P4 HP", "P5 HP", "P6 HP"); }, 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 { GameObject obj3 = GameObject.Find("Hornet Dummy"); if (obj3 != null) { obj3.SetActive(false); } }, AfterExit = delegate { CoroutineUtil.WaitAndExecute(0.1f, delegate { GameObject obj2 = GameObject.Find("Hornet Dummy"); if (obj2 != null) { obj2.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 { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) PlayerData.instance.mapperMentorConvo = true; PlayerData.instance.mapperSparIntro = true; Completion data = ((SerializableNamedList<Completion, NamedCompletion>)(object)PlayerData.instance.QuestCompletionData).GetData("Shakra Final Quest"); CacheStack<Completion>.Cache(data); ((SerializableNamedList<Completion, NamedCompletion>)(object)PlayerData.instance.QuestCompletionData).SetData("Shakra Final Quest", QuestCompletionData.Completed); }, 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"); } }, OnExit = delegate { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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) Completion val = CacheStack<Completion>.Get(); ((SerializableNamedList<Completion, NamedCompletion>)(object)PlayerData.instance.QuestCompletionData).SetData("Shakra Final Quest", val); }, 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.TryGetValue("Crawl_10", out var value) && value.TryGetValue("Blue Assistant", out var value2)) { value2.Value = false; } }, OnExit = delegate { CacheUtils.Restore(); }, TransitionDelay = 3f, CustomSpawnPoint = new Vector2(32f, 8f) } } } }; 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 float GetNailDamage(NailType type) { return type switch { NailType.Old => 5f, NailType.Sharpened => 9f, NailType.Shining => 13f, NailType.Hivesteel => 17f, NailType.Palesteel => 21f, _ => throw new NotImplementedException(), }; } private static float GetMultiplier(NailType type) { float num = GetNailDamage(NailType.Palesteel) / GetNailDamage(type); return Mathf.Max(1f, num); } private static void ScaleToNail(HealthManager hm, NailType type) { hm.hp = Mathf.CeilToInt(GetMultiplier(type) * (float)hm.hp); hm.initHp = hm.hp; PopLogger.Log($"Scaled health for {((Component)hm).gameObject} to {hm.hp}"); } private static void ScaleTransitionHP(string boss_path, string fsm_name, NailType type, params string[] variables) { GameObject val = GameObject.Find(boss_path) ?? GameObjectUtil.FindGameObjectFromScene(boss_path); if (val == null) { PopLogger.Log("Could not find boss to scale HP"); return; } PlayMakerFSM val2 = FSMUtility.LocateMyFSM(val, fsm_name); if (val2 == null) { PopLogger.Log("could not find fsm for scaling"); return; } foreach (string text in variables) { FsmInt fsmInt = val2.FsmVariables.GetFsmInt(text); if (fsmInt == null) { PopLogger.Log("Could not find fsm int: " + text); continue; } fsmInt.Value = Mathf.CeilToInt((float)fsmInt.Value * GetMultiplier(type)); PopLogger.Log($"Setting {text} to {fsmInt.Value}"); } PopLogger.Log($"Patched transition hps for {val}"); } 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 interface IBindings { void ApplyBindings(); void RestoreBindings(); } public class HealthBindings : IBindings { [CompilerGenerated] private int <boundMax>P; private List<GameObject> _overlays; private List<GameObject> _modifiedHealthDisplays; private int _prevMaxHealth; public bool Active { get; private set; } public HealthBindings(int boundMax) { <boundMax>P = boundMax; _overlays = new List<GameObject>(); _modifiedHealthDisplays = new List<GameObject>(); base..ctor(); } public void ApplyUI() { _overlays.Clear(); Transform hudCanvas = Bindings.HudCanvas; GameObject health = ((Component)hudCanvas.Find("Health")).gameObject; PopLogger.Log($"Found health {health}"); foreach (PlayMakerFSM item in from i in Enumerable.Range(0, health.transform.childCount) select FSMUtility.LocateMyFSM(((Component)health.transform.GetChild(i)).gameObject, "health_display")) { if (item != null) { FsmInt fsmInt = item.FsmVariables.GetFsmInt("Health Number"); int? num = ((fsmInt != null) ? new int?(fsmInt.Value) : null); if (num.HasValue && num.Value > <boundMax>P && num.Value <= 10 && num.Value <= _prevMaxHealth) { ((Behaviour)item).enabled = false; GameObject gameObject = ((Component)item).gameObject; PopLogger.Log($"Found health display for health number {num.Value} at {gameObject}"); GameObject gameObject2 = ((Component)((Component)gameObject.transform.Find("Idle")).gameObject.transform.parent).gameObject; gameObject2.SetActive(false); _modifiedHealthDisplays.Add(gameObject2); } } } EventRegister.SendEvent(EventRegisterEvents.HealthUpdate, (GameObject)null); EventRegister.SendEvent(EventRegisterEvents.HeroHealed, (GameObject)null); EventRegister.SendEvent(EventRegisterEvents.HeroHealedToMax, (GameObject)null); } public void RestoreUI() { foreach (GameObject overlay in _overlays) { if (overlay != null) { overlay.SetActive(false); } } _overlays.Clear(); foreach (GameObject modifiedHealthDisplay in _modifiedHealthDisplays) { if (modifiedHealthDisplay != null) { modifiedHealthDisplay.SetActive(true); } } EventRegister.SendEvent(EventRegisterEvents.HealthUpdate, (GameObject)null); EventRegister.SendEvent(EventRegisterEvents.HeroHealed, (GameObject)null); } public void ApplyBindings() { Active = true; _prevMaxHealth = PlayerData.instance.maxHealth; PlayerData.instance.maxHealth = <boundMax>P; PlayerData.instance.maxHealthBase = <boundMax>P; PlayerData.instance.health = Mathf.Min(<boundMax>P, PlayerData.instance.health); ApplyUI(); } public void RestoreBindings() { Active = false; PlayerData.instance.maxHealth = _prevMaxHealth; PlayerData.instance.health = _prevMaxHealth; PlayerData.instance.maxHealthBase = _prevMaxHealth; RestoreUI(); } } public class SilkBindings : IBindings { [CompilerGenerated] private int <maxSilk>P; private int _prevSilk; public bool Active { get; private set; } public SilkBindings(int maxSilk) { <maxSilk>P = maxSilk; base..ctor(); } private void ApplyUI() { EventRegister.SendEvent(EventRegisterEvents.RegeneratedSilkChunk, (GameObject)null); } private void RestoreUI() { EventRegister.SendEvent(EventRegisterEvents.RegeneratedSilkChunk, (GameObject)null); } public void ApplyBindings() { _prevSilk = PlayerData.instance.silkMax; PlayerData.instance.silkMax = <maxSilk>P; PlayerData.instance.silk = Mathf.Min(<maxSilk>P, PlayerData.instance.silk); ApplyUI(); Active = true; } public void RestoreBindings() { PlayerData.instance.silkMax = _prevSilk; Active = false; RestoreUI(); } } public class NailBindings : IBindings { [CompilerGenerated] private float <multiplier>P; public float Multiplier => <multiplier>P; public bool Active { get; private set; } public NailBindings(float multiplier) { <multiplier>P = multiplier; base..ctor(); } public void ApplyBindings() { Hooks.EnableBoundNail(); Active = true; } public void RestoreBindings() { Hooks.DisableBoundNail(); Active = false; } } public class SkillBindings : IBindings { private Dictionary<string, List<string>> _removedTools = new Dictionary<string, List<string>>(); public bool Active { get; private set; } public void ApplyBindings() { Active = true; _removedTools = CrestUtil.RemoveAllTools((ToolItemType x) => (int)x != 3); Hooks.EnablePreventToolUse(); } public void RestoreBindings() { Active = false; CrestUtil.RestoreAllTools(_removedTools, (ToolItemType x) => (int)x != 3); Hooks.DisablePreventToolUse(); } } public class ToolBindings : IBindings { private Dictionary<string, List<string>> _removedTools = new Dictionary<string, List<string>>(); public bool Active { get; private set; } public void ApplyBindings() { Active = true; _removedTools = CrestUtil.RemoveAllTools((ToolItemType x) => (int)x == 3); Hooks.EnablePreventToolUse(); } public void RestoreBindings() { Active = false; CrestUtil.RestoreAllTools(_removedTools, (ToolItemType x) => (int)x == 3); Hooks.DisablePreventToolUse(); } } public static class Bindings { public static HealthBindings HealthBindings = new HealthBindings(4); public static SilkBindings SilkBindings = new SilkBindings(9); public static NailBindings NailBindings = new NailBindings(0.6f); public static SkillBindings SkillBindings = new SkillBindings(); public static ToolBindings ToolBindings = new ToolBindings(); public static Transform HudCanvas => ((Component)GameCameras.instance.hudCamera).transform.Find("In-game/Anchor TL/Hud Canvas Offset/Hud Canvas"); private static void Reset() { HealthBindings = new HealthBindings(4); SilkBindings = new SilkBindings(9); NailBindings = new NailBindings(0.6f); SkillBindings = new SkillBindings(); ToolBindings = new ToolBindings(); } } public class Hooks { public enum HookBehavior { DoubleDamage, InfiniteDamage, BoundNail, PreventToolUse } private static readonly Dictionary<HookBehavior, ToggleableHook> _hooks = new Dictionary<HookBehavior, ToggleableHook>(); private static Action<Action<PlayerData, int, bool, bool>, PlayerData, int, bool, bool> CreateDamageHook(int multiplier, bool absolute) { return delegate(Action<PlayerData, int, bool, bool> orig, PlayerData self, int amount, bool blue, bool mask) { PopLogger.Log($"calling orig with damage: {multiplier * amount}"); orig(self, multiplier * amount, blue, !absolute && mask); }; } private static void BindNailDamageHook(Action<HealthManager, HitInstance> orig, HealthManager self, HitInstance hit) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) //IL_0019: Invalid comparison between Unknown and I4 if ((int)hit.AttackType == 0 || (int)hit.AttackType == 7 || (int)hit.AttackType == 16) { hit.DamageDealt = Math.Min(hit.DamageDealt, Mathf.CeilToInt((float)PlayerData.instance.nailDamage * Bindings.NailBindings.Multiplier)); } orig(self, hit); } private static bool InventoryToolSlotHook(Func<InventoryItemTool, bool> orig, InventoryItemTool self) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)self.ToolType == 3) { if (Bindings.SkillBindings.Active) { PopLogger.Log("Preventing tool use for " + ((Object)self).name); return false; } } else if (Bindings.ToolBindings.Active) { PopLogger.Log("Preventing tool use for " + ((Object)self).name); return false; } return orig(self); } public static void Initialize() { _hooks[HookBehavior.DoubleDamage] = new ToggleableHook(AccessTools.DeclaredMethod(typeof(PlayerData), "TakeHealth", (Type[])null, (Type[])null), CreateDamageHook(2, absolute: false)); _hooks[HookBehavior.InfiniteDamage] = new ToggleableHook(AccessTools.DeclaredMethod(typeof(PlayerData), "TakeHealth", (Type[])null, (Type[])null), CreateDamageHook(56, absolute: true)); _hooks[HookBehavior.BoundNail] = new ToggleableHook(AccessTools.DeclaredMethod(typeof(HealthManager), "TakeDamage", (Type[])null, (Type[])null), new Action<Action<HealthManager, HitInstance>, HealthManager, HitInstance>(BindNailDamageHook)); _hooks[HookBehavior.PreventToolUse] = new ToggleableHook(AccessTools.DeclaredMethod(typeof(InventoryItemTool), "Submit", (Type[])null, (Type[])null), new Func<Func<InventoryItemTool, bool>, InventoryItemTool, bool>(InventoryToolSlotHook)); } public static void EnableDoubleDamage() { PopLogger.Log("enabling double damage"); _hooks[HookBehavior.DoubleDamage].Enable(); } public static void DisableDoubleDamage() { PopLogger.Log("disabling double damage"); _hooks[HookBehavior.DoubleDamage].Disable(); } public static void EnableInfiniteDamage() { _hooks[HookBehavior.InfiniteDamage].Enable(); } public static void DisableInfiniteDamage() { _hooks[HookBehavior.InfiniteDamage].Disable(); } public static void EnableBoundNail() { _hooks[HookBehavior.BoundNail].Enable(); } public static void DisableBoundNail() { _hooks[HookBehavior.BoundNail].Disable(); } public static void EnablePreventToolUse() { _hooks[HookBehavior.PreventToolUse].Enable(); } public static void DisablePreventToolUse() { if (!Bindings.SkillBindings.Active && !Bindings.ToolBindings.Active) { _hooks[HookBehavior.PreventToolUse].Disable(); } } } 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.3.2")] 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") { List<EnemyJournalRecord> list = new List<EnemyJournalRecord>(); foreach (EnemyJournalRecord item in from x in EnemyJournalManager.GetAllEnemies() where BossRegistry.ValidRecords.Contains(((Object)x).name) select x) { if ((((Object)item).name == "Shakra" || ((Object)item).name == "Blue Assistant") && PlayerData.instance.blackThreadWorld) { item.isAlwaysUnlocked = true; } list.Add(item); } __result = list; 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(); Hooks.Initialize(); 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) {