using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using HutongGames.PlayMaker; using HutongGames.PlayMaker.Actions; using TeamCherry.Localization; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("FuriousTrobbio")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FuriousTrobbio")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("0A3CE2E0-F494-45DA-BED3-6A7FC5DB5A38")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] internal static class FsmDiagnostics { internal static void LogChoiceMap(ManualLogSource log, PlayMakerFSM controlFsm, FsmState choiceState) { if (log != null && !((Object)(object)controlFsm == (Object)null) && choiceState != null) { log.LogInfo((object)("[DIAGNOSTIC] ===== " + ((Object)((Component)controlFsm).gameObject).name + " / " + controlFsm.FsmName + " FSM =====")); log.LogInfo((object)"[DIAGNOSTIC] ----- States -----"); FsmState[] fsmStates = controlFsm.FsmStates; foreach (FsmState val in fsmStates) { log.LogInfo((object)("[DIAGNOSTIC] State: " + val.Name)); } log.LogInfo((object)("[DIAGNOSTIC] ----- " + choiceState.Name + " transitions -----")); FsmTransition[] transitions = choiceState.Transitions; foreach (FsmTransition val2 in transitions) { log.LogInfo((object)("[DIAGNOSTIC] Event '" + val2.EventName + "' -> '" + val2.ToState + "'")); } log.LogInfo((object)("[DIAGNOSTIC] ----- " + choiceState.Name + " actions -----")); for (int k = 0; k < choiceState.Actions.Length; k++) { FsmStateAction val3 = choiceState.Actions[k]; string text = ((val3 == null) ? "" : ((object)val3).GetType().FullName); log.LogInfo((object)("[DIAGNOSTIC] Action " + k + ": " + text)); } log.LogInfo((object)"[DIAGNOSTIC] ================================================"); } } internal static void LogStateDetails(ManualLogSource log, FsmState state, string label) { if (log == null || state == null) { return; } log.LogInfo((object)("[PYRO DIAGNOSTIC] ===== " + label + ": " + state.Name + " =====")); FsmTransition[] transitions = state.Transitions; foreach (FsmTransition val in transitions) { log.LogInfo((object)("[PYRO DIAGNOSTIC] Transition '" + val.EventName + "' -> '" + val.ToState + "'")); } for (int j = 0; j < state.Actions.Length; j++) { FsmStateAction val2 = state.Actions[j]; if (val2 != null) { log.LogInfo((object)("[PYRO DIAGNOSTIC] Action " + j + ": " + ((object)val2).GetType().FullName)); FieldInfo[] fields = ((object)val2).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { log.LogInfo((object)("[PYRO DIAGNOSTIC] " + fieldInfo.Name + " = " + DescribeValue(fieldInfo.GetValue(val2)))); } } } } internal static void LogFsmDetails(ManualLogSource log, PlayMakerFSM fsm, string label) { if (log != null && !((Object)(object)fsm == (Object)null)) { log.LogInfo((object)("[PYRO DIAGNOSTIC] ######## " + label + ": " + ((Object)((Component)fsm).gameObject).name + " / " + fsm.FsmName + " ########")); FsmState[] fsmStates = fsm.FsmStates; foreach (FsmState state in fsmStates) { LogStateDetails(log, state, label); } log.LogInfo((object)"[PYRO DIAGNOSTIC] ############################################"); } } internal static void LogMatchingStates(ManualLogSource log, PlayMakerFSM fsm, string label) { if (log == null || (Object)(object)fsm == (Object)null) { return; } log.LogInfo((object)("[PYRO DIAGNOSTIC] ######## " + label + ": " + ((Object)((Component)fsm).gameObject).name + " / " + fsm.FsmName + " ########")); FsmState[] fsmStates = fsm.FsmStates; foreach (FsmState val in fsmStates) { string text = val.Name.ToLowerInvariant(); bool flag = text.Contains("burst") || text.Contains("column") || text.Contains("trap"); FsmTransition[] transitions = val.Transitions; foreach (FsmTransition val2 in transitions) { string text2 = val2.EventName.ToLowerInvariant(); string text3 = val2.ToState.ToLowerInvariant(); flag |= text2.Contains("burst") || text2.Contains("column") || text2.Contains("trap") || text3.Contains("burst") || text3.Contains("column") || text3.Contains("trap"); } if (flag) { LogStateDetails(log, val, label); } } log.LogInfo((object)"[PYRO DIAGNOSTIC] ############################################"); } internal static void LogPyrotechnicsSceneObjects(ManualLogSource log, string sceneName) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (log == null) { return; } string[] array = new string[7] { "burst", "column", "trap", "floor", "fire", "flame", "pyro" }; log.LogInfo((object)"[PYRO DIAGNOSTIC] ===== Matching scene objects ====="); GameObject[] array2 = Resources.FindObjectsOfTypeAll(); foreach (GameObject val in array2) { if ((Object)(object)val == (Object)null) { continue; } Scene scene = val.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } scene = val.scene; if (!(((Scene)(ref scene)).name != sceneName)) { string lowerName = ((Object)val).name.ToLowerInvariant(); if (Array.Exists(array, (string term) => lowerName.Contains(term))) { log.LogInfo((object)("[PYRO DIAGNOSTIC] Object " + GetHierarchyPath(val.transform) + ", active=" + val.activeSelf + ".")); } } } log.LogInfo((object)"[PYRO DIAGNOSTIC] =================================="); } private static string GetHierarchyPath(Transform transform) { string text = ((Object)transform).name; Transform parent = transform.parent; while ((Object)(object)parent != (Object)null) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } internal static void LogObjectFsmMap(ManualLogSource log, GameObject gameObject, string description) { if (log == null || (Object)(object)gameObject == (Object)null) { return; } log.LogInfo((object)("[ANTIC DIAGNOSTIC] ===== " + description + " =====")); PlayMakerFSM[] componentsInChildren = gameObject.GetComponentsInChildren(true); foreach (PlayMakerFSM val in componentsInChildren) { log.LogInfo((object)("[ANTIC DIAGNOSTIC] FSM=" + val.FsmName + ", active state=" + val.ActiveStateName)); FsmState[] states = val.Fsm.States; foreach (FsmState val2 in states) { FsmTransition[] transitions = val2.Transitions; foreach (FsmTransition val3 in transitions) { log.LogInfo((object)("[ANTIC DIAGNOSTIC] " + val2.Name + ": '" + val3.EventName + "' -> '" + val3.ToState + "'")); } if (val2.Name == "Explode") { LogStateActionFields(log, val2); } } } log.LogInfo((object)"[ANTIC DIAGNOSTIC] ================================"); } internal static void LogObjectHierarchy(ManualLogSource log, GameObject gameObject, string description) { if (log != null && !((Object)(object)gameObject == (Object)null)) { log.LogInfo((object)("[BOMB DIAGNOSTIC] ===== " + description + " =====")); LogTransform(log, gameObject.transform, string.Empty); log.LogInfo((object)"[BOMB DIAGNOSTIC] ================================"); } } private static void LogTransform(ManualLogSource log, Transform transform, string indent) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown string text = string.Empty; Component[] components = ((Component)transform).GetComponents(); foreach (Component val in components) { if ((Object)(object)val != (Object)null) { text = text + ((text.Length == 0) ? string.Empty : ", ") + ((object)val).GetType().Name; } } log.LogInfo((object)("[BOMB DIAGNOSTIC] " + indent + ((Object)transform).name + " (active=" + ((Component)transform).gameObject.activeSelf + "; local position=" + ((object)transform.localPosition/*cast due to .constrained prefix*/).ToString() + "; local rotation=" + ((object)transform.localEulerAngles/*cast due to .constrained prefix*/).ToString() + "; components=" + text + ")")); foreach (Transform item in transform) { Transform transform2 = item; LogTransform(log, transform2, indent + " "); } } private static void LogStateActionFields(ManualLogSource log, FsmState state) { log.LogInfo((object)"[BOMB DIAGNOSTIC] ----- Explode actions -----"); for (int i = 0; i < state.Actions.Length; i++) { FsmStateAction val = state.Actions[i]; if (val != null) { log.LogInfo((object)("[BOMB DIAGNOSTIC] Action " + i + ": " + ((object)val).GetType().FullName)); FieldInfo[] fields = ((object)val).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { object value = fieldInfo.GetValue(val); log.LogInfo((object)("[BOMB DIAGNOSTIC] " + fieldInfo.Name + " = " + DescribeValue(value))); } } } } private static string DescribeValue(object value) { if (value == null) { return ""; } GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val != (Object)null) { return "GameObject(" + ((Object)val).name + ")"; } FsmGameObject val2 = (FsmGameObject)((value is FsmGameObject) ? value : null); if (val2 != null) { return "FsmGameObject(" + (((Object)(object)val2.Value != (Object)null) ? ((Object)val2.Value).name : "") + ")"; } FsmEvent val3 = (FsmEvent)((value is FsmEvent) ? value : null); if (val3 != null) { return "FsmEvent(" + val3.Name + ")"; } return value.ToString(); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("name.ryanblocker.furioustrobbio", "Furious Trobbio", "1.0.0")] public class FuriousTrobbio : BaseUnityPlugin { private sealed class FuriousTrapdoorSequenceAction : FsmStateAction { public override void OnEnter() { StartTrapdoorSequence((FsmStateAction)(object)this); } } private const string ArenaSceneName = "Library_13"; private const string BossControlFsmName = "Control"; private const string ChoiceStateName = "Choice"; private const string DazzleFlashEventName = "DAZZLE FLASH"; private const string BombThrowEventName = "BOMB THROW"; private const string TornadoEventName = "TORNADO"; private const string NativeBossAdjective = "Tormented"; private const string NativeBossName = "Trobbio"; private const string FuriousBossAdjective = "The Performer's Final Act"; private const string FuriousBossName = "Furious Trobbio"; private const int NativeBossHealth = 950; private const int FuriousBossHealth = 1500; private const int BurstColumnsThresholdActionIndex = 4; private const int FuriousBurstColumnsThreshold = 1100; private const int FuriousSecondPhaseThreshold = 600; private const float ExtraWaveBurstSpacing = 0.15f; private const float MinTrapdoorBurstSpacing = 0.15f; private const float MaxTrapdoorBurstSpacing = 0.35f; private const float WraithfulWaveBurstSpacing = 0.1f; private const float NativeFinalBurstDelay = 1.25f; private const float ComplementaryBombBlastRotation = 45f; private const float ComplementaryBombBlastLifetime = 2f; private static bool inTrobbioFight; private static PlayMakerFSM bossControlFsm; private static PlayMakerFSM runtimeBossControlFsm; private static GameObject crossBlast90; private static GameObject crossBlast45; private static GameObject crossBlastAntic90; private static GameObject crossBlastAntic45; private static bool fireworksArmed; private static bool lastSelectedAttackWasDazzleFlash; private static bool lastSelectedAttackWasTornado; private static int consecutiveBombThrowCount; private static bool fireworksExtensionRunning; private static bool nativeFireworkIsPlus; private static bool extraAnticsPrepared; private static bool healthSetupRunning; private static bool trapdoorSequenceConfigured; private static bool trapdoorSequenceRunning; private static bool trapdoorHealthThresholdConfigured; private static bool secondPhaseTriggered; private static bool tornadoBombSequenceRunning; private static bool tornadoBombsStartedThisAttack; private static bool replaceBossTitleLocalization; private static bool staggerControlDisabled; private static GameObject crossBombPrefab; private static readonly Dictionary ComplementaryBombAntics = new Dictionary(); public static FuriousTrobbio Instance { get; private set; } public ManualLogSource Log => ((BaseUnityPlugin)this).Logger; private void Awake() { Instance = this; Harmony.CreateAndPatchAll(typeof(FuriousTrobbio), (string)null); SceneManager.sceneLoaded += OnSceneLoaded; Log.LogInfo((object)"Furious Trobbio loaded and initialized."); } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { inTrobbioFight = ((Scene)(ref scene)).name == "Library_13"; ResetFightReferences(); if (inTrobbioFight) { Instance.Log.LogInfo((object)"Furious Trobbio: Tormented Trobbio arena loaded."); } } private static void ResetFightReferences() { bossControlFsm = null; runtimeBossControlFsm = null; crossBlast90 = null; crossBlast45 = null; crossBlastAntic90 = null; crossBlastAntic45 = null; fireworksArmed = false; lastSelectedAttackWasDazzleFlash = false; lastSelectedAttackWasTornado = false; consecutiveBombThrowCount = 0; fireworksExtensionRunning = false; nativeFireworkIsPlus = false; extraAnticsPrepared = false; healthSetupRunning = false; trapdoorSequenceConfigured = false; trapdoorSequenceRunning = false; trapdoorHealthThresholdConfigured = false; secondPhaseTriggered = false; tornadoBombSequenceRunning = false; tornadoBombsStartedThisAttack = false; replaceBossTitleLocalization = false; staggerControlDisabled = false; crossBombPrefab = null; ComplementaryBombAntics.Clear(); } [HarmonyPostfix] [HarmonyPatch(typeof(FsmState), "OnEnter")] private static void OnFsmStateEntered(FsmState __instance) { if (!inTrobbioFight) { return; } object obj; if (__instance == null) { obj = null; } else { Fsm fsm = __instance.Fsm; obj = ((fsm != null) ? fsm.FsmComponent : null); } if ((Object)obj == (Object)null) { return; } PlayMakerFSM fsmComponent = __instance.Fsm.FsmComponent; if (fsmComponent.FsmName == "Control" && ((Object)((Component)fsmComponent).gameObject).name == "Tormented Trobbio") { runtimeBossControlFsm = fsmComponent; } AddComplementaryBombBlast(__instance, fsmComponent); AddComplementaryBombAntic(__instance, fsmComponent); if (fsmComponent.FsmName != "Control" || !((Object)((Component)fsmComponent).gameObject).name.Contains("Trobbio")) { return; } CacheBossReferences(fsmComponent); DisableTrobbioStagger(fsmComponent); switch (__instance.Name) { case "Tornado Antic": tornadoBombsStartedThisAttack = false; if (lastSelectedAttackWasTornado) { Instance.Log.LogInfo((object)"Furious Trobbio: blocked a consecutive Tornado at its native entry state."); fsmComponent.SetState("Quick Idle"); } else { lastSelectedAttackWasTornado = true; } break; case "Flash JumpAntic": lastSelectedAttackWasTornado = false; PrepareExtraFireworkAntics(); break; case "Throw Antic": case "Will Burst Column": lastSelectedAttackWasTornado = false; break; case "Flash Burst": ExtendNativeFireworks(__instance); break; case "Tornado": StartFuriousTornadoBombs(fsmComponent); break; } } [HarmonyPrefix] [HarmonyPatch(typeof(DisplayBossTitle), "OnEnter")] private static void ArmTrobbioBossTitleReplacement(DisplayBossTitle __instance) { object obj; if (__instance == null) { obj = null; } else { Fsm fsm = ((FsmStateAction)__instance).Fsm; obj = ((fsm != null) ? fsm.FsmComponent : null); } PlayMakerFSM val = (PlayMakerFSM)obj; if (inTrobbioFight && !((Object)(object)val == (Object)null) && ((Object)((Component)val).gameObject).name.Contains("Trobbio")) { replaceBossTitleLocalization = true; ((MonoBehaviour)Instance).StartCoroutine(EndTrobbioBossTitleReplacementWindow()); } } [HarmonyPostfix] [HarmonyPatch(typeof(Language), "Get", new Type[] { typeof(string), typeof(string) })] private static void ReplaceTrobbioBossTitleLocalization(ref string __result) { if (replaceBossTitleLocalization && !string.IsNullOrEmpty(__result)) { string a = __result.Trim(); if (string.Equals(a, "Tormented", StringComparison.OrdinalIgnoreCase)) { __result = "The Performer's Final Act"; } else if (string.Equals(a, "Trobbio", StringComparison.OrdinalIgnoreCase)) { __result = "Furious Trobbio"; } } } private static IEnumerator EndTrobbioBossTitleReplacementWindow() { yield return (object)new WaitForSeconds(3f); replaceBossTitleLocalization = false; Instance.Log.LogInfo((object)"Furious Trobbio: applied localized two-line boss title replacement window."); } [HarmonyPostfix] [HarmonyPatch(typeof(FullQuestBase), "TryEndQuest")] private static void OpenArenaAfterCompletedQuest(bool __result) { if (inTrobbioFight && __result) { ((MonoBehaviour)Instance).StartCoroutine(OpenTormentedTrobbioArenaGatesAfterQuest()); } } private static IEnumerator OpenTormentedTrobbioArenaGatesAfterQuest() { yield return null; int opened = 0; PlayMakerFSM[] array = Resources.FindObjectsOfTypeAll(); foreach (PlayMakerFSM fsm in array) { int num2; if (!((Object)(object)fsm == (Object)null) && !(fsm.FsmName != "BG Control") && ((Object)((Component)fsm).gameObject).name.StartsWith("Battle Gate", StringComparison.Ordinal)) { Scene scene = ((Component)fsm).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { scene = ((Component)fsm).gameObject.scene; if (!(((Scene)(ref scene)).name != "Library_13")) { num2 = ((!IsInNamedHierarchy(((Component)fsm).transform, "Boss Scene TormentedTrobbio")) ? 1 : 0); goto IL_0108; } } } num2 = 1; goto IL_0108; IL_0108: if (num2 == 0) { fsm.Fsm.Event("BG OPEN"); opened++; } } Instance.Log.LogInfo((object)("Furious Trobbio: sent BG OPEN to " + opened + " Tormented arena gates.")); } private static void DisableTrobbioStagger(PlayMakerFSM controlFsm) { if (!staggerControlDisabled && !((Object)(object)controlFsm == (Object)null) && !(((Object)((Component)controlFsm).gameObject).name != "Tormented Trobbio")) { PlayMakerFSM val = Array.Find(((Component)controlFsm).GetComponents(), (PlayMakerFSM candidate) => candidate.FsmName == "Stun Control"); if (!((Object)(object)val == (Object)null)) { ((Behaviour)val).enabled = false; staggerControlDisabled = true; Instance.Log.LogInfo((object)"Furious Trobbio: disabled the native Stun Control FSM; staggers are removed."); } } } [HarmonyPrefix] [HarmonyPatch(typeof(SetHP), "OnEnter")] private static void ReplaceTrobbioStartingHealth(SetHP __instance) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (__instance == null || __instance.hp == null || __instance.hp.Value != 950) { return; } GameObject safe = FSMUtility.GetSafe(__instance.target, (FsmStateAction)(object)__instance); Fsm fsm = ((FsmStateAction)__instance).Fsm; PlayMakerFSM val = ((fsm != null) ? fsm.FsmComponent : null); Scene val2; int num; if ((Object)(object)safe != (Object)null) { val2 = safe.scene; if (((Scene)(ref val2)).IsValid()) { val2 = safe.scene; num = ((((Scene)(ref val2)).name == "Library_13") ? 1 : 0); goto IL_0086; } } num = 0; goto IL_0086; IL_0086: bool flag = (byte)num != 0; bool flag2 = ((Object)(object)safe != (Object)null && IsTrobbioHierarchy(safe.transform)) || ((Object)(object)val != (Object)null && IsTrobbioHierarchy(((Component)val).transform)); if (!flag) { val2 = SceneManager.GetActiveScene(); if (((Scene)(ref val2)).name != "Library_13") { return; } } if (flag2) { __instance.hp.Value = 1500; Instance.Log.LogInfo((object)("Furious Trobbio: changed native SetHP from " + 950 + " to " + 1500 + " before scene initialization completed.")); } } private static void AddComplementaryBombBlast(FsmState state, PlayMakerFSM fsm) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00c5: Unknown result type (might be due to invalid IL or missing references) if (!(state.Name != "Explode") && !(((Object)((Component)fsm).gameObject).name != "Trobbio Cross Bomb(Clone)")) { DestroyComplementaryBombAntic(((Component)fsm).gameObject); Transform val = ((Component)fsm).transform.Find("Blast"); if ((Object)(object)val == (Object)null) { Instance.Log.LogWarning((object)"Furious Trobbio: Cross Bomb Blast child was not found."); return; } GameObject val2 = Object.Instantiate(((Component)val).gameObject, val.parent); Transform transform = val2.transform; transform.localPosition = val.localPosition; transform.localRotation = val.localRotation * Quaternion.Euler(0f, 0f, 45f); transform.localScale = val.localScale; Object.Destroy((Object)(object)val2, 2f); Instance.Log.LogInfo((object)"Furious Trobbio: added complementary 45-degree Cross Bomb blast."); } } private static void AddComplementaryBombAntic(FsmState state, PlayMakerFSM fsm) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (state.Name != "Antic" || ((Object)((Component)fsm).gameObject).name != "Trobbio Cross Bomb(Clone)") { return; } Transform val = ((Component)fsm).transform.Find("Pt Antic"); if ((Object)(object)val == (Object)null) { Instance.Log.LogWarning((object)"Furious Trobbio: Cross Bomb Pt Antic child was not found."); return; } GameObject val2 = Object.Instantiate(((Component)val).gameObject, val.parent); Transform transform = val2.transform; transform.localPosition = val.localPosition; transform.localRotation = val.localRotation * Quaternion.Euler(0f, 0f, 45f); transform.localScale = val.localScale; val2.SetActive(true); RestartParticleSystems(val2); int instanceID = ((Object)((Component)fsm).gameObject).GetInstanceID(); if (ComplementaryBombAntics.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } ComplementaryBombAntics[instanceID] = val2; ((MonoBehaviour)Instance).StartCoroutine(DestroyComplementaryAnticWithNative(((Component)fsm).gameObject, ((Component)val).gameObject, val2)); Instance.Log.LogInfo((object)"Furious Trobbio: added complementary 45-degree Cross Bomb antic."); } private static IEnumerator DestroyComplementaryAnticWithNative(GameObject bomb, GameObject nativeAntic, GameObject complementaryAntic) { yield return null; while ((Object)(object)nativeAntic != (Object)null && nativeAntic.activeInHierarchy) { yield return null; } if ((Object)(object)complementaryAntic != (Object)null) { Object.Destroy((Object)(object)complementaryAntic); } RemoveTrackedComplementaryAntic(bomb, complementaryAntic); } private static void DestroyComplementaryBombAntic(GameObject bomb) { int instanceID = ((Object)bomb).GetInstanceID(); if (ComplementaryBombAntics.TryGetValue(instanceID, out var value)) { ComplementaryBombAntics.Remove(instanceID); if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } } private static void RemoveTrackedComplementaryAntic(GameObject bomb, GameObject complementaryAntic) { if (!((Object)(object)bomb == (Object)null)) { int instanceID = ((Object)bomb).GetInstanceID(); if (ComplementaryBombAntics.TryGetValue(instanceID, out var value) && (Object)(object)value == (Object)(object)complementaryAntic) { ComplementaryBombAntics.Remove(instanceID); } } } [HarmonyPrefix] [HarmonyPatch(typeof(SendRandomEventV4), "OnEnter")] private static bool OverrideTrobbioMoveSelection(SendRandomEventV4 __instance) { if (!IsTrobbioChoiceAction(__instance)) { return true; } ConfigureTrapdoorHealthThreshold(((FsmStateAction)__instance).Fsm.FsmComponent); if ((Object)(object)crossBombPrefab == (Object)null) { crossBombPrefab = FindCrossBombPrefab(((FsmStateAction)__instance).Fsm.FsmComponent); Instance.Log.LogInfo((object)("Furious Trobbio: runtime Choice Cross Bomb prefab = " + DescribeObject(crossBombPrefab))); } if (TryStartSecondPhase(((FsmStateAction)__instance).Fsm.FsmComponent)) { return false; } string text = ((consecutiveBombThrowCount >= 3) ? (secondPhaseTriggered ? ((Random.value < 0.5f) ? "DAZZLE FLASH" : "TORNADO") : "DAZZLE FLASH") : ((!secondPhaseTriggered) ? (lastSelectedAttackWasDazzleFlash ? "BOMB THROW" : ((Random.value < 0.5f) ? "DAZZLE FLASH" : "BOMB THROW")) : (lastSelectedAttackWasDazzleFlash ? ((Random.value < 0.5f) ? "BOMB THROW" : "TORNADO") : ((!lastSelectedAttackWasTornado) ? (Random.Range(0, 3) switch { 1 => "BOMB THROW", 0 => "DAZZLE FLASH", _ => "TORNADO", }) : ((Random.value < 0.5f) ? "DAZZLE FLASH" : "BOMB THROW"))))); bool flag = (lastSelectedAttackWasDazzleFlash = text == "DAZZLE FLASH"); consecutiveBombThrowCount = ((text == "BOMB THROW") ? (consecutiveBombThrowCount + 1) : 0); fireworksArmed = flag; fireworksExtensionRunning = false; extraAnticsPrepared = false; Instance.Log.LogInfo((object)("Furious Trobbio: replacing Choice random selection with " + text + ".")); ((FsmStateAction)__instance).Fsm.Event(text); return false; } private static bool IsTrobbioChoiceAction(SendRandomEventV4 action) { if (!inTrobbioFight || action == null) { return false; } FsmState state = ((FsmStateAction)action).State; Fsm fsm = ((FsmStateAction)action).Fsm; PlayMakerFSM val = ((fsm != null) ? fsm.FsmComponent : null); bool flag = ((state != null) ? state.Name : null) == "Choice"; bool flag2 = ((val != null) ? val.FsmName : null) == "Control"; bool flag3 = (Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name.Contains("Trobbio"); return flag && flag2 && flag3; } private static void CacheBossReferences(PlayMakerFSM fsm) { if (!((Object)(object)bossControlFsm != (Object)null)) { bossControlFsm = fsm; crossBlast90 = FindChildOrSceneObject(((Component)fsm).transform, "CrossBlast 90"); crossBlast45 = FindChildOrSceneObject(((Component)fsm).transform, "CrossBlast 45"); crossBlastAntic90 = FindChildOrSceneObject(((Component)fsm).transform, "CrossBlast Antic 90"); crossBlastAntic45 = FindChildOrSceneObject(((Component)fsm).transform, "CrossBlast Antic 45"); crossBombPrefab = FindCrossBombPrefab(fsm); if (!healthSetupRunning) { healthSetupRunning = true; ((MonoBehaviour)Instance).StartCoroutine(FindAndReplaceTrobbioHealth()); } ConfigureTrapdoorBurstSequence(); Instance.Log.LogInfo((object)"Furious Trobbio: cached Control FSM and fireworks references."); Instance.Log.LogInfo((object)("Furious Trobbio: CrossBlast 90 = " + DescribeObject(crossBlast90))); Instance.Log.LogInfo((object)("Furious Trobbio: CrossBlast 45 = " + DescribeObject(crossBlast45))); Instance.Log.LogInfo((object)("Furious Trobbio: CrossBlast Antic 90 = " + DescribeObject(crossBlastAntic90))); Instance.Log.LogInfo((object)("Furious Trobbio: CrossBlast Antic 45 = " + DescribeObject(crossBlastAntic45))); Instance.Log.LogInfo((object)("Furious Trobbio: Cross Bomb prefab = " + DescribeObject(crossBombPrefab))); } } private static GameObject FindCrossBombPrefab(PlayMakerFSM controlFsm) { FsmState val = Array.Find(controlFsm.FsmStates, (FsmState state) => state.Name == "Throw"); if (val == null) { return null; } FsmStateAction[] actions = val.Actions; foreach (FsmStateAction val2 in actions) { SpawnObjectFromGlobalPool val3 = (SpawnObjectFromGlobalPool)(object)((val2 is SpawnObjectFromGlobalPool) ? val2 : null); object obj; if (val3 == null) { obj = null; } else { FsmGameObject gameObject = val3.gameObject; obj = ((gameObject != null) ? gameObject.Value : null); } GameObject val4 = (GameObject)obj; if ((Object)(object)val4 != (Object)null && ((Object)val4).name.Contains("Trobbio Cross Bomb")) { return val4; } } return null; } private static bool TryStartSecondPhase(PlayMakerFSM controlFsm) { if (secondPhaseTriggered || (Object)(object)controlFsm == (Object)null) { return false; } HealthManager component = ((Component)controlFsm).GetComponent(); if ((Object)(object)component == (Object)null || component.hp > 600) { return false; } secondPhaseTriggered = true; controlFsm.SetState("Phase Roar Antic"); Instance.Log.LogInfo((object)("Furious Trobbio: started second phase roar at " + component.hp + " HP; Furious Tornado bombs are now enabled.")); return true; } private static void StartFuriousTornadoBombs(PlayMakerFSM controlFsm) { if (secondPhaseTriggered && !tornadoBombSequenceRunning && !tornadoBombsStartedThisAttack) { if ((Object)(object)crossBombPrefab == (Object)null) { Instance.Log.LogWarning((object)"Furious Trobbio: third-phase Tornado began without a cached Cross Bomb prefab."); return; } tornadoBombsStartedThisAttack = true; ((MonoBehaviour)Instance).StartCoroutine(ReleaseTornadoBombs(controlFsm)); } } private static IEnumerator ReleaseTornadoBombs(PlayMakerFSM controlFsm) { tornadoBombSequenceRunning = true; Instance.Log.LogInfo((object)"Furious Trobbio: Furious Tornado will release 3 Cross Bombs."); for (int index = 0; index < 3; index++) { yield return (object)new WaitForSeconds(Random.Range(0.25f, 0.65f)); if ((Object)(object)controlFsm == (Object)null || (controlFsm.ActiveStateName != "Tornado" && controlFsm.ActiveStateName != "Tornado Turn")) { break; } SpawnTornadoCrossBomb(((Component)controlFsm).transform.position); } tornadoBombSequenceRunning = false; } private static void SpawnTornadoCrossBomb(Vector3 position) { //IL_0006: 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) GameObject val = ObjectPoolExtensions.Spawn(crossBombPrefab, position); if ((Object)(object)val == (Object)null) { Instance.Log.LogWarning((object)"Furious Trobbio: failed to obtain a Cross Bomb from the native pool."); return; } float num; do { num = Random.Range(-12f, 12f); } while (Mathf.Abs(num) < 4f); float num2 = Random.Range(6f, 12f); PlayMakerFSM val2 = Array.Find(val.GetComponents(), (PlayMakerFSM candidate) => candidate.FsmName == "Control"); if ((Object)(object)val2 != (Object)null) { val2.FsmVariables.GetFsmFloat("X Velocity").Value = num; } Rigidbody2D component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.linearVelocity = new Vector2(num, num2); } Instance.Log.LogInfo((object)("Furious Trobbio: released whirlwind Cross Bomb with velocity (" + num.ToString("0.0") + ", " + num2.ToString("0.0") + ").")); } private static void ExtendNativeFireworks(FsmState flashBurstState) { if (fireworksArmed && !fireworksExtensionRunning) { GameObject nativeCrossBlast = GetNativeCrossBlast(flashBurstState); if ((Object)(object)nativeCrossBlast == (Object)null) { Instance.Log.LogWarning((object)"Furious Trobbio: could not identify the native CrossBlast; extension aborted."); fireworksArmed = false; } else { RestartCrossBlastParticles(nativeCrossBlast); ((MonoBehaviour)Instance).StartCoroutine(PlayExtraFireworkWaves()); } } } private static void PrepareExtraFireworkAntics() { if (fireworksArmed && !extraAnticsPrepared) { extraAnticsPrepared = true; Instance.Log.LogInfo((object)"Furious Trobbio: starting extra CrossBlast antics during Flash JumpAntic."); Trigger(crossBlastAntic90, "CrossBlast Antic 90"); Trigger(crossBlastAntic45, "CrossBlast Antic 45"); } } private static GameObject GetNativeCrossBlast(FsmState flashBurstState) { FsmStateAction[] actions = flashBurstState.Actions; foreach (FsmStateAction val in actions) { if (!(val is ActivateGameObject)) { continue; } try { object? obj = ((object)val).GetType().GetField("activatedGameObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val); GameObject val2 = (GameObject)((obj is GameObject) ? obj : null); if (((val2 != null) ? ((Object)val2).name : null) == "CrossBlast 90") { nativeFireworkIsPlus = true; return val2; } if (((val2 != null) ? ((Object)val2).name : null) == "CrossBlast 45") { nativeFireworkIsPlus = false; return val2; } } catch (Exception ex) { Instance.Log.LogWarning((object)("Furious Trobbio: failed to inspect Flash Burst action: " + ex.Message)); } } nativeFireworkIsPlus = true; return crossBlast90; } private static IEnumerator PlayExtraFireworkWaves() { fireworksExtensionRunning = true; GameObject secondBurst = (nativeFireworkIsPlus ? crossBlast45 : crossBlast90); GameObject thirdBurst = (nativeFireworkIsPlus ? crossBlast90 : crossBlast45); yield return (object)new WaitForSeconds(0.15f); TriggerCrossBlast(secondBurst, "Wave 2 CrossBlast"); yield return (object)new WaitForSeconds(0.15f); TriggerCrossBlast(thirdBurst, "Wave 3 CrossBlast"); fireworksArmed = false; fireworksExtensionRunning = false; Instance.Log.LogInfo((object)"Furious Trobbio: 3-wave Furious Fireworks sequence complete."); } private static void Trigger(GameObject gameObject, string description) { if ((Object)(object)gameObject == (Object)null) { Instance.Log.LogWarning((object)("Furious Trobbio: " + description + " object is missing.")); return; } gameObject.SetActive(false); gameObject.SetActive(true); } private static void TriggerCrossBlast(GameObject burst, string description) { Trigger(burst, description); RestartCrossBlastParticles(burst); } private static void RestartCrossBlastParticles(GameObject burst) { RestartParticleSystems(burst); } private static void RestartParticleSystems(GameObject effect) { if (!((Object)(object)effect == (Object)null)) { ParticleSystem[] componentsInChildren = effect.GetComponentsInChildren(true); foreach (ParticleSystem val in componentsInChildren) { val.Stop(true, (ParticleSystemStopBehavior)0); val.Play(true); } } } private static IEnumerator FindAndReplaceTrobbioHealth() { bool loggedCandidates = false; for (int frame = 0; frame < 120; frame++) { HealthManager[] array = Resources.FindObjectsOfTypeAll(); foreach (HealthManager healthManager in array) { int num2; if (!((Object)(object)healthManager == (Object)null)) { Scene scene = ((Component)healthManager).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { scene = ((Component)healthManager).gameObject.scene; if (!(((Scene)(ref scene)).name != "Library_13")) { num2 = ((!IsTrobbioHierarchy(((Component)healthManager).transform)) ? 1 : 0); goto IL_00c5; } } } num2 = 1; goto IL_00c5; IL_00c5: if (num2 == 0) { int initialHealth = Traverse.Create((object)healthManager).Field("initHp").GetValue(); if (!loggedCandidates) { Instance.Log.LogInfo((object)("Furious Trobbio [HEALTH]: candidate " + GetHierarchyPath(((Component)healthManager).transform) + ", hp=" + healthManager.hp + ", initHp=" + initialHealth + ".")); } if (healthManager.hp == 950 || initialHealth == 950) { healthManager.hp = 1500; Traverse.Create((object)healthManager).Field("initHp").SetValue((object)1500); Instance.Log.LogInfo((object)("Furious Trobbio: changed actual Trobbio HealthManager from " + 950 + " to " + 1500 + " at " + GetHierarchyPath(((Component)healthManager).transform) + ".")); healthSetupRunning = false; yield break; } } } loggedCandidates = true; yield return null; } healthSetupRunning = false; Instance.Log.LogWarning((object)"Furious Trobbio [HEALTH]: no 950-HP Trobbio HealthManager appeared during startup."); } private static void ConfigureTrapdoorBurstSequence() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (trapdoorSequenceConfigured) { return; } int num = 0; PlayMakerFSM[] array = Resources.FindObjectsOfTypeAll(); foreach (PlayMakerFSM val in array) { if ((Object)(object)val == (Object)null || ((Object)((Component)val).gameObject).name != "Trapdoor Bursts" || val.FsmName != "Control") { continue; } Scene scene = ((Component)val).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).name != "Library_13" || !IsInNamedHierarchy(((Component)val).transform, "Boss Scene TormentedTrobbio")) { continue; } string[] array2 = new string[8] { "L Ptn 1", "L Ptn 2", "R Ptn 1", "R Ptn 2", "M Ptn 1", "M Ptn 2", "Mid L", "Mid R" }; string[] array3 = array2; foreach (string stateName in array3) { FsmState val2 = Array.Find(val.FsmStates, (FsmState candidate) => candidate.Name == stateName); if (val2 == null) { Instance.Log.LogWarning((object)("Furious Trobbio: missing trapdoor pattern state " + stateName + ".")); return; } val2.Actions = (FsmStateAction[])(object)new FsmStateAction[1] { new FuriousTrapdoorSequenceAction() }; } num++; } if (num > 0) { trapdoorSequenceConfigured = true; Instance.Log.LogInfo((object)("Furious Trobbio: configured ten-burst sequence on " + num + " Tormented trapdoor controller(s).")); } } private static void ConfigureTrapdoorHealthThreshold(PlayMakerFSM controlFsm) { if (trapdoorHealthThresholdConfigured || (Object)(object)controlFsm == (Object)null) { return; } FsmState val = Array.Find(controlFsm.FsmStates, (FsmState state) => state.Name == "Choice"); if (val != null && val.Actions.Length > 4) { FsmStateAction obj = val.Actions[4]; CompareHPBool val2 = (CompareHPBool)(object)((obj is CompareHPBool) ? obj : null); if (val2 != null) { int value = val2.compareTo.Value; val2.compareTo.Value = 1100; trapdoorHealthThresholdConfigured = true; Instance.Log.LogInfo((object)("Furious Trobbio: changed Burst Columns health threshold from " + value + " to " + 1100 + ".")); } else { trapdoorHealthThresholdConfigured = true; Instance.Log.LogWarning((object)"Furious Trobbio: Choice action 4 was not a CompareHPBool action."); } } } private static void StartTrapdoorSequence(FsmStateAction action) { if (trapdoorSequenceRunning) { return; } object obj; if (action == null) { obj = null; } else { Fsm fsm = action.Fsm; obj = ((fsm != null) ? fsm.FsmComponent : null); } PlayMakerFSM val = (PlayMakerFSM)obj; if ((Object)(object)val == (Object)null) { Instance.Log.LogWarning((object)"Furious Trobbio: trapdoor controller was unavailable."); return; } string nativeFinalBurstName = GetNativeFinalBurstName(action.State.Name); if (nativeFinalBurstName == null) { Instance.Log.LogWarning((object)("Furious Trobbio: no native final burst mapping for " + action.State.Name + ".")); } else if (secondPhaseTriggered) { ((MonoBehaviour)Instance).StartCoroutine(PlayWraithfulWave(val, nativeFinalBurstName)); } else { ((MonoBehaviour)Instance).StartCoroutine(PlayTenTrapdoorBursts(val, nativeFinalBurstName)); } } private static IEnumerator PlayWraithfulWave(PlayMakerFSM controller, string finalBurstName) { trapdoorSequenceRunning = true; Transform burstContainer = ((Component)controller).transform.Find("Bursts"); if ((Object)(object)burstContainer == (Object)null) { Instance.Log.LogWarning((object)"Furious Trobbio: Wraithful Wave could not find the Bursts container."); trapdoorSequenceRunning = false; yield break; } List sequence = new List(); for (char letter = 'A'; letter <= 'G'; letter = (char)(letter + 1)) { Transform burst = burstContainer.Find("Burst " + letter); if ((Object)(object)burst == (Object)null) { Instance.Log.LogWarning((object)("Furious Trobbio: Wraithful Wave could not find Burst " + letter + ".")); trapdoorSequenceRunning = false; yield break; } sequence.Add(((Component)burst).gameObject); } sequence.Sort((GameObject left, GameObject right) => left.transform.position.x.CompareTo(right.transform.position.x)); int waitFrames = 0; while (((Object)(object)runtimeBossControlFsm == (Object)null || runtimeBossControlFsm.ActiveStateName != "BC Attack") && waitFrames < 120) { waitFrames++; yield return null; } if ((Object)(object)runtimeBossControlFsm == (Object)null || runtimeBossControlFsm.ActiveStateName != "BC Attack") { Instance.Log.LogWarning((object)("Furious Trobbio: Wraithful Wave boss did not reach BC Attack; active state=" + (((Object)(object)runtimeBossControlFsm == (Object)null) ? "MISSING" : runtimeBossControlFsm.ActiveStateName) + ".")); } Transform nativeEmergence = burstContainer.Find(finalBurstName); GameObject emergenceBurst = (((Object)(object)nativeEmergence == (Object)null) ? null : ((Component)nativeEmergence).gameObject); if ((Object)(object)emergenceBurst == (Object)null) { Instance.Log.LogWarning((object)("Furious Trobbio: Wraithful Wave could not resolve native emergence burst " + finalBurstName + ".")); trapdoorSequenceRunning = false; yield break; } int missingPosition; do { missingPosition = Random.Range(0, sequence.Count); } while ((Object)(object)sequence[missingPosition] == (Object)(object)emergenceBurst); GameObject missingBurst = sequence[missingPosition]; sequence.RemoveAt(missingPosition); bool travelsRight = Random.value < 0.5f; if (!travelsRight) { sequence.Reverse(); } int emergenceIndex = sequence.IndexOf(emergenceBurst); int emergenceSlot = emergenceIndex + 1; Instance.Log.LogInfo((object)("Furious Trobbio: Wraithful Wave started " + (travelsRight ? "left-to-right" : "right-to-left") + "; safe gap=" + ((Object)missingBurst).name + ", emergence slot=" + emergenceSlot + ", burst=" + ((Object)sequence[emergenceSlot - 1]).name + ".")); for (int index = 0; index < sequence.Count; index++) { GameObject burst2 = sequence[index]; if (index + 1 == emergenceSlot) { controller.FsmVariables.GetFsmGameObject("Final Burst").Value = burst2; if ((Object)(object)runtimeBossControlFsm != (Object)null && runtimeBossControlFsm.ActiveStateName == "BC Attack") { runtimeBossControlFsm.Fsm.Event("FINAL BURST"); } controller.SetState("Final Burst"); yield return null; if ((Object)(object)runtimeBossControlFsm != (Object)null && runtimeBossControlFsm.ActiveStateName == "BC Attack") { Instance.Log.LogWarning((object)"Furious Trobbio: Wraithful Wave native handoff left boss in BC Attack; sending recovery event."); runtimeBossControlFsm.Fsm.Event("FINAL BURST"); } } else { RestartTrapdoorBurst(burst2); } if (index < sequence.Count - 1) { yield return (object)new WaitForSeconds(0.1f); } } trapdoorSequenceRunning = false; Instance.Log.LogInfo((object)"Furious Trobbio: Wraithful Wave complete."); } private static IEnumerator PlayTenTrapdoorBursts(PlayMakerFSM controller, string finalBurstName) { trapdoorSequenceRunning = true; Transform burstContainer = ((Component)controller).transform.Find("Bursts"); if ((Object)(object)burstContainer == (Object)null) { Instance.Log.LogWarning((object)"Furious Trobbio: trapdoor Bursts container was not found."); trapdoorSequenceRunning = false; yield break; } List firstSeven = new List(); for (char letter = 'A'; letter <= 'G'; letter = (char)(letter + 1)) { Transform burst = burstContainer.Find("Burst " + letter); if ((Object)(object)burst == (Object)null) { Instance.Log.LogWarning((object)("Furious Trobbio: Burst " + letter + " was not found.")); trapdoorSequenceRunning = false; yield break; } firstSeven.Add(((Component)burst).gameObject); } Shuffle(firstSeven); List sequence = new List(firstSeven); List repeats = new List(); for (int index = 0; index < 3; index++) { repeats.Add(firstSeven[index]); } Shuffle(repeats); sequence.AddRange(repeats); int emergenceSlot = Random.Range(6, 9); int emergenceIndex = emergenceSlot - 1; int nativeFinalIndex = sequence.FindIndex((GameObject val) => ((Object)val).name == finalBurstName); GameObject displacedBurst = sequence[emergenceIndex]; sequence[emergenceIndex] = sequence[nativeFinalIndex]; sequence[nativeFinalIndex] = displacedBurst; float[] burstGaps = new float[sequence.Count - 1]; float timeToEmergence; do { timeToEmergence = 0f; for (int index2 = 0; index2 < burstGaps.Length; index2++) { burstGaps[index2] = Random.Range(0.15f, 0.35f); if (index2 < emergenceIndex) { timeToEmergence += burstGaps[index2]; } } } while (timeToEmergence < 1.25f); Instance.Log.LogInfo((object)("Furious Trobbio: " + sequence.Count + "-burst sequence started; emergence slot=" + emergenceSlot + ", burst=" + finalBurstName + ", emergence time=" + timeToEmergence + ".")); for (int index3 = 0; index3 < sequence.Count; index3++) { GameObject burst2 = sequence[index3]; int slot = index3 + 1; if (slot == emergenceSlot) { int waitFrames = 0; while (((Object)(object)runtimeBossControlFsm == (Object)null || runtimeBossControlFsm.ActiveStateName != "BC Attack") && waitFrames < 120) { waitFrames++; yield return null; } if ((Object)(object)runtimeBossControlFsm == (Object)null || runtimeBossControlFsm.ActiveStateName != "BC Attack") { Instance.Log.LogWarning((object)("Furious Trobbio: boss did not reach BC Attack before emergence; active state=" + (((Object)(object)runtimeBossControlFsm == (Object)null) ? "MISSING" : runtimeBossControlFsm.ActiveStateName) + ".")); } controller.FsmVariables.GetFsmGameObject("Final Burst").Value = burst2; if ((Object)(object)runtimeBossControlFsm != (Object)null && runtimeBossControlFsm.ActiveStateName == "BC Attack") { runtimeBossControlFsm.Fsm.Event("FINAL BURST"); } controller.SetState("Final Burst"); yield return null; if ((Object)(object)runtimeBossControlFsm != (Object)null && runtimeBossControlFsm.ActiveStateName == "BC Attack") { Instance.Log.LogWarning((object)"Furious Trobbio: native FINAL BURST handoff did not leave BC Attack; sending recovery event."); runtimeBossControlFsm.Fsm.Event("FINAL BURST"); } } else { RestartTrapdoorBurst(burst2); } if (index3 < sequence.Count - 1) { yield return (object)new WaitForSeconds(burstGaps[index3]); } } trapdoorSequenceRunning = false; Instance.Log.LogInfo((object)("Furious Trobbio: " + sequence.Count + "-burst trapdoor sequence complete.")); } private static string GetNativeFinalBurstName(string patternStateName) { switch (patternStateName) { case "L Ptn 1": case "L Ptn 2": return "Burst C"; case "R Ptn 1": case "R Ptn 2": return "Burst E"; case "M Ptn 1": case "M Ptn 2": return "Burst D"; case "Mid L": return "Burst B"; case "Mid R": return "Burst F"; default: return null; } } private static void RestartTrapdoorBurst(GameObject burst) { burst.SetActive(false); burst.SetActive(true); } private static void Shuffle(IList values) { for (int num = values.Count - 1; num > 0; num--) { int index = Random.Range(0, num + 1); T value = values[num]; values[num] = values[index]; values[index] = value; } } private static string GetHierarchyPath(Transform transform) { string text = ((Object)transform).name; Transform parent = transform.parent; while ((Object)(object)parent != (Object)null) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } private static bool IsTrobbioHierarchy(Transform transform) { Transform val = transform; while ((Object)(object)val != (Object)null) { if (((Object)val).name.Contains("Trobbio")) { return true; } val = val.parent; } return false; } private static bool IsInNamedHierarchy(Transform transform, string name) { Transform val = transform; while ((Object)(object)val != (Object)null) { if (((Object)val).name == name) { return true; } val = val.parent; } return false; } private static GameObject FindSceneObjectExact(string name) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) GameObject[] array = Resources.FindObjectsOfTypeAll(); foreach (GameObject val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name == name) { Scene scene = val.scene; if (((Scene)(ref scene)).IsValid()) { return val; } } } return null; } private static GameObject FindChildOrSceneObject(Transform parent, string name) { GameObject val = FindChildAnyDepth(parent, name); return val ?? FindSceneObjectExact(name); } private static GameObject FindChildAnyDepth(Transform parent, string name) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown foreach (Transform item in parent) { Transform val = item; if (((Object)val).name == name) { return ((Component)val).gameObject; } GameObject val2 = FindChildAnyDepth(val, name); if ((Object)(object)val2 != (Object)null) { return val2; } } return null; } private static string DescribeObject(GameObject gameObject) { return ((Object)(object)gameObject == (Object)null) ? "MISSING" : "FOUND"; } }