Decompiled source of Gabrielings v0.5.8
Gabrielings.dll
Decompiled a day 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.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using Gabrielings.Components; using Gabrielings.Configuration; using Gabrielings.Systems; using Gabrielings.Utilities; using HarmonyLib; using PluginConfig.API; using PluginConfig.API.Decorators; using PluginConfig.API.Fields; using ULTRAKILL.Cheats; using ULTRAKILL.Enemy; using ULTRAKILL.Portal; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Gabrielings")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+1b981e1d24f7faeeb07a02c1e5687e9c81e173dc")] [assembly: AssemblyProduct("Gabrielings")] [assembly: AssemblyTitle("Gabrielings")] [assembly: AssemblyVersion("1.0.0.0")] namespace Gabrielings { [BepInPlugin("grabelings.kiyroprower.ultrakill", "Grabielings", "0.5.8")] [BepInProcess("ULTRAKILL.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string GUID = "grabelings.kiyroprower.ultrakill"; public const string NAME = "Grabielings"; public const string VERSION = "0.5.8"; public const string PLUGIN_CONFIGURATOR_GUID = "com.eternalUnion.pluginConfigurator"; private Harmony _harmony; private bool _quittingHooked; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; GabrielingsConfig.Initialize(((BaseUnityPlugin)this).Logger); PowerSpawnManager.Initialize(); if (!GabrielingsConfig.Enabled) { Log.LogInfo((object)"Gabrielings is disabled in config — patches will stay idle until re-enabled."); } _harmony = new Harmony("grabelings.kiyroprower.ultrakill"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)"Harmony patches applied for Grabielings v0.5.8."); if (!_quittingHooked) { Application.quitting += OnApplicationQuitting; _quittingHooked = true; } PowerSpawnManager.Reset(); LogDebug("Spawn manager reset during plugin awake."); } private void Update() { PowerSpawnManager.Tick(); } public bool Unload() { PowerSpawnManager.Shutdown(); if (_quittingHooked) { Application.quitting -= OnApplicationQuitting; _quittingHooked = false; } if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } Instance = null; Log = null; return true; } private void OnApplicationQuitting() { PowerSpawnManager.Reset(); } public static void LogDebug(string message) { if (GabrielingsConfig.DebugLogging && !string.IsNullOrEmpty(message)) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("[Debug] " + message)); } } } } } namespace Gabrielings.Utilities { public static class EnemyFilter { public static bool IsPlayer(EnemyIdentifier eid) { if ((Object)(object)eid == (Object)null || (Object)(object)((Component)eid).gameObject == (Object)null) { return false; } NewMovement instance = MonoSingleton<NewMovement>.Instance; if ((Object)(object)instance != (Object)null) { return (Object)(object)((Component)instance).gameObject == (Object)(object)((Component)eid).gameObject; } return false; } public static bool IsGabrielPower(EnemyIdentifier eid) { if ((Object)(object)eid == (Object)null) { return false; } GabrielPower gabrielPower = default(GabrielPower); return ((Component)eid).TryGetComponent<GabrielPower>(ref gabrielPower); } public static bool IsArenaTarget(EnemyIdentifier eid) { if ((Object)(object)eid == (Object)null || eid.dead) { return false; } if (IsPlayer(eid)) { return false; } if (IsGabrielPower(eid)) { return false; } if (IsIgnoredSupportEnemy(eid)) { return false; } if (IsDamageImmune(eid)) { return false; } return true; } public static bool IsIgnoredSupportEnemy(EnemyIdentifier eid) { if (!IsIgnoredIdol(eid)) { return IsIgnoredDeathcatcher(eid); } return true; } public static bool IsIgnoredIdol(EnemyIdentifier eid) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 if ((Object)(object)eid == (Object)null) { return false; } if ((int)eid.enemyType != 21) { return (Object)(object)((Component)eid).GetComponent<Idol>() != (Object)null; } return true; } public static bool IsIgnoredDeathcatcher(EnemyIdentifier eid) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 if ((Object)(object)eid == (Object)null) { return false; } if ((int)eid.enemyType != 39) { return (Object)(object)((Component)eid).GetComponent<Deathcatcher>() != (Object)null; } return true; } public static bool IsDamageImmune(EnemyIdentifier eid) { if ((Object)(object)eid == (Object)null) { return true; } if (InvincibleEnemies.Enabled || eid.blessed) { return true; } return eid.totalDamageTakenMultiplier <= 0f; } } public static class PowerPrefabExtractor { private static GameObject _cachedPrefab; public static GameObject ResolvePrefab() { if ((Object)(object)_cachedPrefab != (Object)null) { return _cachedPrefab; } GameObject val = FindInLoadedScenes(); if ((Object)(object)val != (Object)null) { _cachedPrefab = val; return _cachedPrefab; } val = FindInResources(); if ((Object)(object)val != (Object)null) { _cachedPrefab = val; return _cachedPrefab; } val = TryAddressables(); if ((Object)(object)val != (Object)null) { _cachedPrefab = val; return _cachedPrefab; } return null; } public static void Invalidate() { _cachedPrefab = null; } private static GameObject FindInLoadedScenes() { return FindInResources(); } private static GameObject FindInResources() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Power[] array = Resources.FindObjectsOfTypeAll<Power>(); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] == (Object)null) { continue; } GameObject gameObject = ((Component)array[i]).gameObject; if (!((Object)(object)gameObject == (Object)null)) { Scene scene = gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { return gameObject; } } } for (int j = 0; j < array.Length; j++) { if ((Object)(object)array[j] != (Object)null && (Object)(object)((Component)array[j]).gameObject != (Object)null) { return ((Component)array[j]).gameObject; } } return null; } private static GameObject TryAddressables() { //IL_002f: 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) string[] array = new string[4] { "Assets/Prefabs/Enemies/Power.prefab", "Assets/Prefabs/Enemies/Power", "Power", "Enemies/Power" }; for (int i = 0; i < array.Length; i++) { try { AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)array[i]); if (val.IsValid()) { GameObject val2 = val.WaitForCompletion(); if ((Object)(object)val2 != (Object)null) { return val2; } } } catch { } } return null; } } } namespace Gabrielings.Systems { public static class PowerSpawnManager { private static readonly List<GameObject> _alivePowers = new List<GameObject>(8); private static readonly List<GameObject> _managedProjectiles = new List<GameObject>(16); private static readonly List<EnemyIdentifier> _trackedEnemies = new List<EnemyIdentifier>(32); private static readonly Dictionary<EnemyIdentifier, int> _enemyDamageFrames = new Dictionary<EnemyIdentifier, int>(16); private static readonly Dictionary<SwingCheck2, List<EnemyIdentifier>> _managedMeleeHitEnemies = new Dictionary<SwingCheck2, List<EnemyIdentifier>>(16); private static readonly Collider[] EmptyColliders = (Collider[])(object)new Collider[0]; private static readonly MethodInfo PowerBackdashMethod = typeof(Power).GetMethod("Backdash", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null); private static readonly object[] PowerBackdashAnimationArgs = new object[1] { true }; private const float LockedDoorInitialScanDelay = 0.25f; private const float LockedDoorRetryDelay = 0.5f; private const float LockedDoorScanTimeout = 8f; private const float OpenAreaSignalCooldown = 1f; private const float OpenMapTargetMaxPlayerDistance = 55f; private const float WaveSettleDelay = 1.25f; private const float ManagedPowerProjectileOwnerSearchDistance = 18f; private const int EarthmoverMissionNumber = 29; private const float FollowMinDistance = 7f; private const float FollowMaxDistance = 22f; private const float FollowTeleportDistance = 70f; private const float ProvidenceHookDodgeForce = 750f; private const float ProvidenceHookDodgeRayDistance = 7f; private const float ProvidenceHookDodgeRepeatDelay = 0.1f; private const string PowerDodgeAnimationState = "Backdash"; private const float PlayerCollisionRefreshInterval = 0.5f; public const EnemyType ManagedPowerSurrogateType = (EnemyType)37; private static ActivateArena _trackedArena; private static Door _pendingLockedDoor; private static bool _pendingOpenAreaScan; private static float _pendingLockedDoorTimer; private static float _pendingLockedDoorTimeout; private static float _openAreaSignalCooldown; private static float _clearGraceTimer; private static int _remainingEnemySnapshot; private static bool _targetByPlayerProximity; private static bool _initialized; private static int _managedPowerProjectileParryDepth; public static void Initialize() { if (!_initialized) { EnemyTracker.onEnemyAdded = (Action<EnemyIdentifier>)Delegate.Combine(EnemyTracker.onEnemyAdded, new Action<EnemyIdentifier>(HandleEnemyAdded)); StatsManager.checkpointRestart += OnCheckpointRestart; _initialized = true; Plugin.LogDebug("Power spawn manager subscribed to enemy and checkpoint events."); } } public static void Shutdown() { if (_initialized) { EnemyTracker.onEnemyAdded = (Action<EnemyIdentifier>)Delegate.Remove(EnemyTracker.onEnemyAdded, new Action<EnemyIdentifier>(HandleEnemyAdded)); StatsManager.checkpointRestart -= OnCheckpointRestart; _initialized = false; } Reset(); } public static void Reset() { DespawnAll(silent: true); _trackedEnemies.Clear(); _enemyDamageFrames.Clear(); _managedMeleeHitEnemies.Clear(); _trackedArena = null; _pendingLockedDoor = null; _pendingOpenAreaScan = false; _pendingLockedDoorTimer = 0f; _pendingLockedDoorTimeout = 0f; _openAreaSignalCooldown = 0f; _clearGraceTimer = 0f; _remainingEnemySnapshot = 0; _targetByPlayerProximity = false; _managedPowerProjectileParryDepth = 0; } public static void HandleArenaActivated(ActivateArena arena) { if (!GabrielingsConfig.Enabled) { Plugin.LogDebug("Arena activation ignored because the mod is disabled."); return; } if (!CanAssistArena(arena)) { Plugin.LogDebug("Arena activation ignored because it is not a player combat arena."); return; } if ((Object)(object)_trackedArena != (Object)null && (Object)(object)_trackedArena != (Object)(object)arena) { Plugin.LogDebug("New arena activation detected while another arena was tracked; despawning old allies."); DespawnAll(); } else if ((Object)(object)_trackedArena == (Object)null && _alivePowers.Count > 0) { Plugin.LogDebug("New arena activation detected while a fallback assist was active; despawning old allies."); DespawnAll(); } _trackedArena = arena; _pendingLockedDoor = null; _pendingOpenAreaScan = false; _pendingLockedDoorTimer = 0f; _pendingLockedDoorTimeout = 0f; _targetByPlayerProximity = false; _trackedEnemies.Clear(); CollectArenaTargets(arena, _trackedEnemies); _remainingEnemySnapshot = CountRemainingTrackedEnemies(); if (_remainingEnemySnapshot <= 0) { Plugin.LogDebug("Arena has no direct enemy targets; scheduling fallback scan."); Door val = FindFirstDoor(arena); _trackedEnemies.Clear(); _trackedArena = null; if ((Object)(object)val != (Object)null) { ScheduleLockedDoorAssist(val, "arena without direct targets"); } else { ScheduleOpenAreaAssist("arena without direct targets"); } } else { Plugin.LogDebug($"Arena activation accepted with {_remainingEnemySnapshot} tracked enemies."); _clearGraceTimer = 0f; SpawnPowers(GabrielingsConfig.PowerCount); } } public static void HandleDoorLocked(Door door) { if (!GabrielingsConfig.Enabled) { Plugin.LogDebug("Door lock ignored because the mod is disabled."); } else { ScheduleLockedDoorAssist(door, "door lock"); } } public static void HandleBossHealthBar(BossHealthBar bossBar) { if (!GabrielingsConfig.Enabled) { Plugin.LogDebug("Boss assist ignored because the mod is disabled."); return; } if (!GabrielingsConfig.AssistBosses) { Plugin.LogDebug("Boss assist ignored because boss assists are disabled."); return; } if (IsEarthmoverFakeBossBar(bossBar)) { Plugin.LogDebug("Boss assist ignored for 7-4's global Earthmover boss bar."); return; } EnemyIdentifier val = ResolveBossEnemy(bossBar); if (!IsValidAssistTarget(val)) { Plugin.LogDebug("Boss health bar detected, but no valid boss EnemyIdentifier was resolved."); return; } if (!_trackedEnemies.Contains(val)) { _trackedEnemies.Add(val); _remainingEnemySnapshot = CountRemainingTrackedEnemies(); Plugin.LogDebug("Boss target tracked: " + DescribeEnemy(val) + "."); } _pendingLockedDoor = null; _pendingOpenAreaScan = false; _pendingLockedDoorTimer = 0f; _pendingLockedDoorTimeout = 0f; _targetByPlayerProximity = false; if (_alivePowers.Count == 0) { Plugin.LogDebug("Spawning ally Powers for boss encounter."); SpawnPowers(GabrielingsConfig.PowerCount); } } public static void HandleCheckpointActivated(CheckPoint checkpoint) { if (HasActiveState()) { Plugin.LogDebug("Checkpoint activated; clearing active ally Powers and pending scans."); Reset(); } } public static void HandleCheckpointRestart(string source) { if (HasActiveState()) { Plugin.LogDebug("Checkpoint restart from " + source + "; clearing active ally Powers and pending scans."); Reset(); } } public static void HandlePlayerDeath() { if (HasActiveState()) { Plugin.LogDebug("Player death detected; clearing active ally Powers and pending scans."); Reset(); } } public static void NotifyPowerKilledEnemy(EnemyIdentifier enemy) { if (!((Object)(object)enemy == (Object)null) && _trackedEnemies.Contains(enemy)) { _remainingEnemySnapshot = CountRemainingTrackedEnemies(); Plugin.LogDebug($"Tracked enemy died; {_remainingEnemySnapshot} enemies remain."); if (_remainingEnemySnapshot <= 0) { StartClearGrace("tracked enemy death"); } } } public static void HandleEnemyTargetUpdated(EnemyIdentifier eid) { if (!GabrielingsConfig.Enabled || (Object)(object)eid == (Object)null) { return; } if (_alivePowers.Count > 0 || _trackedEnemies.Count > 0) { if (IsOpenAreaCombatTarget(eid)) { AddWaveTarget(eid); } } else if (GabrielingsConfig.ExtendedEnemyCheck && !((Object)(object)_pendingLockedDoor != (Object)null) && !_pendingOpenAreaScan && !(_openAreaSignalCooldown > 0f) && IsOpenAreaCombatTarget(eid)) { _openAreaSignalCooldown = 1f; ScheduleOpenAreaAssist("open-map combat target " + DescribeEnemy(eid)); } } public static void ConfigureManagedPowerProjectile(Projectile projectile) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown if ((Object)(object)projectile == (Object)null || (int)projectile.safeEnemyType != 40 || projectile.friendly || projectile.playerBullet) { return; } GabrielPower gabrielPower = FindNearestManagedPower(((Component)projectile).transform.position, 18f); if ((Object)(object)gabrielPower == (Object)null) { return; } GabrielPowerProjectile gabrielPowerProjectile = ((Component)projectile).GetComponent<GabrielPowerProjectile>(); if ((Object)(object)gabrielPowerProjectile == (Object)null) { gabrielPowerProjectile = ((Component)projectile).gameObject.AddComponent<GabrielPowerProjectile>(); } gabrielPowerProjectile.Owner = gabrielPower; gabrielPowerProjectile.OriginalSafeEnemyType = projectile.safeEnemyType; projectile.sourceWeapon = ((Component)gabrielPower).gameObject; TrackManagedProjectile(projectile); EnemyIdentifier val = SelectPowerTarget(((Component)projectile).transform.position, gabrielPower.CurrentTarget); if (!IsValidActiveTarget(val)) { gabrielPowerProjectile.Target = null; projectile.targetHandle = null; projectile.isTargetPlayer = false; projectile.target = null; DestroyManagedProjectile(projectile); Plugin.LogDebug("Managed Power projectile was despawned because no active enemy target was available."); return; } gabrielPowerProjectile.Target = val; TargetHandle val2 = CreateTargetHandle(val); if (val2 != (TargetHandle)null) { projectile.targetHandle = val2; } projectile.isTargetPlayer = false; projectile.target = new EnemyTarget(val); Plugin.LogDebug("Configured managed Power projectile target: " + DescribeEnemy(val) + "."); } public static void PrepareManagedPowerProjectileHit(Projectile projectile, Collider other) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)projectile == (Object)null || (Object)(object)other == (Object)null || (int)projectile.safeEnemyType != 40) { return; } GabrielPowerProjectile component = ((Component)projectile).GetComponent<GabrielPowerProjectile>(); EnemyIdentifier val = (((Object)(object)component == (Object)null) ? null : component.Target); if (!IsManagedPowerTarget(val)) { return; } EnemyIdentifier val2 = ResolveColliderEnemy(other); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 != (Object)(object)val) && val2.enemyType == projectile.safeEnemyType) { projectile.safeEnemyType = (EnemyType)37; TargetHandle val3 = CreateTargetHandle(val2); if (val3 != (TargetHandle)null) { projectile.targetHandle = val3; } Plugin.LogDebug("Prepared managed Power projectile friendly-fire bypass for " + DescribeEnemy(val2) + "."); } } public static bool ShouldSkipManagedPowerProjectileCollision(Projectile projectile, Collider other) { if ((Object)(object)projectile == (Object)null || (Object)(object)other == (Object)null) { return false; } GameObject gameObject = ((Component)other).gameObject; if ((Object)(object)gameObject == (Object)null) { return false; } GabrielPowerProjectile component = ((Component)projectile).GetComponent<GabrielPowerProjectile>(); if ((Object)(object)component != (Object)null && IsPlayerCollider(other)) { Plugin.LogDebug("Skipped managed Power projectile collision with the player."); return true; } if ((Object)(object)component != (Object)null && (Object)(object)ResolveManagedPowerMarker(ResolveColliderEnemy(other), gameObject) != (Object)null) { Plugin.LogDebug("Skipped managed Power projectile collision with another managed Power."); return true; } if (IsPlayerOwnedProjectile(projectile) && (Object)(object)ResolveManagedPowerMarker(ResolveColliderEnemy(other), gameObject) != (Object)null) { Plugin.LogDebug("Skipped player projectile collision with a managed Power."); return true; } return false; } public static bool ShouldSkipManagedPowerExplosionCollision(Explosion explosion, Collider other) { if ((Object)(object)explosion == (Object)null || (Object)(object)other == (Object)null || !IsPlayerCollider(other)) { return false; } if (!IsManagedPowerExplosion(explosion)) { return false; } Plugin.LogDebug("Skipped managed Power projectile explosion collision with the player."); return true; } public static void MarkEnemyProjectileDamageToManagedPower(Projectile projectile, Collider other) { if (!((Object)(object)projectile == (Object)null) && !((Object)(object)other == (Object)null) && !projectile.friendly && !projectile.playerBullet && !((Object)(object)((Component)projectile).GetComponent<GabrielPowerProjectile>() != (Object)null)) { EnemyIdentifier val = ResolveColliderEnemy(other); if (!((Object)(object)ResolveManagedPowerMarker(val, ((Object)(object)val == (Object)null) ? null : ((Component)val).gameObject) == (Object)null)) { MarkEnemyDamageToManagedPower(val); } } } public static void MarkEnemyMeleeDamageToManagedPower(EnemyIdentifier receiver, EnemyIdentifier attacker) { if (!((Object)(object)receiver == (Object)null) && !((Object)(object)attacker == (Object)null) && !((Object)(object)ResolveManagedPowerMarker(receiver, ((Component)receiver).gameObject) == (Object)null) && !EnemyFilter.IsPlayer(attacker) && !EnemyFilter.IsGabrielPower(attacker)) { MarkEnemyDamageToManagedPower(receiver); } } public static bool ShouldSkipManagedPowerMeleeCollision(SwingCheck2 swingCheck, Collider other) { if ((Object)(object)swingCheck == (Object)null || (Object)(object)other == (Object)null) { return false; } if (!IsManagedPowerSwing(swingCheck)) { return false; } if (!IsPlayerCollider(other)) { if ((Object)(object)ResolveManagedPowerMarker(ResolveColliderEnemy(other), ((Component)other).gameObject) == (Object)null) { return false; } Plugin.LogDebug("Skipped managed Power melee collision with another managed Power."); return true; } Plugin.LogDebug("Skipped managed Power melee collision with the player."); return true; } public static bool ShouldSkipManagedPowerMeleeEnemyCollision(SwingCheck2 swingCheck, EnemyIdentifier receiver) { if ((Object)(object)swingCheck == (Object)null || (Object)(object)receiver == (Object)null) { return false; } if (!IsManagedPowerSwing(swingCheck)) { return false; } if ((Object)(object)ResolveManagedPowerMarker(receiver, ((Component)receiver).gameObject) == (Object)null) { return false; } Plugin.LogDebug("Skipped managed Power melee damage to another managed Power."); return true; } public static bool ShouldBlockManagedPowerDamage(EnemyIdentifier receiver, GameObject target, GameObject sourceWeapon) { if ((Object)(object)ResolveManagedPowerMarker(receiver, target) == (Object)null) { return false; } if (IsHookDamageToManagedPower(receiver)) { HandleManagedPowerHooked(ResolveHookArm(), receiver); return true; } if (!IsEnemyDamageToManagedPower(receiver, sourceWeapon)) { Plugin.LogDebug("Blocked player/non-enemy damage against a managed Power."); return true; } return GabrielingsConfig.Immortal; } public static void HandleManagedPowerHooked(HookArm hookArm, EnemyIdentifier caughtEnemy) { if ((Object)(object)caughtEnemy == (Object)null) { return; } GabrielPower component = ((Component)caughtEnemy).GetComponent<GabrielPower>(); if (!((Object)(object)component == (Object)null)) { caughtEnemy.hitter = string.Empty; caughtEnemy.hookIgnore = false; caughtEnemy.hooked = false; if ((Object)(object)hookArm != (Object)null) { hookArm.StopThrow(1f, true); } PlayManagedPowerDodgeAnimation(component); ApplyProvidenceHookDodge(component); if (ShouldRepeatProvidenceHookDodge(caughtEnemy) && ((Behaviour)component).isActiveAndEnabled) { ((MonoBehaviour)component).StartCoroutine(DelayedProvidenceHookDodge(component)); } Plugin.LogDebug("Managed Power used Providence-style hook dodge."); } } public static bool BeginManagedPowerProjectileParry(Projectile projectile) { if ((Object)(object)projectile == (Object)null || (Object)(object)((Component)projectile).GetComponent<GabrielPowerProjectile>() == (Object)null) { return false; } _managedPowerProjectileParryDepth++; return true; } public static void EndManagedPowerProjectileParry() { if (_managedPowerProjectileParryDepth > 0) { _managedPowerProjectileParryDepth--; } } public static bool ShouldSuppressManagedPowerProjectileParryHealing(int health, bool silent) { if (_managedPowerProjectileParryDepth > 0 && !silent) { return health >= 999; } return false; } public static bool ShouldMuteManagedPowerVoice(Power power) { if (GabrielingsConfig.MutePowerVoices) { return IsManagedPower(power); } return false; } public static bool ShouldBlockManagedPowerPortalTravel(Enemy enemy) { //IL_0032: 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) if ((Object)(object)enemy == (Object)null || (Object)(object)((Component)enemy).GetComponent<GabrielPower>() == (Object)null) { return false; } Rigidbody component = ((Component)enemy).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null && !component.isKinematic) { component.velocity = Vector3.zero; component.angularVelocity = Vector3.zero; } Plugin.LogDebug("Blocked managed Power portal traversal."); return true; } public static void Tick() { if (!GabrielingsConfig.Enabled) { Reset(); return; } if (_openAreaSignalCooldown > 0f) { _openAreaSignalCooldown -= Time.deltaTime; } ProcessPendingLockedDoorAssist(); if (_alivePowers.Count == 0) { PruneManagedProjectiles(); PruneEnemyDamageFrames(); return; } HandleRepositionHotkey(); PruneEnemyDamageFrames(); PruneTrackedTargetsOutsidePlayerRange(); ApplyCurrentPowerSettings(); UpdateIdlePlayerFollowing(); int num = CountRemainingTrackedEnemies(); if (num != _remainingEnemySnapshot) { _remainingEnemySnapshot = num; Plugin.LogDebug($"Tracked enemy count changed; {num} enemies remain."); } if (num <= 0) { DespawnManagedProjectiles(silent: false); if (!WaitForWaveContinuation()) { FinishAssist(); } } } public static void DespawnAll() { DespawnAll(silent: false); } private static void DespawnAll(bool silent) { int num = 0; for (int i = 0; i < _alivePowers.Count; i++) { GameObject val = _alivePowers[i]; if ((Object)(object)val != (Object)null) { CancelManagedPowerMusicRequest(val); Object.Destroy((Object)(object)val); num++; } } _alivePowers.Clear(); DespawnManagedProjectiles(silent); if (!silent && num > 0) { Plugin.LogDebug($"Despawned {num} ally Powers."); } } private static bool CanAssistArena(ActivateArena arena) { if ((Object)(object)arena == (Object)null || arena.activated || arena.forEnemy) { return false; } if (HasConfiguredEnemies(arena)) { return true; } return HasDoor(arena); } private static bool HasDoor(ActivateArena arena) { Door[] doors = arena.doors; if (doors == null || doors.Length == 0) { return false; } bool flag = false; for (int i = 0; i < doors.Length; i++) { if ((Object)(object)doors[i] != (Object)null) { flag = true; break; } } if (!flag) { return false; } return true; } private static bool HasActiveState() { if (_alivePowers.Count <= 0 && _trackedEnemies.Count <= 0 && !((Object)(object)_pendingLockedDoor != (Object)null)) { return _pendingOpenAreaScan; } return true; } private static bool HasConfiguredEnemies(ActivateArena arena) { GameObject[] enemies = arena.enemies; if (enemies == null || enemies.Length == 0) { return false; } for (int i = 0; i < enemies.Length; i++) { if ((Object)(object)enemies[i] != (Object)null) { return true; } } return false; } private static void ScheduleLockedDoorAssist(Door door, string reason) { if ((Object)(object)door == (Object)null) { Plugin.LogDebug("Locked-door assist was not scheduled from " + reason + ": door is null."); return; } if (_alivePowers.Count > 0 || _trackedEnemies.Count > 0) { Plugin.LogDebug("Locked-door assist from " + reason + " ignored because an assist is already active."); return; } if ((Object)(object)_pendingLockedDoor != (Object)null || _pendingOpenAreaScan) { Plugin.LogDebug("Locked-door assist from " + reason + " ignored because a door scan is already pending."); return; } _pendingLockedDoor = door; _pendingOpenAreaScan = false; _pendingLockedDoorTimer = 0.25f; _pendingLockedDoorTimeout = 8f; Plugin.LogDebug($"Locked-door assist scheduled from {reason}; scanning for enemies for up to {8f:0.0}s."); } private static void ScheduleOpenAreaAssist(string reason) { if (!GabrielingsConfig.ExtendedEnemyCheck) { Plugin.LogDebug("Extended enemy check from " + reason + " ignored because fallback scans are disabled."); return; } if (_alivePowers.Count > 0 || _trackedEnemies.Count > 0) { Plugin.LogDebug("Open-area assist from " + reason + " ignored because an assist is already active."); return; } if ((Object)(object)_pendingLockedDoor != (Object)null || _pendingOpenAreaScan) { Plugin.LogDebug("Open-area assist from " + reason + " ignored because a scan is already pending."); return; } _pendingLockedDoor = null; _pendingOpenAreaScan = true; _pendingLockedDoorTimer = 0.25f; _pendingLockedDoorTimeout = 8f; Plugin.LogDebug($"Extended enemy check scheduled from {reason}; scanning for enemies for up to {8f:0.0}s."); } private static void ProcessPendingLockedDoorAssist() { if ((Object)(object)_pendingLockedDoor == (Object)null && !_pendingOpenAreaScan) { return; } _pendingLockedDoorTimeout -= Time.deltaTime; if (_pendingLockedDoorTimeout <= 0f) { Plugin.LogDebug("Fallback scan timed out without finding active enemies."); ClearPendingLockedDoorAssist(); return; } _pendingLockedDoorTimer -= Time.deltaTime; if (!(_pendingLockedDoorTimer > 0f)) { if ((Object)(object)_pendingLockedDoor != (Object)null && !_pendingLockedDoor.locked) { Plugin.LogDebug("Locked-door fallback scan skipped because the door is no longer locked."); ClearPendingLockedDoorAssist(); } else if (!TryStartAssistFromCurrentEnemies("locked-door fallback scan")) { _pendingLockedDoorTimer = 0.5f; Plugin.LogDebug($"Fallback scan found no active enemies; retrying for {_pendingLockedDoorTimeout:0.0}s."); } } } private static void ClearPendingLockedDoorAssist() { _pendingLockedDoor = null; _pendingOpenAreaScan = false; _pendingLockedDoorTimer = 0f; _pendingLockedDoorTimeout = 0f; } private static bool TryStartAssistFromCurrentEnemies(string reason) { bool pendingOpenAreaScan = _pendingOpenAreaScan; _trackedArena = null; _trackedEnemies.Clear(); CollectCurrentEnemyTargets(_trackedEnemies, _pendingOpenAreaScan); _remainingEnemySnapshot = CountRemainingTrackedEnemies(); if (_remainingEnemySnapshot <= 0) { _trackedEnemies.Clear(); return false; } ClearPendingLockedDoorAssist(); _targetByPlayerProximity = pendingOpenAreaScan; Plugin.LogDebug($"{reason} accepted with {_remainingEnemySnapshot} tracked active enemies."); _clearGraceTimer = 0f; SpawnPowers(GabrielingsConfig.PowerCount); return true; } private static Door FindFirstDoor(ActivateArena arena) { if ((Object)(object)arena == (Object)null || arena.doors == null) { return null; } Door[] doors = arena.doors; for (int i = 0; i < doors.Length; i++) { if ((Object)(object)doors[i] != (Object)null) { return doors[i]; } } return null; } private static void CollectArenaTargets(ActivateArena arena, List<EnemyIdentifier> targets) { targets.Clear(); GameObject[] enemies = arena.enemies; if (enemies == null || enemies.Length == 0) { return; } foreach (GameObject val in enemies) { if (!((Object)(object)val == (Object)null)) { EnemyIdentifier val2 = val.GetComponent<EnemyIdentifier>(); if ((Object)(object)val2 == (Object)null) { val2 = val.GetComponentInChildren<EnemyIdentifier>(true); } if (IsValidAssistTarget(val2) && !targets.Contains(val2)) { targets.Add(val2); } } } } private static void CollectCurrentEnemyTargets(List<EnemyIdentifier> targets, bool requireCombatSignal) { targets.Clear(); List<EnemyIdentifier> list = null; try { EnemyTracker instance = MonoSingleton<EnemyTracker>.Instance; if ((Object)(object)instance != (Object)null) { list = instance.GetCurrentEnemies(); } } catch { list = null; } if (list != null && list.Count > 0) { for (int i = 0; i < list.Count; i++) { AddCurrentTarget(list[i], targets, requireCombatSignal); } if (targets.Count > 0) { Plugin.LogDebug($"EnemyTracker provided {targets.Count} valid active targets."); return; } } EnemyIdentifier[] array = Resources.FindObjectsOfTypeAll<EnemyIdentifier>(); for (int j = 0; j < array.Length; j++) { AddCurrentTarget(array[j], targets, requireCombatSignal); } Plugin.LogDebug($"Resource scan provided {targets.Count} valid active targets."); } private static void AddCurrentTarget(EnemyIdentifier eid, List<EnemyIdentifier> targets, bool requireCombatSignal) { if (IsValidAssistTarget(eid) && !targets.Contains(eid)) { GameObject gameObject = ((Component)eid).gameObject; if (!((Object)(object)gameObject == (Object)null) && gameObject.activeInHierarchy && (!requireCombatSignal || IsOpenAreaCombatTarget(eid))) { targets.Add(eid); } } } private static bool IsOpenAreaCombatTarget(EnemyIdentifier eid) { if (!IsValidActiveTarget(eid)) { return false; } if (eid.target != null && eid.target.isPlayer) { return IsTargetCloseToPlayer(eid); } return false; } private static bool IsValidActiveTarget(EnemyIdentifier eid) { if (!IsValidAssistTarget(eid)) { return false; } GameObject gameObject = ((Component)eid).gameObject; if ((Object)(object)gameObject != (Object)null) { return gameObject.activeInHierarchy; } return false; } private static bool IsValidAssistTarget(EnemyIdentifier eid) { if (!EnemyFilter.IsArenaTarget(eid)) { return false; } if (!GabrielingsConfig.AssistBosses && IsBossTarget(eid)) { return false; } return true; } private static bool IsBossTarget(EnemyIdentifier eid) { if ((Object)(object)eid == (Object)null) { return false; } if (eid.isBoss) { return true; } if (!((Object)(object)((Component)eid).GetComponent<BossHealthBar>() != (Object)null)) { return (Object)(object)((Component)eid).GetComponent<BossIdentifier>() != (Object)null; } return true; } private static bool IsEarthmoverFakeBossBar(BossHealthBar bossBar) { if ((Object)(object)bossBar == (Object)null) { return false; } if (IsEarthmoverLevel()) { return true; } if (ContainsEarthmoverText(bossBar.bossName) || ContainsEarthmoverText(((Object)((Component)bossBar).gameObject).name)) { return true; } IEnemyHealthDetails source = bossBar.source; if (source != null && ContainsEarthmoverText(source.FullName)) { return true; } Transform val = ((Component)bossBar).transform; while ((Object)(object)val != (Object)null) { if (ContainsEarthmoverText(((Object)val).name)) { return true; } val = val.parent; } return false; } private static bool IsEarthmoverLevel() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) try { StatsManager instance = MonoSingleton<StatsManager>.Instance; if ((Object)(object)instance != (Object)null && instance.levelNumber == 29) { return true; } } catch { } try { if (SceneHelper.CurrentLevelNumber == 29) { return true; } } catch { } if (ContainsEarthmoverText(SceneHelper.CurrentScene)) { return true; } try { Scene activeScene = SceneManager.GetActiveScene(); return ContainsEarthmoverText(((Scene)(ref activeScene)).name); } catch { return false; } } private static bool ContainsEarthmoverText(string value) { if (string.IsNullOrEmpty(value)) { return false; } if (value.IndexOf("7-4", StringComparison.OrdinalIgnoreCase) < 0 && value.IndexOf("Earthmover", StringComparison.OrdinalIgnoreCase) < 0 && value.IndexOf("Earth Mover", StringComparison.OrdinalIgnoreCase) < 0) { return value.IndexOf("1000-THR", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static EnemyIdentifier ResolveBossEnemy(BossHealthBar bossBar) { if ((Object)(object)bossBar == (Object)null) { return null; } EnemyIdentifier component = ((Component)bossBar).GetComponent<EnemyIdentifier>(); if ((Object)(object)component != (Object)null) { return component; } IEnemyHealthDetails source = bossBar.source; EnemyIdentifier val = (EnemyIdentifier)(object)((source is EnemyIdentifier) ? source : null); if (val != null) { return val; } component = ((Component)bossBar).GetComponentInParent<EnemyIdentifier>(); if ((Object)(object)component != (Object)null) { return component; } return ((Component)bossBar).GetComponentInChildren<EnemyIdentifier>(true); } private static string DescribeEnemy(EnemyIdentifier eid) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)eid == (Object)null) { return "<null>"; } GameObject gameObject = ((Component)eid).gameObject; string arg = (((Object)(object)gameObject == (Object)null) ? "<no GameObject>" : ((Object)gameObject).name); return $"{arg} ({eid.enemyType})"; } private static void SpawnPowers(int count) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_0087: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ResolveSpawnOrigin(_trackedArena); GameObject val2 = PowerPrefabExtractor.ResolvePrefab(); if ((Object)(object)val2 == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"Gabrielings: Power prefab could not be resolved."); } _trackedEnemies.Clear(); _trackedArena = null; return; } count = Mathf.Clamp(count, 1, 100); int num = 0; Vector3 val3 = default(Vector3); for (int i = 0; i < count; i++) { ((Vector3)(ref val3))..ctor(Random.Range(-1.5f, 1.5f), 0f, Random.Range(-1.5f, 1.5f)); GameObject val4; try { val4 = Object.Instantiate<GameObject>(val2, val + val3, Quaternion.identity); } catch (Exception ex) { Plugin.LogDebug("Power instantiate failed: " + ex.GetType().Name + ": " + ex.Message); continue; } if (!((Object)(object)val4 == (Object)null)) { ConfigureSpawnedPower(val4, num); _alivePowers.Add(val4); num++; } } if (num <= 0) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"Gabrielings: Power prefab resolved, but no Powers could be spawned."); } _trackedEnemies.Clear(); _trackedArena = null; } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"Gabrielings: spawned {num} Powers."); } } } private static void ConfigureSpawnedPower(GameObject go, int followIndex) { GabrielPower gabrielPower = go.GetComponent<GabrielPower>(); if ((Object)(object)gabrielPower == (Object)null) { gabrielPower = go.AddComponent<GabrielPower>(); } gabrielPower.EnemyIdentifier = go.GetComponent<EnemyIdentifier>(); gabrielPower.Power = go.GetComponent<Power>(); gabrielPower.VoiceAudio = go.GetComponent<AudioSource>(); gabrielPower.Animator = go.GetComponent<Animator>(); gabrielPower.FollowIndex = followIndex; gabrielPower.FollowPhase = Random.Range(0f, (float)Math.PI * 2f); if ((Object)(object)gabrielPower.EnemyIdentifier != (Object)null) { gabrielPower.BaseHealth = gabrielPower.EnemyIdentifier.health; } EnemyIdentifier enemyIdentifier = gabrielPower.EnemyIdentifier; if ((Object)(object)enemyIdentifier != (Object)null) { enemyIdentifier.ignorePlayer = true; enemyIdentifier.attackEnemies = true; enemyIdentifier.immuneToFriendlyFire = false; enemyIdentifier.hookIgnore = false; enemyIdentifier.prioritizePlayerOverFallback = false; enemyIdentifier.prioritizeEnemiesUnlessAttacked = false; enemyIdentifier.ResetTarget(); enemyIdentifier.blessed = false; if (GabrielingsConfig.Immortal) { enemyIdentifier.health = float.MaxValue; } Enemy component = go.GetComponent<Enemy>(); if ((Object)(object)component != (Object)null && component.vision != null) { component.SyncVision(); } RefreshPowerCombatTarget(gabrielPower, enemyIdentifier); } RefreshManagedPowerPlayerCollision(gabrielPower, force: true); if ((Object)(object)gabrielPower.Power != (Object)null) { gabrielPower.Power.aggroBounds = null; } DetachFromPowerCooldowns(gabrielPower.Power); if (!go.activeSelf) { go.SetActive(true); } ApplyManagedPowerAudioSettings(gabrielPower); CancelManagedPowerMusicRequest(gabrielPower, decrementMusicRequest: false); RemoveManagedPowerPortalTraveller(gabrielPower); } private static void ConfigureSwingChecks(GameObject go, EnemyIdentifier eid, EnemyIdentifier target) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) SwingCheck2[] componentsInChildren = go.GetComponentsInChildren<SwingCheck2>(true); EnemyType type = ResolveMeleeAttackerType(eid, target); int num = ((!IsFleshBossTarget(target)) ? 1 : 4); foreach (SwingCheck2 val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { val.OverrideEnemyIdentifier(eid); val.type = type; if (val.enemyDamage <= 0 && val.damage > 0) { val.enemyDamage = Mathf.Max(num, val.damage / 10); } else if (val.enemyDamage > 0 && val.enemyDamage < num) { val.enemyDamage = num; } } } Plugin.LogDebug($"Configured {componentsInChildren.Length} Power melee hitboxes."); } private static EnemyType ResolveMeleeAttackerType(EnemyIdentifier owner, EnemyIdentifier target) { if (!((Object)(object)owner != (Object)null)) { return (EnemyType)40; } return (EnemyType)37; } private static Vector3 ResolveSpawnOrigin(ActivateArena arena) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) NewMovement instance = MonoSingleton<NewMovement>.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)((Component)instance).transform != (Object)null) { return ((Component)instance).transform.position + Vector3.up * 1.5f; } if ((Object)(object)arena == (Object)null || (Object)(object)((Component)arena).transform == (Object)null) { return Vector3.zero; } return ((Component)arena).transform.position + Vector3.up * 1.5f; } private static void ApplyCurrentPowerSettings() { bool immortal = GabrielingsConfig.Immortal; for (int num = _alivePowers.Count - 1; num >= 0; num--) { GameObject val = _alivePowers[num]; if ((Object)(object)val == (Object)null) { _alivePowers.RemoveAt(num); } else { GabrielPower component = val.GetComponent<GabrielPower>(); if (!((Object)(object)component == (Object)null)) { EnemyIdentifier val2 = (((Object)(object)component.EnemyIdentifier != (Object)null) ? component.EnemyIdentifier : val.GetComponent<EnemyIdentifier>()); if (!((Object)(object)val2 == (Object)null)) { component.EnemyIdentifier = val2; if ((Object)(object)component.Power == (Object)null) { component.Power = val.GetComponent<Power>(); } if ((Object)(object)component.Animator == (Object)null) { component.Animator = val.GetComponent<Animator>(); } val2.ignorePlayer = true; val2.attackEnemies = true; val2.immuneToFriendlyFire = false; val2.hookIgnore = false; val2.prioritizePlayerOverFallback = false; val2.prioritizeEnemiesUnlessAttacked = false; DetachFromPowerCooldowns(component.Power); RefreshPowerCombatTarget(component, val2); RefreshManagedPowerPlayerCollision(component, force: false); ApplyManagedPowerAudioSettings(component); CancelManagedPowerMusicRequest(component); RemoveManagedPowerPortalTraveller(component); val2.blessed = false; if (immortal) { val2.health = float.MaxValue; } else if (component.BaseHealth > 0f && val2.health > component.BaseHealth) { val2.health = component.BaseHealth; } } } } } } private static void ApplyManagedPowerAudioSettings(GabrielPower marker) { if (!((Object)(object)marker == (Object)null) && GabrielingsConfig.MutePowerVoices) { if ((Object)(object)marker.VoiceAudio == (Object)null) { marker.VoiceAudio = ((Component)marker).GetComponent<AudioSource>(); } if ((Object)(object)marker.VoiceAudio != (Object)null && marker.VoiceAudio.isPlaying) { marker.VoiceAudio.Stop(); } } } private static void CancelManagedPowerMusicRequest(GameObject go, bool decrementMusicRequest = true) { if (!((Object)(object)go == (Object)null)) { CancelManagedPowerMusicRequest(go.GetComponent<GabrielPower>(), decrementMusicRequest); } } private static void CancelManagedPowerMusicRequest(GabrielPower marker, bool decrementMusicRequest = true) { if ((Object)(object)marker == (Object)null || (Object)(object)((Component)marker).gameObject == (Object)null) { return; } Enemy component = ((Component)marker).GetComponent<Enemy>(); if ((Object)(object)component == (Object)null || !component.musicRequested) { return; } component.musicRequested = false; if (decrementMusicRequest) { try { MusicManager val = default(MusicManager); if (MonoSingleton<MusicManager>.TryGetInstance(ref val) && (Object)(object)val != (Object)null) { val.PlayCleanMusic(); } } catch { } } Plugin.LogDebug("Cancelled managed Power combat music request."); } private static void RemoveManagedPowerPortalTraveller(GabrielPower marker) { if ((Object)(object)marker == (Object)null || (Object)(object)((Component)marker).gameObject == (Object)null) { return; } Enemy component = ((Component)marker).GetComponent<Enemy>(); if ((Object)(object)component == (Object)null) { return; } try { PortalManagerV2 val = default(PortalManagerV2); if (MonoSingleton<PortalManagerV2>.TryGetInstance(ref val) && (Object)(object)val != (Object)null) { val.RemoveTraveller((IPortalTraveller)(object)component); } } catch { } } private static int CountRemainingTrackedEnemies() { int num = 0; for (int num2 = _trackedEnemies.Count - 1; num2 >= 0; num2--) { EnemyIdentifier val = _trackedEnemies[num2]; if ((Object)(object)val == (Object)null) { _trackedEnemies.RemoveAt(num2); } else if (EnemyFilter.IsArenaTarget(val)) { num++; } } return num; } private static void RefreshPowerCombatTarget(GabrielPower marker, EnemyIdentifier eid) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown if ((Object)(object)marker == (Object)null || (Object)(object)eid == (Object)null) { return; } EnemyIdentifier val = SelectPowerTarget(((Component)eid).transform.position, marker.CurrentTarget); if ((Object)(object)val == (Object)null) { if ((Object)(object)marker.CurrentTarget != (Object)null) { marker.CurrentTarget = null; eid.ResetTarget(); ConfigureSwingChecks(((Component)eid).gameObject, eid, null); } return; } bool num = (Object)(object)marker.CurrentTarget != (Object)(object)val || eid.target == null || !eid.target.isEnemy || (Object)(object)eid.target.enemyIdentifier != (Object)(object)val; marker.CurrentTarget = val; if (num) { eid.target = new EnemyTarget(val); ConfigureSwingChecks(((Component)eid).gameObject, eid, val); Plugin.LogDebug("Power target set to " + DescribeEnemy(val) + "."); } } private static EnemyIdentifier SelectPowerTarget(Vector3 origin, EnemyIdentifier preferred) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (IsSelectablePowerTarget(preferred)) { return preferred; } EnemyIdentifier result = null; float num = float.MaxValue; Vector3 position = Vector3.zero; bool flag = _targetByPlayerProximity && TryGetPlayerPosition(out position); for (int num2 = _trackedEnemies.Count - 1; num2 >= 0; num2--) { EnemyIdentifier val = _trackedEnemies[num2]; if (IsSelectablePowerTarget(val)) { Vector3 val2 = (flag ? position : origin); Vector3 val3 = ((Component)val).transform.position - val2; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = val; } } } return result; } private static bool IsSelectablePowerTarget(EnemyIdentifier target) { if (!IsValidActiveTarget(target)) { return false; } if (_targetByPlayerProximity) { return IsTargetCloseToPlayer(target); } return true; } private static bool IsManagedPowerTarget(EnemyIdentifier target) { if (!IsValidActiveTarget(target) || !_trackedEnemies.Contains(target)) { return false; } for (int i = 0; i < _alivePowers.Count; i++) { GameObject val = _alivePowers[i]; if (!((Object)(object)val == (Object)null)) { GabrielPower component = val.GetComponent<GabrielPower>(); if ((Object)(object)component != (Object)null && (Object)(object)component.CurrentTarget == (Object)(object)target) { return true; } } } return false; } private static GabrielPower FindNearestManagedPower(Vector3 position, float maxDistance) { //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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) GabrielPower result = null; float num = maxDistance * maxDistance; for (int i = 0; i < _alivePowers.Count; i++) { GameObject val = _alivePowers[i]; if ((Object)(object)val == (Object)null) { continue; } GabrielPower component = val.GetComponent<GabrielPower>(); if (!((Object)(object)component == (Object)null)) { Vector3 val2 = val.transform.position - position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = component; } } } return result; } private static TargetHandle CreateTargetHandle(EnemyIdentifier target) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if ((Object)(object)target == (Object)null) { return null; } Enemy component = ((Component)target).GetComponent<Enemy>(); if (!((Object)(object)component == (Object)null)) { return new TargetHandle((ITarget)(object)component); } return null; } private static void TrackManagedProjectile(Projectile projectile) { if (!((Object)(object)projectile == (Object)null) && !((Object)(object)((Component)projectile).gameObject == (Object)null)) { GameObject gameObject = ((Component)projectile).gameObject; if (!_managedProjectiles.Contains(gameObject)) { _managedProjectiles.Add(gameObject); } } } private static void DestroyManagedProjectile(Projectile projectile) { if (!((Object)(object)projectile == (Object)null) && !((Object)(object)((Component)projectile).gameObject == (Object)null)) { GameObject gameObject = ((Component)projectile).gameObject; _managedProjectiles.Remove(gameObject); Object.Destroy((Object)(object)gameObject); } } private static void DespawnManagedProjectiles(bool silent) { int num = 0; for (int num2 = _managedProjectiles.Count - 1; num2 >= 0; num2--) { GameObject val = _managedProjectiles[num2]; if (!((Object)(object)val == (Object)null)) { Object.Destroy((Object)(object)val); num++; } } _managedProjectiles.Clear(); if (!silent && num > 0) { Plugin.LogDebug($"Despawned {num} managed Power projectiles."); } } private static void PruneManagedProjectiles() { for (int num = _managedProjectiles.Count - 1; num >= 0; num--) { if ((Object)(object)_managedProjectiles[num] == (Object)null) { _managedProjectiles.RemoveAt(num); } } } private static void MarkEnemyDamageToManagedPower(EnemyIdentifier receiver) { if (!((Object)(object)receiver == (Object)null)) { _enemyDamageFrames[receiver] = Time.frameCount; } } private static bool IsEnemyDamageToManagedPower(EnemyIdentifier receiver, GameObject sourceWeapon) { if ((Object)(object)sourceWeapon != (Object)null) { if ((Object)(object)sourceWeapon.GetComponentInParent<GabrielPower>() != (Object)null || (Object)(object)sourceWeapon.GetComponentInParent<GabrielPowerProjectile>() != (Object)null) { return false; } if ((Object)(object)sourceWeapon.GetComponentInParent<NewMovement>() != (Object)null) { return false; } EnemyIdentifier componentInParent = sourceWeapon.GetComponentInParent<EnemyIdentifier>(); if ((Object)(object)componentInParent != (Object)null) { if (!EnemyFilter.IsPlayer(componentInParent)) { return !EnemyFilter.IsGabrielPower(componentInParent); } return false; } } if ((Object)(object)receiver != (Object)null && _enemyDamageFrames.TryGetValue(receiver, out var value) && Time.frameCount - value <= 1) { return true; } if ((Object)(object)receiver != (Object)null) { return receiver.hitter == "enemy"; } return false; } private static bool IsManagedPowerExplosion(Explosion explosion) { if ((Object)(object)explosion == (Object)null) { return false; } if (EnemyFilter.IsGabrielPower(explosion.originEnemy)) { return true; } GameObject sourceWeapon = explosion.sourceWeapon; if ((Object)(object)sourceWeapon != (Object)null) { if (!((Object)(object)sourceWeapon.GetComponentInParent<GabrielPower>() != (Object)null)) { return (Object)(object)sourceWeapon.GetComponentInParent<GabrielPowerProjectile>() != (Object)null; } return true; } return false; } private static bool IsPlayerOwnedProjectile(Projectile projectile) { if ((Object)(object)projectile == (Object)null) { return false; } if (projectile.playerBullet || projectile.friendly) { return true; } GameObject sourceWeapon = projectile.sourceWeapon; if ((Object)(object)sourceWeapon == (Object)null) { return false; } if ((Object)(object)sourceWeapon.GetComponentInParent<NewMovement>() != (Object)null) { return true; } return EnemyFilter.IsPlayer(sourceWeapon.GetComponentInParent<EnemyIdentifier>()); } private static bool IsHookDamageToManagedPower(EnemyIdentifier receiver) { if ((Object)(object)receiver != (Object)null) { return receiver.hitter == "hook"; } return false; } private static HookArm ResolveHookArm() { try { return MonoSingleton<HookArm>.Instance; } catch { return null; } } private static void PruneEnemyDamageFrames() { if (_enemyDamageFrames.Count == 0) { return; } List<EnemyIdentifier> list = null; foreach (KeyValuePair<EnemyIdentifier, int> enemyDamageFrame in _enemyDamageFrames) { if ((Object)(object)enemyDamageFrame.Key == (Object)null || Time.frameCount - enemyDamageFrame.Value > 1) { if (list == null) { list = new List<EnemyIdentifier>(); } list.Add(enemyDamageFrame.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { _enemyDamageFrames.Remove(list[i]); } } } public static bool TryHandleManagedPowerFleshBossMeleeCollision(SwingCheck2 swingCheck, EnemyIdentifier receiver, Collider other, EnemyIdentifier attacker) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)swingCheck == (Object)null || (Object)(object)receiver == (Object)null || (Object)(object)other == (Object)null) { return false; } if (!IsManagedPowerSwing(swingCheck) || !IsFleshBossTarget(receiver) || !IsSelectablePowerTarget(receiver)) { return false; } if (HasManagedMeleeHit(swingCheck, receiver)) { return true; } RecordManagedMeleeHit(swingCheck, receiver); if (!swingCheck.hitColliders.Contains(other)) { swingCheck.hitColliders.Add(other); } if (swingCheck.enemyDamage <= 0 && swingCheck.damage > 0) { swingCheck.enemyDamage = Mathf.Max(4, swingCheck.damage / 10); } receiver.hitter = "enemy"; float num = Mathf.Max(1f, (float)swingCheck.enemyDamage); if ((Object)(object)attacker != (Object)null) { num *= attacker.totalDamageModifier; } Vector3 val = ((Component)swingCheck).transform.position - ((Component)other).transform.position; Vector3 val2 = (((Vector3)(ref val)).normalized + Vector3.up) * 10000f; receiver.DeliverDamage(((Component)other).gameObject, val2, ((Component)other).transform.position, num, false, 0f, (GameObject)null, false, false); Plugin.LogDebug("Applied managed Power melee damage to Flesh boss target " + DescribeEnemy(receiver) + "."); return true; } public static void ClearManagedPowerMeleeHitRecord(SwingCheck2 swingCheck) { if ((Object)(object)swingCheck != (Object)null) { _managedMeleeHitEnemies.Remove(swingCheck); } } private static bool HasManagedMeleeHit(SwingCheck2 swingCheck, EnemyIdentifier receiver) { if ((Object)(object)swingCheck != (Object)null && (Object)(object)receiver != (Object)null && _managedMeleeHitEnemies.TryGetValue(swingCheck, out var value)) { return value.Contains(receiver); } return false; } private static void RecordManagedMeleeHit(SwingCheck2 swingCheck, EnemyIdentifier receiver) { if (!((Object)(object)swingCheck == (Object)null) && !((Object)(object)receiver == (Object)null)) { if (!_managedMeleeHitEnemies.TryGetValue(swingCheck, out var value)) { value = new List<EnemyIdentifier>(2); _managedMeleeHitEnemies.Add(swingCheck, value); } if (!value.Contains(receiver)) { value.Add(receiver); } } } private static GabrielPower ResolveManagedPowerMarker(EnemyIdentifier receiver, GameObject target) { GabrielPower result = default(GabrielPower); if ((Object)(object)receiver != (Object)null && ((Component)receiver).TryGetComponent<GabrielPower>(ref result)) { return result; } if (!((Object)(object)target == (Object)null)) { return target.GetComponentInParent<GabrielPower>(); } return null; } private static bool IsManagedPowerSwing(SwingCheck2 swingCheck) { if ((Object)(object)swingCheck == (Object)null) { return false; } if ((Object)(object)swingCheck.eid != (Object)null && (Object)(object)((Component)swingCheck.eid).GetComponentInParent<GabrielPower>() != (Object)null) { return true; } return (Object)(object)((Component)swingCheck).GetComponentInParent<GabrielPower>() != (Object)null; } private static bool IsFleshBossTarget(EnemyIdentifier target) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 if ((Object)(object)target != (Object)null) { if ((int)target.enemyType != 17) { return (int)target.enemyType == 30; } return true; } return false; } private static bool IsPlayerCollider(Collider other) { if ((Object)(object)other == (Object)null || (Object)(object)((Component)other).gameObject == (Object)null) { return false; } if (!((Component)other).gameObject.CompareTag("Player")) { return (Object)(object)((Component)other).GetComponentInParent<NewMovement>() != (Object)null; } return true; } private static void RefreshManagedPowerPlayerCollision(GabrielPower marker, bool force) { if ((Object)(object)marker == (Object)null || (Object)(object)((Component)marker).gameObject == (Object)null || (!force && Time.time < marker.NextPlayerCollisionRefreshTime)) { return; } Collider[] array = ResolvePlayerColliders(); if (array.Length == 0) { marker.NextPlayerCollisionRefreshTime = Time.time + 0.5f; return; } if (force || marker.Colliders == null || marker.Colliders.Length == 0 || !HasSameColliders(marker.IgnoredPlayerColliders, array)) { marker.Colliders = ((Component)marker).GetComponentsInChildren<Collider>(true); marker.IgnoredPlayerColliders = array; } Collider[] colliders = marker.Colliders; foreach (Collider val in colliders) { if ((Object)(object)val == (Object)null) { continue; } foreach (Collider val2 in array) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val == (Object)(object)val2)) { Physics.IgnoreCollision(val, val2, true); } } } marker.NextPlayerCollisionRefreshTime = Time.time + 0.5f; } private static Collider[] ResolvePlayerColliders() { NewMovement instance = MonoSingleton<NewMovement>.Instance; if ((Object)(object)instance == (Object)null) { return EmptyColliders; } Collider[] componentsInChildren = ((Component)instance).GetComponentsInChildren<Collider>(true); if (componentsInChildren != null && componentsInChildren.Length != 0) { return componentsInChildren; } if ((Object)(object)instance.playerCollider != (Object)null) { return (Collider[])(object)new CapsuleCollider[1] { instance.playerCollider }; } Collider component = ((Component)instance).GetComponent<Collider>(); if (!((Object)(object)component == (Object)null)) { return (Collider[])(object)new Collider[1] { component }; } return EmptyColliders; } private static bool HasSameColliders(Collider[] existing, Collider[] current) { if (existing == null || current == null || existing.Length != current.Length) { return false; } for (int i = 0; i < existing.Length; i++) { if ((Object)(object)existing[i] != (Object)(object)current[i]) { return false; } } return true; } private static void HandleRepositionHotkey() { //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_0006: 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) KeyCode repositionKey = GabrielingsConfig.RepositionKey; if ((int)repositionKey != 0 && Input.GetKeyDown(repositionKey)) { RepositionPowersToPlayer("keybind"); } } private static void RepositionPowersToPlayer(string reason) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_007c: Unknown result type (might be due to invalid IL or missing references) NewMovement instance = MonoSingleton<NewMovement>.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)((Component)instance).transform == (Object)null) { return; } int num = 0; for (int i = 0; i < _alivePowers.Count; i++) { GameObject val = _alivePowers[i]; if (!((Object)(object)val == (Object)null)) { GabrielPower component = val.GetComponent<GabrielPower>(); Vector3 position = (((Object)(object)component == (Object)null) ? (((Component)instance).transform.position + Vector3.up * 2f) : CalculateFollowPosition(component, ((Component)instance).transform)); MovePowerInstantly(val, position); num++; } } if (num > 0) { Plugin.LogDebug($"Repositioned {num} Powers near V1 from {reason}."); } } private static void ApplyProvidenceHookDodge(GabrielPower marker) { //IL_0020: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_0087: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)marker == (Object)null) && !((Object)(object)((Component)marker).gameObject == (Object)null)) { Transform transform = ((Component)marker).transform; Vector3 val = transform.up * Random.Range(-5f, 5f) + transform.right * Random.Range(-5f, 5f); if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = transform.right; } if (IsProvidenceDodgeBlocked(transform.position, val)) { val *= -1f; } ApplyProvidenceDodgeImpulse(marker, val); } } private static void PlayManagedPowerDodgeAnimation(GabrielPower marker) { if ((Object)(object)marker == (Object)null || (Object)(object)((Component)marker).gameObject == (Object)null) { return; } Power val = (marker.Power = (((Object)(object)marker.Power != (Object)null) ? marker.Power : ((Component)marker).GetComponent<Power>())); if ((Object)(object)val != (Object)null && PowerBackdashMethod != null) { try { PowerBackdashMethod.Invoke(val, PowerBackdashAnimationArgs); return; } catch { } } Animator val2 = (marker.Animator = (((Object)(object)marker.Animator != (Object)null) ? marker.Animator : ((Component)marker).GetComponent<Animator>())); if ((Object)(object)val2 != (Object)null) { val2.Play("Backdash", 0, 0f); } } private static void ApplyProvidenceDodgeImpulse(GabrielPower marker, Vector3 direction) { //IL_002c: 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_003f: 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) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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) if (!((Object)(object)marker == (Object)null) && !((Object)(object)((Component)marker).gameObject == (Object)null) && !(((Vector3)(ref direction)).sqrMagnitude < 0.001f)) { if (IsProvidenceDodgeBlocked(((Component)marker).transform.position, ((Vector3)(ref direction)).normalized)) { direction *= -1f; } Rigidbody component = ((Component)marker).GetComponent<Rigidbody>(); if (!((Object)(object)component == (Object)null)) { EnemyIdentifier val = (((Object)(object)marker.EnemyIdentifier != (Object)null) ? marker.EnemyIdentifier : ((Component)marker).GetComponent<EnemyIdentifier>()); float num = (((Object)(object)val == (Object)null) ? 1f : val.totalSpeedModifier); component.AddForce(((Vector3)(ref direction)).normalized * 750f * num, (ForceMode)1); } } } private static bool IsProvidenceDodgeBlocked(Vector3 origin, Vector3 direction) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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) if (((Vector3)(ref direction)).sqrMagnitude >= 0.001f) { return PortalPhysicsV2.Raycast(origin, direction, 7f, LayerMask.op_Implicit(LayerMaskDefaults.Get((LMD)1)), (QueryTriggerInteraction)0); } return false; } private static bool ShouldRepeatProvidenceHookDodge(EnemyIdentifier eid) { try { return Enemy.InitializeDifficulty(eid) >= 2; } catch { return true; } } private static IEnumerator DelayedProvidenceHookDodge(GabrielPower marker) { yield return (object)new WaitForSeconds(0.1f); ApplyProvidenceHookDodge(marker); } private static void MovePowerInstantly(GameObject go, Vector3 position) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)go == (Object)null) { return; } go.transform.position = position; Rigidbody component = go.GetComponent<Rigidbody>(); if (!((Object)(object)component == (Object)null)) { component.position = position; if (!component.isKinematic) { component.velocity = Vector3.zero; } } } private static void UpdateIdlePlayerFollowing() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!GabrielingsConfig.FollowPlayerWhenIdle) { return; } NewMovement instance = MonoSingleton<NewMovement>.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)((Component)instance).transform == (Object)null) { return; } for (int i = 0; i < _alivePowers.Count; i++) { GameObject val = _alivePowers[i]; if (!((Object)(object)val == (Object)null)) { GabrielPower component = val.GetComponent<GabrielPower>(); if (!((Object)(object)component == (Object)null) && ShouldFollowPlayer(component, ((Component)instance).transform.position)) { Vector3 followPosition = CalculateFollowPosition(component, ((Component)instance).transform); MovePowerTowardFollowPosition(val, followPosition); } } } } private static bool ShouldFollowPlayer(GabrielPower marker, Vector3 playerPosition) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0048: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)marker == (Object)null) { return false; } if ((Object)(object)marker.Power != (Object)null && marker.Power.inAction) { return false; } if (IsSelectablePowerTarget(marker.CurrentTarget)) { return false; } Vector3 val = ((Component)marker).transform.position - playerPosition; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude > 484f) { return true; } return sqrMagnitude > 49f; } private static Vector3 CalculateFollowPosition(GabrielPower marker, Transform player) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) Vector3 forward = player.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.001f) { forward = Vector3.forward; } ((Vector3)(ref forward)).Normalize(); Vector3 val = player.right; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = Vector3.Cross(Vector3.up, forward); } ((Vector3)(ref val)).Normalize(); int num = Mathf.Abs(marker.FollowIndex); float num2 = (((num & 1) == 0) ? 1f : (-1f)) * (2.6f + (float)(num % 3) * 0.9f); float num3 = 5.5f + (float)(num / 2 % 3) * 1.2f; float num4 = 2.2f + (float)(num % 4) * 0.35f + Mathf.Sin(Time.time * 1.8f + marker.FollowPhase) * 0.3f; return player.position - forward * num3 + val * num2 + Vector3.up * num4; } private static void MovePowerTowardFollowPosition(GameObject go, Vector3 followPosition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) Vector3 val = followPosition - go.transform.position; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.75f) { return; } Rigidbody component = go.GetComponent<Rigidbody>(); if (magnitude > 70f) { go.transform.position = followPosition; if ((Object)(object)component != (Object)null && !component.isKinematic) { component.velocity = Vector3.zero; } return; } float num = Mathf.Lerp(5f, 18f, Mathf.InverseLerp(2f, 30f, magnitude)); Vector3 val2 = ((Vector3)(ref val)).normalized * num; if ((Object)(object)component != (Object)null && !component.isKinematic) { component.velocity = Vector3.Lerp(component.velocity, val2, Time.deltaTime * 4f); } else { go.transform.position = Vector3.MoveTowards(go.transform.position, followPosition, num * Time.deltaTime); } } private static EnemyIdentifier ResolveColliderEnemy(Collider other) { if ((Object)(object)other == (Object)null) { return null; } EnemyIdentifierIdentifier componentInParent = ((Component)other).GetComponentInParent<EnemyIdentifierIdentifier>(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.eid != (Object)null) { return componentInParent.eid; } return ((Component)other).GetComponentInParent<EnemyIdentifier>(); } private static void StartClearGrace(string reason) { _remainingEnemySnapshot = 0; if (_clearGraceTimer <= 0f) { _clearGraceTimer = 1.25f; Plugin.LogDebug("No tracked enemies remain after " + reason + "; waiting briefly for a next wave."); } } private static bool WaitForWaveContinuation() { if (_clearGraceTimer <= 0f) { _clearGraceTimer = 1.25f; return true; } _clearGraceTimer -= Time.deltaTime; return _clearGraceTimer > 0f; } private static void FinishAssist() { _clearGraceTimer = 0f; DespawnAll(); _trackedEnemies.Clear(); _trackedArena = null; } private static void HandleEnemyAdded(EnemyIdentifier eid) { if (!((Object)(object)eid == (Object)null)) { if (_alivePowers.Count > 0 || _trackedEnemies.Count > 0) { AddWaveTarget(eid); } else if (!((Object)(object)_pendingLockedDoor == (Object)null) || _pendingOpenAreaScan) { Plugin.LogDebug("Enemy added during pending fallback scan: " + DescribeEnemy(eid) + "."); TryStartAssistFromCurrentEnemies("enemy-added fallback"); } } } private static void AddWaveTarget(EnemyIdentifier eid) { if (IsValidAssistTarget(eid) && !_trackedEnemies.Contains(eid) && (!_targetByPlayerProximity || IsTargetCloseToPlayer(eid))) { GameObject gameObject = ((Component)eid).gameObject; if (!((Object)(object)gameObject == (Object)null) && gameObject.activeInHierarchy) { _trackedEnemies.Add(eid); _remainingEnemySnapshot = CountRemainingTrackedEnemies(); _clearGraceTimer = 0f; Plugin.LogDebug($"Wave target tracked: {DescribeEnemy(eid)}; {_remainingEnemySnapshot} enemies remain."); } } } private static void PruneTrackedTargetsOutsidePlayerRange() { if (!_targetByPlayerProximity) { return; } for (int num = _trackedEnemies.Count - 1; num >= 0; num--) { EnemyIdentifier val = _trackedEnemies[num]; if ((Object)(object)val == (Object)null || !IsTargetCloseToPlayer(val)) { ClearManagedPowerTarget(val); _trackedEnemies.RemoveAt(num); } } } private static void ClearManagedPowerTarget(EnemyIdentifier target) { for (int i = 0; i < _alivePowers.Count; i++) { GameObject val = _alivePowers[i]; if ((Object)(object)val == (Object)null) { continue; } GabrielPower component = val.GetComponent<GabrielPower>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.CurrentTarget != (Object)(object)target)) { component.CurrentTarget = null; if ((Object)(object)component.EnemyIdentifier != (Object)null) { component.EnemyIdentifier.ResetTarget(); } } } } private static bool IsTargetCloseToPlayer(EnemyIdentifier target) { //IL_001a: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null || !TryGetPlayerPosition(out var position)) { return false; } Vector3 val = ((Component)target).transform.position - position; return ((Vector3)(ref val)).sqrMagnitude <= 3025f; } private static bool TryGetPlayerPosition(out Vector3 position) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0029: Unknown result type (might be due to invalid IL or missing references) NewMovement instance = MonoSingleton<NewMovement>.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)((Component)instance).transform != (Object)null) { position = ((Component)instance).transform.position; return true; } position = Vector3.zero; return false; } public static bool IsManagedPower(Power power) { GabrielPower gabrielPower = default(GabrielPower); if ((Object)(object)power != (Object)null) { return ((Component)power).TryGetComponent<GabrielPower>(ref gabrielPower); } return false; } public static void DetachFromPowerCooldowns(Power power) { if (!IsManagedPower(power)) { return; } EnemyCooldowns instance = MonoSingleton<EnemyCooldowns>.Instance; if (!((Object)(object)instance == (Object)null)) { instance.RemovePower(power); if ((Object)(object)instance.attackingPower == (Object)(object)power) { instance.attackingPower = null; } } } private static void OnCheckpointRestart() { HandleCheckpointRestart("StatsManager.checkpointRestart"); } } } namespace Gabrielings.Patches { public struct PowerCooldownState { public bool Applied; public EnemyCooldowns Cooldowns; public Power PreviousAttackingPower; } [HarmonyPatch] public static class AllPatches { } [HarmonyPatch(typeof(ActivateArena), "Activate", new Type[] { })] public static class ActivateArena_Activate_Patch { [HarmonyPrefix] public static void Prefix(ActivateArena __instance) { if (!((Object)(object)__instance == (Object)null)) { PowerSpawnManager.HandleArenaActivated(__instance); } } } [HarmonyPatch(typeof(Door), "Lock", new Type[] { })] public static class Door_Lock_Patch { [HarmonyPostfix] public static void Postfix(Door __instance) { if (!((Object)(object)__instance == (Object)null)) { PowerSpawnManager.HandleDoorLocked(__instance); } } } [HarmonyPatch(typeof(BossHealthBar), "OnEnable", new Type[] { })] public static class BossHealthBar_OnEnable_Patch { [HarmonyPostfix] public static void Postfix(BossHealthBar __instance) { if (!((Object)(object)__instance == (Object)null)) { PowerSpawnManager.HandleBossHealthBar(__instance); } } } [HarmonyPatch(typeof(Power), "Update", new Type[] { })] public static class Power_Update_Patch { [HarmonyPrefix] public static void Prefix(Power __instance, ref PowerCooldownState __state) { if (PowerSpawnManager.IsManagedPower(__instance)) { EnemyCooldowns instance = MonoSingleton<EnemyCooldowns>.Instance; if (!((Object)(object)instance == (Object)null) && instance.powers != null) { __state.Applied = true; __state.Cooldowns = instance; __state.PreviousAttackingPower = instance.attackingPower; instance.attackingPower = null; instance.powers.Remove(__instance); instance.powers.Insert(0, __instance); } } } [HarmonyFinalizer] public static Exception Finalizer(Exception __exception, Power __instance, PowerCooldownState __state) { if (__state.Applied && (Object)(object)__state.Cooldowns != (Object)null) { __state.Cooldowns.powers.Remove(__instance); __state.Cooldowns.attackingPower = __state.PreviousAttackingPower; } return __exception; } } [HarmonyPatch(typeof(EnemyCooldowns), "AddPower", new Type[] { typeof(Power) })] public static class EnemyCooldowns_AddPower_Patch { [HarmonyPostfix] public static void Postfix(Power pwr) { PowerSpawnManager.DetachFromPowerCooldowns(pwr); } } [HarmonyPatch(typeof(Power), "StopAction", new Type[] { })] public static class Power_StopAction_Patch { [HarmonyPrefix] public static void Prefix(Power __instance, ref PowerCooldownState __state) { PowerPatchSupport.PrepareManagedAttackEnd(__instance, ref __state); } [HarmonyFinalizer] public static Exception Finalizer(Exception __exception, Power __instance, PowerCooldownState __state) { PowerPatchSupport.RestoreManagedAttackEnd(__instance, __state); return __exception; } } [HarmonyPatch(typeof(Power), "PlaySound", new Type[] { typeof(AudioClip), typeof(bool), typeof(bool), typeof(float) })] public static class Power_PlaySound_Patch { [HarmonyPrefix] public static bool Prefix(Power __instance) { return !PowerSpawnManager.ShouldMuteManagedPowerVoice(__instance); } } [HarmonyPatch(typeof(Power), "CanPlaySound", new Type[] { typeof(bool) })] public static class Power_CanPlaySound_Patch { [HarmonyPrefix] public static bool Prefix(Power __instance, ref bool __result) { if (!PowerSpawnManager.ShouldMuteManagedPowerVoice(__instance)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Power), "DespawnWeapon", new Type[] { typeof(GameObject), typeof(bool) })] public static class Power_DespawnWeapon_Patch { [HarmonyPrefix] public static void Prefix(Power __instance, ref PowerCooldownState __state) { PowerPatchSupport.PrepareManagedAttackEnd(__instance, ref __state); } [HarmonyFinalizer] public static Exception Finalizer(Exception __exception, Power __instance, PowerCooldownState __state) { PowerPatchSupport.RestoreManagedAttackEnd(__instance, __state); return __exception; } } public static class PowerPatchSupport { public static void PrepareManagedAttackEnd(Power power, ref PowerCooldownState state) { if (PowerSpawnManager.IsManagedPower(power)) { EnemyCooldowns instance = MonoSingleton<EnemyCooldowns>.Instance; if (!((Object)(object)instance == (Object)null)) { state.Applied = true; state.Cooldowns = instance; state.PreviousAttackingPower = (((Object)(object)instance.attackingPower == (Object)(object)power) ? null : instance.attackingPower); instance.attackingPower = power; } } } public static void RestoreManagedAttackEnd(Power power, PowerCooldownState state) { if (state.Applied && !((Object)(object)state.Cooldowns == (Object)null)) { PowerSpawnManager.DetachFromPowerCooldowns(power); if ((Object)(object)state.Cooldowns.attackingPower == (Object)null || (Object)(object)state.Cooldowns.attackingPower == (Object)(object)power) { state.Cooldowns.attackingPower = state.PreviousAttackingPower; } } } } [HarmonyPatch(typeof(EnemyCooldowns), "PowerAttackEnd", new Type[] { })] public static class EnemyCooldowns_PowerAttackEnd_Patch { [HarmonyPostfix] public static void Postfix(Power __state) { PowerSpawnManager.DetachFromPowerCooldowns(__state); } [HarmonyPrefix] public static void Prefix(EnemyCooldowns __instance, ref Power __state) { __state = (((Object)(object)__instance == (Object)null) ? null : __instance.attackingPower); } } [HarmonyPatch(typeof(EnemyIdentifier), "UpdateTarget", new Type[] { })] public static class EnemyIdentifier_UpdateTarget_Patch { [HarmonyPostfix] public static void Postfix(EnemyIdentifier __instance) { PowerSpawnManager.HandleEnemyTargetUpdated(__instance); } } [HarmonyPatch(typeof(Projectile), "Start", new Type[] { })] public static class Projectile_Start_Patch { [HarmonyPrefix] public static void Prefix(Projectile __instance) { PowerSpawnManager.ConfigureManagedPowerProjectile(__instance); } [HarmonyPostfix] public static void Postfix(Projectile __instance) { PowerSpawnManager.ConfigureManagedPowerProjectile(__instance); } } [HarmonyPatch(typeof(Projectile), "OnTriggerEnter", new Type[] { typeof(Collider) })] public static class Projectile_OnTriggerEnter_Patch { [HarmonyPrefix] public static bool Prefix(Projectile __instance, Collider other) { if (PowerSpawnManager.ShouldSkipManagedPowerProjectileCollision(__instance, other)) { return false; } PowerSpawnManager.MarkEnemyProjectileDamageToManagedPower(__instance, other); PowerSpawnManager.PrepareManagedPowerProjectileHit(__instance, other); return true; } } [HarmonyPatch(typeof(Explosion), "OnTriggerEnter", new Type[] { typeof(Collider) })] public static class Explosion_OnTriggerEnter_Patch { [HarmonyPrefix] public static bool Prefix(Explosion __instance, Collider other) { return !PowerSpawnManager.ShouldSkipManagedPowerExplosionCollision(__instance, other); } } [HarmonyPatch(typeof(SwingCheck2), "CheckEidCollision", new Type[] { typeof(EnemyIdentifier), typeof(Collider) })] public static class SwingCheck2_CheckEidCollision_Patch { [HarmonyPrefix] public static bool Prefix(SwingCheck2 __instance, EnemyIdentifier enid, Collider other, EnemyIdentifier ___eid) { if (PowerSpawnManager.ShouldSkipManagedPowerMeleeEnemyCollision(__instance, enid)) { return false; } if (PowerSpawnManager.TryHandleManagedPowerFleshBossMeleeCollision(__instance, enid, other, ___eid)) { return false; } PowerSpawnManager.MarkEnemyMeleeDamageToManagedPower(enid, ___eid); return true; } } [HarmonyPatch(typeof(SwingCheck2), "DamageStart", new Type[] { })] public static class SwingCheck2_DamageStart_Patch { [HarmonyPrefix] public static void Prefix(SwingCheck2 __instance) { PowerSpawnManager.ClearManagedPowerMeleeHitRecord(__instance); } } [HarmonyPatch(typeof(SwingCheck2), "DamageStop", new Type[] { })] public static class SwingCheck2_DamageStop_Patch { [HarmonyPostfix] public static void Postfix(SwingCheck2 __instance) { PowerSpawnManager.ClearManagedPowerMeleeHitRecord(__instance); } } [HarmonyPatch(typeof(SwingCheck2), "CheckCollision", new Type[] { typeof(Collider) })] public static class SwingCheck2_CheckCollision_Patch { [HarmonyPrefix] public static bool Prefix(SwingCheck2 __instance, Collider other) { return !PowerSpawnManager.ShouldSkipManagedPowerMeleeCollision(__instance, other); } } [HarmonyPatch(typeof(HookArm), "FixedUpdate", new Type[] { })] public static class HookArm_FixedUpdate_Patch { [HarmonyPostfix] public static void Postfix(HookArm __instance, EnemyIdentifier ___caughtEid) { PowerSpawnManager.HandleManagedPowerHooked(__instance, ___caughtEid); } } [HarmonyPatch(typeof(Punch), "ParryProjectile", new Type[] { typeof(Projectile) })] public static class Punch_ParryProjectile_Patch { [HarmonyPrefix] public static void Prefix(Projectile proj, ref bool __state) { __state = PowerSpawnManager.BeginManagedPowerProjectileParry(proj); } [HarmonyFinalizer] public static Exception Finalizer(Exception __exception, bool __state) { if (__state) { PowerSpawnManager.EndManagedPowerProjectileParry(); } return __exception; } } [HarmonyPatch(typeof(NewMovement), "GetHealth", new Type[] { typeof(int), typeof(bool), typeof(bool), typeof(bool) })] public static class NewMovement_GetHealth_Patch { [HarmonyPrefix] public static bool Prefix(int health, bool silent) { return !PowerSpawnManager.ShouldSuppressManagedPowerProjectileParryHealing(health, silent); } } [HarmonyPatch(typeof(StatsManager), "Restart", new Type[] { })] public static class StatsManager_Restart_Patch { [HarmonyPrefix] public static void Prefix() { PowerSpawnManager.HandleCheckpointRestart("StatsManager.Restart"); } } [HarmonyPatch(typeof(CheckPoint), "ActivateCheckPoint", new Type[] { })] public static class CheckPoint_ActivateCheckPoint_Patch { [HarmonyPostfix] public static void Postfix(CheckPoint __instance) { PowerSpawnManager.HandleCheckpointActivated(__instance); } } [HarmonyPatch(typeof(CheckPoint), "OnRespawn", new Type[] { })] public static class CheckPoint_OnRespawn_Patch { [HarmonyPrefix] public static void Prefix(CheckPoint __instance) { PowerSpawnManager.HandleCheckpointRestart("CheckPoint.OnRespawn"); } } [HarmonyPatch(typeof(NewMovement), "GetHurt", new Type[] { typeof(int), typeof(bool), typeof(float), typeof(bool), typeof(bool), typeof(float), typeof(bool) })] public static class NewMovement_GetHurt_Patch { [HarmonyPostfix] public static void Postfix(NewMovement __instance) { if ((Object)(object)__instance != (Object)null && __instance.dead) { PowerSpawnManager.HandlePlayerDeath(); } } } [HarmonyPatch(typeof(Enemy), "OnTravel", new Type[] { typeof(PortalTravelDetails) })] public static class Enemy_OnTravel_Patch { [HarmonyPrefix] public static bool Prefix(Enemy __instance, ref bool? __result) { if (!PowerSpawnManager.ShouldBlockManagedPowerPortalTravel(__instance)) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(Enemy), "OnTeleportBlocked", new Type[] { typeof(PortalTravelDetails) })] public static class Enemy_OnTeleportBlocked_Patch { [HarmonyPrefix] public static bool Prefix(Enemy __instance) { return !PowerSpawnManager.ShouldBlockManagedPowerPortalTravel(__instance); } } [HarmonyPatch(typeof(EnemyIdentifier), "DeliverDamage", new Type[] { typeof(GameObject), typeof(Vector3), typeof(Vector3), typeof(float), typeof(bool), typeof(float), typeof(GameObject), typeof(bool), typeof(bool) })] public static class EnemyIdentifier_DeliverDamage_Patch { [HarmonyPrefix] public static bool Prefix(EnemyIdentifier __instance, GameObject target, GameObject sourceWeapon) { return !PowerSpawnManager.ShouldBlockManagedPowerDamage(__instance, target, sourceWeapon); } } [HarmonyPatch(typeof(EnemyIdentifier), "ProcessDeath", new Type[] { typeof(bool) })] public static class EnemyIdentifier_ProcessDeath_Patch { [HarmonyPostfix] public static void Postfix(EnemyIdentifier __instance) { if (!((Object)(object)__instance == (Object)null) && __instance.dead && EnemyFilter.IsArenaTarget(__instance)) { PowerSpawnManager.NotifyPowerKilledEnemy(__instance); } } } } namespace Gabrielings.Conf