using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using FairAI; using FairAI.Component; using FairAI.Patches; using GameNetcodeStuff; using HarmonyLib; using LethalThings; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("FairAI")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FairAI")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("42deea12-f73e-4d63-81e9-5359e98c8d53")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } internal class TurretAIPatch { private readonly struct TurretTarget { public readonly PlayerControllerB Player; public readonly EnemyAI Enemy; public static readonly TurretTarget None = default(TurretTarget); public bool IsPlayer => (Object)(object)Player != (Object)null; public bool IsEnemy => (Object)(object)Enemy != (Object)null; public bool IsValid => IsPlayer || IsEnemy; public bool IsDead => (IsPlayer && Player.isPlayerDead) || (IsEnemy && (Enemy.isEnemyDead || Enemy.enemyHP <= 0)); public Vector3 AimPosition => IsPlayer ? ((Component)Player.gameplayCamera).transform.position : (((Component)Enemy).transform.position + Vector3.up * 0.5f); public Transform AimTransform => IsPlayer ? ((Component)Player.gameplayCamera).transform : ((Component)Enemy).transform; public TurretTarget(PlayerControllerB p) { Player = p; Enemy = null; } public TurretTarget(EnemyAI e) { Player = null; Enemy = e; } } private const float DetectRange = 30f; private const int SweepRays = 7; private static readonly Type TurretType = typeof(Turret); private static bool HasCustomSettings => Plugin.turretSettings.Count > 7; private static float FireInterval => HasCustomSettings ? Setting(1) : 0.21f; private static float SwitchInterval => HasCustomSettings ? Setting(3) : 7f; private static float DetectSpeed => HasCustomSettings ? Setting(5) : 28f; private static float ChargeSpeed => HasCustomSettings ? Setting(6) : 95f; private static float BerserkSpeed => HasCustomSettings ? Setting(7) : 77f; private static int PlayerDamage => HasCustomSettings ? ((int)Setting(0)) : Plugin.GetInt("TurretConfig", "Player Damage"); private static T GetField(Turret t, string name) { return (T)TurretType.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(t); } private static void SetField(Turret t, string name, object value) { TurretType.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(t, value); } private static void CallMethod(Turret t, string name, params object[] args) { TurretType.GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic).Invoke(t, args); } private static float Setting(int index) { return Plugin.turretSettings[index]; } private static FAIR_AI GetAI(Turret turret) { return ((Component)turret).gameObject.GetComponent() ?? ((Component)turret).gameObject.AddComponent(); } private static TurretTarget GetCurrentTarget(Turret turret, FAIR_AI ai) { if ((Object)(object)ai.targetWithRotation != (Object)null && !ai.targetWithRotation.isEnemyDead) { return new TurretTarget(ai.targetWithRotation); } if ((Object)(object)turret.targetPlayerWithRotation != (Object)null && !turret.targetPlayerWithRotation.isPlayerDead) { return new TurretTarget(turret.targetPlayerWithRotation); } return TurretTarget.None; } private static void SetCurrentTarget(Turret turret, FAIR_AI ai, TurretTarget target) { turret.targetPlayerWithRotation = null; ai.targetWithRotation = null; if (target.IsPlayer) { turret.targetPlayerWithRotation = target.Player; } else if (target.IsEnemy) { ai.targetWithRotation = target.Enemy; turret.targetTransform = ((Component)target.Enemy).transform; } } private static void ClearTarget(Turret turret, FAIR_AI ai) { turret.targetPlayerWithRotation = null; ai.targetWithRotation = null; turret.targetTransform = null; ai.targetWithRotation = null; if (((NetworkBehaviour)turret).IsServer) { turret.RemoveTargetedPlayerClientRpc(); ai.RemoveTargetedEnemyClientRpc(); } } public static bool PatchUpdate(ref Turret __instance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Invalid comparison between Unknown and I4 //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected I4, but got Unknown //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !Plugin.AllowFairness(((Component)__instance).transform.position)) { return false; } Turret val = __instance; FAIR_AI aI = GetAI(val); if (!val.turretActive) { SetField(val, "wasTargetingPlayerLastFrame", false); val.turretMode = (TurretMode)0; ClearTarget(val, aI); return false; } TurretTarget currentTarget = GetCurrentTarget(val, aI); if (currentTarget.IsValid && !currentTarget.IsDead) { if (!GetField(val, "wasTargetingPlayerLastFrame")) { SetField(val, "wasTargetingPlayerLastFrame", true); if ((int)val.turretMode == 0) { val.turretMode = (TurretMode)1; } } SyncTargetTransform(val, aI, currentTarget); } else if (currentTarget.IsDead) { ClearTarget(val, aI); SetField(val, "wasTargetingPlayerLastFrame", false); val.turretMode = (TurretMode)0; } else if (GetField(val, "wasTargetingPlayerLastFrame")) { SetField(val, "wasTargetingPlayerLastFrame", false); val.turretMode = (TurretMode)0; } TurretMode turretMode = val.turretMode; TurretMode val2 = turretMode; switch ((int)val2) { case 0: DetectionFunction(val, aI); break; case 1: ChargingFunction(val, aI); break; case 2: FiringFunction(val, aI); break; case 3: BerserkFunction(val); break; } if (GetField(val, "rotatingClockwise")) { val.turnTowardsObjectCompass.localEulerAngles = new Vector3(-180f, val.turretRod.localEulerAngles.y - Time.deltaTime * 20f, 180f); } else if (GetField(val, "rotatingSmoothly")) { val.turnTowardsObjectCompass.localEulerAngles = new Vector3(-180f, Mathf.Clamp(val.targetRotation, 0f - val.rotationRange, val.rotationRange), 180f); } val.turretRod.rotation = Quaternion.RotateTowards(val.turretRod.rotation, val.turnTowardsObjectCompass.rotation, val.rotationSpeed * Time.deltaTime); return false; } private static void DetectionFunction(Turret turret, FAIR_AI ai) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_028d: Unknown result type (might be due to invalid IL or missing references) if ((int)GetField(turret, "turretModeLastFrame") > 0) { SetField(turret, "turretModeLastFrame", (object)(TurretMode)0); SetField(turret, "rotatingClockwise", false); SetField(turret, "rotatingSmoothly", true); SetField(turret, "turretInterval", Random.Range(0f, 0.15f)); turret.mainAudio.Stop(); turret.farAudio.Stop(); turret.berserkAudio.Stop(); StopAndStartFadeBulletAudio(turret); turret.bulletParticles.Stop(true, (ParticleSystemStopBehavior)0); turret.rotationSpeed = DetectSpeed; turret.turretAnimator.SetInteger("TurretMode", 0); } if (!((NetworkBehaviour)turret).IsServer) { return; } float field = GetField(turret, "switchRotationTimer"); if (field >= SwitchInterval) { SetField(turret, "switchRotationTimer", 0f); bool flag = !GetField(turret, "rotatingRight"); turret.SwitchRotationClientRpc(flag); turret.SwitchRotationOnInterval(flag); } else { SetField(turret, "switchRotationTimer", field + Time.deltaTime); } float field2 = GetField(turret, "turretInterval"); if (field2 < 0.25f) { SetField(turret, "turretInterval", field2 + Time.deltaTime); return; } SetField(turret, "turretInterval", 0f); TurretTarget target = FindBestTarget(turret, angleRangeCheck: true); if (target.IsValid && (!target.IsEnemy || Plugin.CanMob("TurretTargetAllMobs", ".Turret Target", target.Enemy.enemyType.enemyName))) { SetCurrentTarget(turret, ai, target); if (target.IsEnemy) { ai.SwitchedTargetedEnemyClientRpc(turret, target.Enemy); Plugin.logger.LogInfo((object)("Turret: Detected enemy '" + target.Enemy.enemyType.enemyName + "', entering charging mode.")); } else { turret.SwitchTargetedPlayerClientRpc((int)target.Player.playerClientId, true); Plugin.logger.LogInfo((object)"Turret: Detected player, entering charging mode."); } CallMethod(turret, "SwitchTurretMode", (object)(TurretMode)1); turret.SetToModeClientRpc(1); turret.turretMode = (TurretMode)1; } } private static void ChargingFunction(Turret turret, FAIR_AI ai) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)GetField(turret, "turretModeLastFrame") != 1) { SetField(turret, "turretModeLastFrame", (object)(TurretMode)1); SetField(turret, "rotatingClockwise", false); SetField(turret, "rotatingSmoothly", false); SetField(turret, "lostLOSTimer", 0f); turret.mainAudio.PlayOneShot(turret.detectPlayerSFX); WalkieTalkie.TransmitOneShotAudio(turret.mainAudio, turret.detectPlayerSFX, 1f); turret.berserkAudio.Stop(); turret.rotationSpeed = ChargeSpeed; turret.turretAnimator.SetInteger("TurretMode", 1); } TurnTowardsTarget(turret, ai); if (!((NetworkBehaviour)turret).IsServer) { return; } float field = GetField(turret, "turretInterval"); if (field < 1.5f) { SetField(turret, "turretInterval", field + Time.deltaTime); return; } SetField(turret, "turretInterval", 0f); TurretTarget target = FindBestTarget(turret, angleRangeCheck: false); if (!target.IsValid) { Plugin.logger.LogInfo((object)"Turret: Lost LOS during charge wind-up, returning to detection."); ClearTarget(turret, ai); return; } if (target.IsEnemy && !Plugin.CanMob("TurretTargetAllMobs", ".Turret Target", target.Enemy.enemyType.enemyName)) { ClearTarget(turret, ai); return; } SetCurrentTarget(turret, ai, target); Plugin.logger.LogInfo((object)"Turret: Charge complete, opening fire."); CallMethod(turret, "SwitchTurretMode", (object)(TurretMode)2); turret.SetToModeClientRpc(2); } private static void FiringFunction(Turret turret, FAIR_AI ai) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0070: Unknown result type (might be due to invalid IL or missing references) if ((int)GetField(turret, "turretModeLastFrame") != 2) { SetField(turret, "turretModeLastFrame", (object)(TurretMode)2); SetField(turret, "rotatingSmoothly", false); SetField(turret, "lostLOSTimer", 0f); turret.berserkAudio.Stop(); RoundManager.Instance.PlayAudibleNoise(((Component)turret.berserkAudio).transform.position, 15f, 0.9f, 0, false, 0); turret.mainAudio.clip = turret.firingSFX; turret.mainAudio.Play(); turret.farAudio.clip = turret.firingFarSFX; turret.farAudio.Play(); turret.bulletParticles.Play(true); turret.bulletCollisionAudio.Play(); StopAndStartFadeBulletAudio(turret); turret.bulletCollisionAudio.volume = 1f; turret.turretAnimator.SetInteger("TurretMode", 2); } TurnTowardsTarget(turret, ai); if (!GetField(turret, "hasLineOfSight")) { if (!((NetworkBehaviour)turret).IsServer) { return; } float num = GetField(turret, "lostLOSTimer") + Time.deltaTime; SetField(turret, "lostLOSTimer", num); if (num >= 2f) { SetField(turret, "lostLOSTimer", 0f); TurretTarget target = FindBestTarget(turret, angleRangeCheck: false); if (target.IsValid && (!target.IsEnemy || Plugin.CanMob("TurretTargetAllMobs", ".Turret Target", target.Enemy.enemyType.enemyName))) { Plugin.logger.LogInfo((object)"Turret: Re-acquired target after LOS loss."); SetCurrentTarget(turret, ai, target); SetField(turret, "turretInterval", 0f); } else { Plugin.logger.LogInfo((object)"Turret: LOS lost for 2 s, no replacement — returning to detection."); ReturnToDetection(turret, ai); } } return; } SetField(turret, "lostLOSTimer", 0f); float field = GetField(turret, "turretInterval"); if (field < FireInterval) { SetField(turret, "turretInterval", field + Time.deltaTime); return; } SetField(turret, "turretInterval", 0f); ApplyDamageToLocalPlayer(turret); PerformShootRaycast(turret, useCenterPoint: false); TurretTarget currentTarget = GetCurrentTarget(turret, ai); if (!currentTarget.IsValid || currentTarget.IsDead) { TurretTarget target2 = FindBestTarget(turret, angleRangeCheck: false); if (target2.IsValid && (!target2.IsEnemy || Plugin.CanMob("TurretTargetAllMobs", ".Turret Target", target2.Enemy.enemyType.enemyName))) { Plugin.logger.LogInfo((object)"Turret: Target died, acquired new target."); SetCurrentTarget(turret, ai, target2); } else { Plugin.logger.LogInfo((object)"Turret: Target died, no new targets — returning to detection."); ReturnToDetection(turret, ai); } } } private static void BerserkFunction(Turret turret) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)GetField(turret, "turretModeLastFrame") != 3) { SetField(turret, "turretModeLastFrame", (object)(TurretMode)3); SetField(turret, "rotatingClockwise", false); SetField(turret, "rotatingSmoothly", true); SetField(turret, "lostLOSTimer", 0f); SetField(turret, "wasTargetingPlayerLastFrame", false); SetField(turret, "berserkTimer", 1.3f); SetField(turret, "enteringBerserkMode", true); turret.targetPlayerWithRotation = null; turret.rotationSpeed = BerserkSpeed; turret.berserkAudio.Play(); turret.turretAnimator.SetInteger("TurretMode", 1); } if (GetField(turret, "enteringBerserkMode")) { float num = GetField(turret, "berserkTimer") - Time.deltaTime; SetField(turret, "berserkTimer", num); if (num <= 0f) { SetField(turret, "enteringBerserkMode", false); SetField(turret, "rotatingClockwise", true); SetField(turret, "berserkTimer", 9f); turret.turretAnimator.SetInteger("TurretMode", 2); turret.mainAudio.clip = turret.firingSFX; turret.mainAudio.Play(); turret.farAudio.clip = turret.firingFarSFX; turret.farAudio.Play(); turret.bulletParticles.Play(true); turret.bulletCollisionAudio.Play(); StopAndStartFadeBulletAudio(turret); turret.bulletCollisionAudio.volume = 1f; } return; } float field = GetField(turret, "turretInterval"); if (field >= FireInterval) { SetField(turret, "turretInterval", 0f); ApplyDamageToLocalPlayer(turret); PerformShootRaycast(turret, useCenterPoint: true); } else { SetField(turret, "turretInterval", field + Time.deltaTime); } if (((NetworkBehaviour)turret).IsServer) { float num2 = GetField(turret, "berserkTimer") - Time.deltaTime; SetField(turret, "berserkTimer", num2); if (num2 <= 0f) { CallMethod(turret, "SwitchTurretMode", 0); turret.SetToModeClientRpc(0); } } } private static TurretTarget FindBestTarget(Turret turret, bool angleRangeCheck) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) //IL_0040: Unknown result type (might be due to invalid IL or missing references) EnemyAI val = SweepForEnemy(turret); if ((Object)(object)val != (Object)null && !val.isEnemyDead && (!angleRangeCheck || WithinAngleRange(turret, ((Component)val).transform.position + Vector3.up * 0.5f))) { return new TurretTarget(val); } PlayerControllerB val2 = SweepForPlayer(turret, angleRangeCheck); if ((Object)(object)val2 != (Object)null && !val2.isPlayerDead) { return new TurretTarget(val2); } return TurretTarget.None; } private static EnemyAI SweepForEnemy(Turret turret) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) //IL_004d: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) float rotationRange = turret.rotationRange; Vector3 val = Quaternion.Euler(0f, 0f - rotationRange, 0f) * turret.aimPoint.forward; float num = rotationRange * 2f / 6f; Ray val2 = default(Ray); for (int i = 0; i < 7; i++) { ((Ray)(ref val2))..ctor(turret.centerPoint.position, val); RaycastHit[] array = Physics.RaycastAll(val2, 30f, -5, (QueryTriggerInteraction)2); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int j = 0; j < array2.Length; j++) { RaycastHit val3 = array2[j]; if (Physics.Linecast(turret.centerPoint.position, ((RaycastHit)(ref val3)).point, StartOfRound.Instance.collidersAndRoomMask, (QueryTriggerInteraction)1)) { break; } EnemyAI val4 = ((Component)((RaycastHit)(ref val3)).transform).GetComponent() ?? ((Component)((RaycastHit)(ref val3)).transform).GetComponent()?.mainScript; if ((Object)(object)val4 != (Object)null && !val4.isEnemyDead && val4.enemyHP > 0) { return val4; } } val = Quaternion.Euler(0f, num, 0f) * val; } return null; } private static PlayerControllerB SweepForPlayer(Turret turret, bool angleRangeCheck) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) //IL_004d: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: 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_00f6: Invalid comparison between Unknown and I4 //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) float rotationRange = turret.rotationRange; Vector3 val = Quaternion.Euler(0f, 0f - rotationRange, 0f) * turret.aimPoint.forward; float num = rotationRange * 2f / 6f; Ray val2 = default(Ray); RaycastHit val3 = default(RaycastHit); for (int i = 0; i < 7; i++) { ((Ray)(ref val2))..ctor(turret.centerPoint.position, val); if (Physics.Raycast(val2, ref val3, 30f, 1051400, (QueryTriggerInteraction)1)) { if (((Component)((RaycastHit)(ref val3)).transform).CompareTag("Player")) { PlayerControllerB component = ((Component)((RaycastHit)(ref val3)).transform).GetComponent(); if ((Object)(object)component != (Object)null) { if (angleRangeCheck && !WithinAngleRange(turret, ((Component)component).transform.position + Vector3.up * 1.75f)) { return null; } return component; } } else if (((int)turret.turretMode == 2 || (int)turret.turretMode == 3) && !GetField(turret, "enteringBerserkMode") && ((Component)((RaycastHit)(ref val3)).transform).tag.StartsWith("PlayerRagdoll")) { Rigidbody component2 = ((Component)((RaycastHit)(ref val3)).transform).GetComponent(); if (component2 != null) { component2.AddForce(((Vector3)(ref val)).normalized * 42f, (ForceMode)1); } } } val = Quaternion.Euler(0f, num, 0f) * val; } return null; } private static bool WithinAngleRange(Turret turret, Vector3 worldPos) { //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_0017: Unknown result type (might be due to invalid IL or missing references) return Vector3.Angle(worldPos - turret.centerPoint.position, turret.forwardFacingPos.forward) <= turret.rotationRange; } private static void TurnTowardsTarget(Turret turret, FAIR_AI ai) { //IL_0043: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) TurretTarget currentTarget = GetCurrentTarget(turret, ai); if (currentTarget.IsValid && !currentTarget.IsDead) { SyncTargetTransform(turret, ai, currentTarget); bool flag = (Object)(object)turret.targetTransform != (Object)null && WithinAngleRange(turret, turret.targetTransform.position) && !Physics.Linecast(turret.aimPoint.position, currentTarget.AimPosition, StartOfRound.Instance.collidersAndRoomMask, (QueryTriggerInteraction)1); SetField(turret, "hasLineOfSight", flag); if (flag) { turret.tempTransform.position = currentTarget.AimPosition - Vector3.up * 0.15f; turret.turnTowardsObjectCompass.LookAt(turret.tempTransform); } } } private static void SyncTargetTransform(Turret turret, FAIR_AI ai, TurretTarget target) { if (target.IsPlayer) { turret.targetTransform = ((target.Player.isPlayerDead && (Object)(object)target.Player.deadBody != (Object)null) ? ((Component)target.Player.deadBody.bodyParts[5]).transform : ((Component)target.Player.gameplayCamera).transform); } else if (target.IsEnemy) { turret.targetTransform = ((Component)target.Enemy).transform; } } private static void ApplyDamageToLocalPlayer(Turret turret) { //IL_0031: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null || localPlayerController.isPlayerDead) { return; } Ray val = default(Ray); ((Ray)(ref val))..ctor(turret.centerPoint.position, turret.aimPoint.forward); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, ref val2, 30f, 1051400, (QueryTriggerInteraction)1) && ((Component)((RaycastHit)(ref val2)).transform).CompareTag("Player") && !((Object)(object)((Component)((RaycastHit)(ref val2)).transform).GetComponent() != (Object)(object)localPlayerController)) { int playerDamage = PlayerDamage; if (playerDamage <= 0) { localPlayerController.MakeCriticallyInjured(false); localPlayerController.DamagePlayer(playerDamage, false, true, (CauseOfDeath)0, 0, false, default(Vector3)); localPlayerController.MakeCriticallyInjured(false); } else if (localPlayerController.health > playerDamage) { localPlayerController.DamagePlayer(playerDamage, true, true, (CauseOfDeath)7, 0, false, default(Vector3)); } else { localPlayerController.KillPlayer(turret.aimPoint.forward * 40f, true, (CauseOfDeath)7, 0, default(Vector3), false); } } } private static void PerformShootRaycast(Turret turret, bool useCenterPoint) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_007b: 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_0090: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) Ray val = default(Ray); ((Ray)(ref val))..ctor(turret.aimPoint.position, turret.aimPoint.forward); SetField(turret, "shootRay", val); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, ref val2, 30f, StartOfRound.Instance.collidersAndRoomMask, (QueryTriggerInteraction)1)) { SetField(turret, "hit", val2); ((Component)turret.bulletCollisionAudio).transform.position = ((Ray)(ref val)).GetPoint(((RaycastHit)(ref val2)).distance - 0.5f); } Vector3 aimPoint = (useCenterPoint ? turret.centerPoint.position : turret.aimPoint.position); Vector3 forward = Quaternion.Euler(0f, (float)(-(int)turret.rotationRange) / 3f, 0f) * turret.aimPoint.forward; Plugin.AttackTargets(((Component)turret).GetComponent(), aimPoint, forward, 30f); } private static void ReturnToDetection(Turret turret, FAIR_AI ai) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) ClearTarget(turret, ai); turret.turretMode = (TurretMode)0; turret.SetToModeClientRpc(0); SetField(turret, "wasTargetingPlayerLastFrame", false); SetField(turret, "targetingDeadPlayer", true); turret.turretAnimator.SetInteger("TurretMode", 0); CallMethod(turret, "SwitchTurretMode", (object)(TurretMode)0); } public static bool CheckForTargetsInLOS(ref Turret __instance, float radius = 2f, bool angleRangeCheck = false) { FAIR_AI aI = GetAI(__instance); TurretTarget turretTarget = FindBestTarget(__instance, angleRangeCheck); if (!turretTarget.IsValid) { return false; } aI.targets = new Dictionary { { 0, turretTarget.IsPlayer ? ((Component)turretTarget.Player).gameObject : ((Component)turretTarget.Enemy).gameObject } }; return true; } public static bool SetTargetToEnemyBody(ref Turret __instance) { if ((Object)(object)__instance == (Object)null) { return false; } FAIR_AI aI = GetAI(__instance); SyncTargetTransform(__instance, aI, GetCurrentTarget(__instance, aI)); return false; } public static bool TurnTowardsTargetEnemyIfHasLOS(ref Turret __instance) { if ((Object)(object)__instance == (Object)null) { return false; } TurnTowardsTarget(__instance, GetAI(__instance)); return false; } private static void StopAndStartFadeBulletAudio(Turret turret) { FieldInfo field = TurretType.GetField("fadeBulletAudioCoroutine", BindingFlags.Instance | BindingFlags.NonPublic); object? obj = field?.GetValue(turret); Coroutine val = (Coroutine)((obj is Coroutine) ? obj : null); if (val != null) { ((MonoBehaviour)turret).StopCoroutine(val); } MethodInfo method = TurretType.GetMethod("FadeBulletAudio", BindingFlags.Instance | BindingFlags.NonPublic); field?.SetValue(turret, ((MonoBehaviour)turret).StartCoroutine((IEnumerator)method.Invoke(turret, null))); } } namespace FairAI { public class FAIR_AI : NetworkBehaviour { public EnemyAI targetWithRotation; public Dictionary targets; private void Awake() { targetWithRotation = null; } [ClientRpc] public void SwitchedTargetedEnemyClientRpc(Turret turret, EnemyAI enemy, bool setModeToCharging = false) { targetWithRotation = enemy; if (setModeToCharging) { Type typeFromHandle = typeof(Turret); MethodInfo method = typeFromHandle.GetMethod("SwitchTurretMode", BindingFlags.Instance | BindingFlags.NonPublic); method.Invoke(turret, new object[1] { 2 }); } } [ClientRpc] public void RemoveTargetedEnemyClientRpc() { targetWithRotation = null; } } [BepInPlugin("GoldenKitten.FairAI", "Fair AI", "1.5.8")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private const string modGUID = "GoldenKitten.FairAI"; private const string modName = "Fair AI"; private const string modVersion = "1.5.8"; private Harmony harmony = new Harmony("GoldenKitten.FairAI"); private static readonly float onMeshThreshold = 3f; public static Plugin Instance = null; public static ManualLogSource logger; public static List allEnemies; public static List enemies; public static List items; public static List enemyList; public static List itemList; public static List turretSettings; public static Dictionary speeds; public static Dictionary positions; public static Dictionary sinkingValues; public static Dictionary sinkingProgress; public static Assembly codeRebirthAssembly; public static Assembly lethalConfigAssembly; public static Assembly lguAssembly; public static Assembly surfacedAssembly; public static Assembly turretSettingsAssembly; public static Type rubberBootsType; public static PropertyInfo tsBoundConfig; public const string ltModID = "evaisa.lethalthings"; public const string surfacedModID = "Surfaced"; public static bool codeRebirthEnabled = false; public static bool lethalConfigEnabled = false; public static bool lethalThingsEnabled = false; public static bool lguEnabled = false; public static bool playersEnteredInside = false; public static bool roundHasStarted = false; public static bool surfacedEnabled = false; public static bool turretSettingsEnabled = false; public static int wallsAndEnemyLayerMask = 524288; public static int enemyMask = 524288; public static int allHittablesMask; private async void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } logger = Logger.CreateLogSource("GoldenKitten.FairAI"); allEnemies = new List(); enemies = new List(); items = new List(); itemList = new List(); enemyList = new List(); speeds = new Dictionary(); positions = new Dictionary(); sinkingProgress = new Dictionary(); turretSettings = new List(); sinkingValues = new Dictionary(); harmony = new Harmony("GoldenKitten.FairAI"); harmony.PatchAll(typeof(Plugin)); Patch(typeof(RoundManager), "Start", null, typeof(RoundManagerPatch), "PatchStart", isPrefix: false); Patch(typeof(StartOfRound), "Awake", null, typeof(LevelGenManPatch), "PatchAwake", isPrefix: false); Patch(typeof(StartOfRound), "Start", null, typeof(StartOfRoundPatch), "PatchStart", isPrefix: false); Patch(typeof(StartOfRound), "Update", null, typeof(StartOfRoundPatch), "PatchUpdate", isPrefix: false); Patch(typeof(FlowermanAI), "HitEnemy", new Type[4] { typeof(int), typeof(PlayerControllerB), typeof(bool), typeof(int) }, typeof(EnemyAIPatch), "BrackenHitEnemyPatch", isPrefix: true); Patch(typeof(HoarderBugAI), "HitEnemy", new Type[4] { typeof(int), typeof(PlayerControllerB), typeof(bool), typeof(int) }, typeof(EnemyAIPatch), "HoardingBugHitEnemyPatch", isPrefix: true); Patch(typeof(EnemyAI), "KillEnemyOnOwnerClient", new Type[1] { typeof(bool) }, typeof(EnemyAIPatch), "KillEnemyOnOwnerClientPatch", isPrefix: false); Patch(typeof(QuicksandTrigger), "OnTriggerStay", new Type[1] { typeof(Collider) }, typeof(QuickSandPatch), "OnTriggerStayPatch", isPrefix: true); Patch(typeof(QuicksandTrigger), "StopSinkingLocalPlayer", new Type[1] { typeof(PlayerControllerB) }, typeof(QuickSandPatch), "StopSinkingLocalPlayerPatch", isPrefix: true); Patch(typeof(QuicksandTrigger), "OnTriggerExit", new Type[1] { typeof(Collider) }, typeof(QuickSandPatch), "OnTriggerExitPatch", isPrefix: true); Patch(typeof(Turret), "Update", null, typeof(TurretAIPatch), "PatchUpdate", isPrefix: true); Patch(typeof(Turret), "CheckForPlayersInLineOfSight", new Type[2] { typeof(float), typeof(bool) }, typeof(TurretAIPatch), "CheckForTargetsInLOS", isPrefix: true); Patch(typeof(Turret), "SetTargetToPlayerBody", null, typeof(TurretAIPatch), "SetTargetToEnemyBody", isPrefix: true); Patch(typeof(Turret), "TurnTowardsTargetIfHasLOS", null, typeof(TurretAIPatch), "TurnTowardsTargetEnemyIfHasLOS", isPrefix: true); Patch(typeof(Landmine), "SpawnExplosion", new Type[8] { typeof(Vector3), typeof(bool), typeof(float), typeof(float), typeof(int), typeof(float), typeof(GameObject), typeof(bool) }, typeof(MineAIPatch), "PatchSpawnExplosion", isPrefix: false); Patch(typeof(Landmine), "OnTriggerEnter", null, typeof(MineAIPatch), "PatchOnTriggerEnter", isPrefix: false); Patch(typeof(Landmine), "OnTriggerExit", null, typeof(MineAIPatch), "PatchOnTriggerExit", isPrefix: false); Patch(typeof(Landmine), "Detonate", null, typeof(MineAIPatch), "DetonatePatch", isPrefix: false); await WaitForProcess(1); GetTurretSettings(); logger.LogInfo((object)"Fair AI initiated!"); } private void Patch(Type type, string method, Type[] parameters, Type patchType, string patchMethod, bool isPrefix) { CreateHarmonyPatch(harmony, type, method, parameters, patchType, patchMethod, isPrefix); } public static void ImmortalAffected() { if (!GetBool("General", "ImmortalAffected")) { enemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null && e.canDie select e).ToList(); } allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); } public static float[] SpeedAndAccelerationEnemyList(EnemyAICollisionDetect enemy) { if ((Object)(object)enemy?.mainScript?.enemyType == (Object)null) { logger.LogWarning((object)"No valid enemy to get speeds!"); return new float[2] { 1f, 1f }; } string key = RemoveInvalidCharacters(enemy.mainScript.enemyType.enemyName); if (speeds.TryGetValue(key, out var value)) { return value; } NavMeshAgent componentInChildren = ((Component)enemy.mainScript).GetComponentInChildren(); float[] array = ((!((Object)(object)componentInChildren != (Object)null)) ? new float[2] { 1f, 1f } : new float[2] { componentInChildren.speed, componentInChildren.acceleration }); speeds[key] = array; return array; } public static float[] GetSpeeds(string name) { if (speeds.TryGetValue(name, out var value)) { return value; } logger.LogWarning((object)("Speeds missing on: " + name)); return null; } public static void GetTurretSettings() { if (!turretSettingsEnabled) { turretSettings = new List(8) { 50f, 0.21f, 0f, 7f, 0f, 28f, 95f, 77f }; return; } object value = tsBoundConfig.GetValue(null); if (value == null) { logger.LogInfo((object)"Unable to get BoundConfig"); return; } Type type = value.GetType(); turretSettings.Clear(); string[] array = new string[8] { "turretDamage", "turretFireRate", "turretWarmupTime", "turretRotateTimer", "turretRotationRange", "turretIdleRotationSpeed", "turretFiringRotationSpeed", "turretBerzerkRotationSpeed" }; string[] array2 = array; foreach (string name in array2) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public); if (!(field == null)) { object value2 = field.GetValue(value); PropertyInfo propertyInfo = value2?.GetType().GetProperty("Value"); if (!(propertyInfo == null)) { object value3 = propertyInfo.GetValue(value2); turretSettings.Add((value3 is int num) ? ((float)num) : ((float)value3)); } } } logger.LogInfo((object)$"Got Turret Settings: {turretSettings.Count}"); } public static async Task> WaitForProcess(int waitTime) { await Task.Delay(waitTime); await Instance.DelayedInitialization(); return Array.Empty(); } private async Task DelayedInitialization() { await Task.Run(delegate { TryLoadCodeRebirth(); TryLoadLategameUpgrades(); TryLoadLethalConfig(); TryLoadLethalThings(); TryLoadSurfaced(); TryLoadTurretSettings(); logger.LogInfo((object)"Optional Components initiated!"); }); } private void TryLoadLethalThings() { TryLoadAssembly("LethalThings", ref lethalThingsEnabled, delegate(Assembly assembly) { Type type = assembly.GetType("LethalThings.RoombaAI"); if (!(type == null) && BoombaPatch.enabled) { Patch(type, "Start", null, typeof(BoombaPatch), "PatchStart", isPrefix: false); Patch(type, "DoAIInterval", null, typeof(BoombaPatch), "PatchDoAIInterval", isPrefix: false); lethalThingsEnabled = true; } }); } private void TryLoadSurfaced() { TryLoadAssembly("Surfaced", ref surfacedEnabled, delegate(Assembly assembly) { surfacedAssembly = assembly; if (SurfacedMinePatch.enabled) { Type type = assembly.GetType("Seamine"); if (type != null) { Patch(type, "OnTriggerEnter", new Type[1] { typeof(Collider) }, typeof(SurfacedMinePatch), "PatchOnTriggerEnter", isPrefix: false); surfacedEnabled = true; logger.LogInfo((object)"Surfaced Component Seamine Initiated!"); } Type type2 = assembly.GetType("Bertha"); if (type2 != null) { Patch(type2, "OnTriggerEnter", new Type[1] { typeof(Collider) }, typeof(SurfacedMinePatch), "PatchBerthaOnTriggerEnter", isPrefix: false); surfacedEnabled = true; logger.LogInfo((object)"Surfaced Component Bertha Initiated!"); } } }); } private void TryLoadTurretSettings() { try { Assembly assembly = Assembly.Load("TheNameIsTyler.TurretSettings"); if (!(assembly == null)) { turretSettingsAssembly = assembly; PropertyInfo propertyInfo = assembly.GetType("TurretSettings.TurretSettings")?.GetProperty("BoundConfig", BindingFlags.Static | BindingFlags.NonPublic); if (propertyInfo != null) { tsBoundConfig = propertyInfo; turretSettingsEnabled = true; logger.LogInfo((object)"TurretSettings Component Initiated!"); } } } catch (Exception e) { LogOptionalError("TurretSettings", e); } } private void TryLoadLategameUpgrades() { try { Assembly assembly = Assembly.Load("MoreShipUpgrades"); if (!(assembly == null)) { lguAssembly = assembly; Type type = assembly.GetType("MoreShipUpgrades.UpgradeComponents.TierUpgrades.Player.RubberBoots"); if (type?.GetMethod("ReduceMovementHinderance") != null) { rubberBootsType = type; lguEnabled = true; logger.LogInfo((object)"LategameUpgrades Component Initiated!"); } } } catch (Exception e) { LogOptionalError("LategameUpgrades", e); } } private void TryLoadLethalConfig() { TryLoadAssembly("LethalConfig", ref lethalConfigEnabled, delegate(Assembly assembly) { lethalConfigAssembly = assembly; if (assembly.GetType("LethalConfig.LethalConfigManager") != null) { lethalConfigEnabled = true; logger.LogInfo((object)"LethalConfig Component Initiated!"); } }); } private void TryLoadCodeRebirth() { TryLoadAssembly("CodeRebirth", ref codeRebirthEnabled, delegate(Assembly assembly) { codeRebirthAssembly = assembly; if (assembly.GetType("CodeRebirth.CodeRebirthEnemyKeys.CutieFly") != null) { codeRebirthEnabled = true; logger.LogInfo((object)"CodeRebirth Component Initiated!"); } }); } private void TryLoadAssembly(string assemblyName, ref bool enabledFlag, Action onFound) { try { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == assemblyName); if (assembly != null) { onFound(assembly); } else { logger.LogWarning((object)(assemblyName + " assembly not found. Skipping optional patch.")); } } catch (Exception e) { LogOptionalError(assemblyName, e); } } private static void LogOptionalError(string name, Exception e) { if (!e.Message.Contains("Could not load the file")) { logger.LogError((object)("An error occurred while trying to apply patches for " + name + ": " + e.Message)); } } public static List GetActivePlayers() { return StartOfRound.Instance.allPlayerScripts.Where((PlayerControllerB p) => (Object)(object)p != (Object)null && !p.isPlayerDead && ((Behaviour)p).isActiveAndEnabled && p.isPlayerControlled).ToList(); } public static bool AllowFairness(Vector3 position) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0065: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null) { return true; } if (!Can("CheckForPlayersInside")) { return true; } if (!StartOfRound.Instance.shipHasLanded) { return true; } if (!IsAPlayersOutside()) { goto IL_006d; } if (!(position.y > -80f)) { Bounds bounds = StartOfRound.Instance.shipInnerRoomBounds.bounds; if (!((Bounds)(ref bounds)).Contains(position)) { goto IL_006d; } } int result = 1; goto IL_0075; IL_006d: result = (playersEnteredInside ? 1 : 0); goto IL_0075; IL_0075: return (byte)result != 0; } public static bool IsAPlayersOutside() { if (!StartOfRound.Instance.shipHasLanded) { return false; } return GetActivePlayers().Any((PlayerControllerB p) => !p.isInsideFactory); } public static bool IsAPlayerInsideShip() { if (!StartOfRound.Instance.shipHasLanded) { return false; } return GetActivePlayers().Any((PlayerControllerB p) => p.isInHangarShipRoom); } public static bool IsAPlayerInsideDungeon() { if (!StartOfRound.Instance.shipHasLanded) { return false; } return GetActivePlayers().Any((PlayerControllerB p) => p.isInsideFactory); } public static bool CanMob(string parentIdentifier, string identifier, string mobName) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!((BaseUnityPlugin)Instance).Config[new ConfigDefinition("Mobs", parentIdentifier)].BoxedValue.ToString().Equals("TRUE", StringComparison.OrdinalIgnoreCase)) { return false; } string text = RemoveInvalidCharacters(mobName).ToUpper(); string target = RemoveInvalidCharacters(text + identifier).ToUpper(); return ((BaseUnityPlugin)Instance).Config.Keys.Where((ConfigDefinition e) => RemoveInvalidCharacters(e.Key.ToUpper()) == target).Any((ConfigDefinition e) => ((BaseUnityPlugin)Instance).Config[e].BoxedValue.ToString().Equals("TRUE", StringComparison.OrdinalIgnoreCase)); } public static bool Can(string identifier) { string target = RemoveInvalidCharacters(identifier.ToUpper()); return ((BaseUnityPlugin)Instance).Config.Keys.Where((ConfigDefinition e) => RemoveInvalidCharacters(e.Key.ToUpper()) == target).Any((ConfigDefinition e) => ((BaseUnityPlugin)Instance).Config[e].BoxedValue.ToString().Equals("TRUE", StringComparison.OrdinalIgnoreCase)); } public static int GetInt(string parentIdentifier, string identifier) { try { int.TryParse(((BaseUnityPlugin)Instance).Config[parentIdentifier, identifier].BoxedValue.ToString(), out var result); return result; } catch { return 1; } } public static float GetFloat(string parentIdentifier, string identifier) { try { float.TryParse(((BaseUnityPlugin)Instance).Config[parentIdentifier, identifier].BoxedValue.ToString(), out var result); return result; } catch { return 1f; } } public static bool GetBool(string parentIdentifier, string identifier) { return ((BaseUnityPlugin)Instance).Config[parentIdentifier, identifier].BoxedValue.ToString().Equals("TRUE", StringComparison.OrdinalIgnoreCase); } public static string RemoveWhitespaces(string source) { return string.Join("", source.Split((string[]?)null, StringSplitOptions.RemoveEmptyEntries)); } public static string RemoveSpecialCharacters(string source) { StringBuilder stringBuilder = new StringBuilder(); foreach (char c in source) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(c); } } return stringBuilder.ToString(); } public static string RemoveInvalidCharacters(string source) { return RemoveWhitespaces(RemoveSpecialCharacters(source)); } public static Type FindType(string fullName) { try { return (from a in AppDomain.CurrentDomain.GetAssemblies() where !a.IsDynamic select a).SelectMany((Assembly a) => a.GetTypes()).FirstOrDefault((Type t) => t.FullName.Equals(fullName)); } catch { return null; } } public static void CreateHarmonyPatch(Harmony harmony, Type typeToPatch, string methodToPatch, Type[] parameters, Type patchType, string patchMethod, bool isPrefix, bool isTranspiler = false) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown if (typeToPatch == null || patchType == null) { logger.LogInfo((object)"Type is either incorrect or does not exist!"); return; } MethodInfo methodInfo = AccessTools.Method(typeToPatch, methodToPatch, parameters, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(patchType, patchMethod, (Type[])null, (Type[])null); if (isTranspiler) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null); } else if (isPrefix) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } public static bool IsAgentOnNavMesh(GameObject agentObject) { //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_000d: 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_002e: 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_0047: 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_0060: Unknown result type (might be due to invalid IL or missing references) Vector3 position = agentObject.transform.position; NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(position, ref val, onMeshThreshold, -1)) { return false; } return Mathf.Approximately(position.x, ((NavMeshHit)(ref val)).position.x) && Mathf.Approximately(position.z, ((NavMeshHit)(ref val)).position.z) && position.y >= ((NavMeshHit)(ref val)).position.y; } public static List GetTargets(FAIR_AI turret_ai, Vector3 aimPoint, Vector3 forward, float range) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0064: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) List list = new List(); HashSet hashSet = new HashSet(); float num = ((Component)turret_ai).GetComponent()?.rotationRange ?? 45f; int num2 = 7; Vector3 val = Quaternion.Euler(0f, (0f - num) / 3f, 0f) * forward; float num3 = num / 3f * 2f / (float)(num2 - 1); Ray val2 = default(Ray); IHittable val5 = default(IHittable); EnemyAI val7 = default(EnemyAI); for (int i = 0; i < num2; i++) { ((Ray)(ref val2))..ctor(aimPoint, val); RaycastHit[] array = Physics.RaycastAll(val2, range, -5, (QueryTriggerInteraction)2); Array.Sort(array, (RaycastHit x, RaycastHit y) => ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance)); Vector3 val3 = aimPoint + val * range; RaycastHit[] array2 = array; for (int j = 0; j < array2.Length; j++) { RaycastHit val4 = array2[j]; Transform transform = ((RaycastHit)(ref val4)).transform; if (((Component)transform).TryGetComponent(ref val5)) { EnemyAICollisionDetect val6 = (EnemyAICollisionDetect)(object)((val5 is EnemyAICollisionDetect) ? val5 : null); if (val6 != null) { EnemyAI mainScript = val6.mainScript; if ((Object)(object)mainScript != (Object)null && !mainScript.isEnemyDead && mainScript.enemyHP > 0 && hashSet.Add(((Component)transform).gameObject)) { list.Add(((Component)transform).gameObject); } } else if (!(val5 is PlayerControllerB) && !(val5 is SandSpiderWebTrap) && (!(val5 is Turret) || GetBool("TurretConfig", "HitOtherTurrets"))) { val5.Hit(1, val3, (PlayerControllerB)null, false, -1); } val3 = ((RaycastHit)(ref val4)).point; } else { if (((Component)transform).TryGetComponent(ref val7) && !val7.isEnemyDead && val7.enemyHP > 0 && hashSet.Add(((Component)transform).gameObject)) { list.Add(((Component)transform).gameObject); } val3 = ((RaycastHit)(ref val4)).point; } } val = Quaternion.Euler(0f, num3, 0f) * val; } return list; } public static List GetEnemyTargets(List originalTargets) { List list = new List(); EnemyAICollisionDetect item = default(EnemyAICollisionDetect); foreach (GameObject originalTarget in originalTargets) { if ((Object)(object)originalTarget == (Object)null) { continue; } if (originalTarget.TryGetComponent(ref item)) { list.Add(item); continue; } EnemyAICollisionDetect componentInChildren = originalTarget.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { list.Add(componentInChildren); } } return list; } public static bool AttackTargets(FAIR_AI turret_ai, Vector3 aimPoint, Vector3 forward, float range) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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) return HitTargets(GetTargets(turret_ai, aimPoint, forward, range), forward); } public static bool HitTargets(List targets, Vector3 forward) { //IL_00d5: 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_0138: Unknown result type (might be due to invalid IL or missing references) if (!targets.Any()) { return false; } bool result = false; IHittable val3 = default(IHittable); foreach (GameObject target in targets) { if ((Object)(object)target == (Object)null) { continue; } EnemyAI val = target.GetComponent() ?? target.GetComponent()?.mainScript; if ((Object)(object)val != (Object)null) { if (CanMob("TurretDamageAllMobs", ".Turret Damage", val.enemyType.enemyName)) { int @int = GetInt("TurretConfig", "Enemy Damage"); NutcrackerEnemyAI val2 = (NutcrackerEnemyAI)(object)((val is NutcrackerEnemyAI) ? val : null); if (val2 == null || ((EnemyAI)val2).currentBehaviourStateIndex > 0) { val.HitEnemyOnLocalClient(@int, default(Vector3), (PlayerControllerB)null, false, -1); result = true; } } } else if (target.TryGetComponent(ref val3) && !(val3 is PlayerControllerB) && (!(val3 is Turret) || GetBool("TurretConfig", "HitOtherTurrets"))) { val3.Hit(1, forward, (PlayerControllerB)null, true, -1); result = true; } } return result; } } public class Utils { [CompilerGenerated] private sealed class d__2 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Action onComplete; public float timeToWait; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(timeToWait); <>1__state = 1; return true; case 1: <>1__state = -1; onComplete?.Invoke(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static void AddLethalConfigBoolItem(ConfigEntry tempEntry) { Type type = Plugin.lethalConfigAssembly.GetType("LethalConfig.ConfigItems.BoolCheckBoxConfigItem"); ConstructorInfo constructor = type.GetConstructor(new Type[1] { typeof(ConfigEntry) }); object obj = constructor.Invoke(new object[1] { tempEntry }); Type type2 = Plugin.lethalConfigAssembly.GetType("LethalConfig.LethalConfigManager"); MethodInfo method = type2.GetMethod("AddConfigItem", new Type[1] { type.BaseType }); method.Invoke(null, new object[1] { obj }); } public static void AddLethalConfigFloatItem(ConfigEntry tempEntry) { Type type = Plugin.lethalConfigAssembly.GetType("LethalConfig.ConfigItems.FloatInputFieldConfigItem"); ConstructorInfo constructor = type.GetConstructor(new Type[1] { typeof(ConfigEntry) }); object obj = constructor.Invoke(new object[1] { tempEntry }); Type type2 = Plugin.lethalConfigAssembly.GetType("LethalConfig.LethalConfigManager"); MethodInfo method = type2.GetMethod("AddConfigItem", new Type[1] { type.BaseType }); method.Invoke(null, new object[1] { obj }); } [IteratorStateMachine(typeof(d__2))] public static IEnumerator WaitForTime(Action onComplete, float timeToWait) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__2(0) { onComplete = onComplete, timeToWait = timeToWait }; } public static bool WaitInSeconds(float timeToWait, MonoBehaviour objectToTime = null) { if ((Object)(object)objectToTime == (Object)null) { objectToTime = (MonoBehaviour)(object)Plugin.Instance; } bool done = false; objectToTime.StartCoroutine(WaitForTime(delegate { done = true; }, timeToWait)); return done; } public static void SetupConfig() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Expected O, but got Unknown //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Expected O, but got Unknown //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Expected O, but got Unknown //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Expected O, but got Unknown //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Expected O, but got Unknown //IL_052f: Unknown result type (might be due to invalid IL or missing references) //IL_0539: Expected O, but got Unknown //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_0596: Expected O, but got Unknown //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_05f3: Expected O, but got Unknown //IL_0646: Unknown result type (might be due to invalid IL or missing references) //IL_0650: Expected O, but got Unknown //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06ad: Expected O, but got Unknown //IL_0700: Unknown result type (might be due to invalid IL or missing references) //IL_070a: Expected O, but got Unknown //IL_075d: Unknown result type (might be due to invalid IL or missing references) //IL_0767: Expected O, but got Unknown //IL_07ba: Unknown result type (might be due to invalid IL or missing references) //IL_07c4: Expected O, but got Unknown //IL_0817: Unknown result type (might be due to invalid IL or missing references) //IL_0821: Expected O, but got Unknown //IL_08a5: Unknown result type (might be due to invalid IL or missing references) //IL_08af: Expected O, but got Unknown //IL_09d2: Unknown result type (might be due to invalid IL or missing references) //IL_09dc: Expected O, but got Unknown //IL_0a43: Unknown result type (might be due to invalid IL or missing references) //IL_0a4d: Expected O, but got Unknown //IL_0ab4: Unknown result type (might be due to invalid IL or missing references) //IL_0abe: Expected O, but got Unknown //IL_0b25: Unknown result type (might be due to invalid IL or missing references) //IL_0b2f: Expected O, but got Unknown //IL_0b96: Unknown result type (might be due to invalid IL or missing references) //IL_0ba0: Expected O, but got Unknown //IL_0c07: Unknown result type (might be due to invalid IL or missing references) //IL_0c11: Expected O, but got Unknown if (!Plugin.itemList.SequenceEqual(Plugin.items) || Plugin.items.Count == 0) { Plugin.items = Resources.FindObjectsOfTypeAll().ToList(); Plugin.itemList = Plugin.items; } Plugin.allHittablesMask = StartOfRound.Instance.collidersRoomMaskDefaultAndPlayers | 0x280008 | Plugin.enemyMask; if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("General", "ImmortalAffected"))) { ConfigEntry tempEntry = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("General", "ImmortalAffected", false, "If set to on/true immortal enemies will be targeted and trip off traps."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry); } if (Plugin.enemies.Count == 0) { if (!Plugin.GetBool("General", "ImmortalAffected")) { Plugin.enemies = (from e in Resources.FindObjectsOfTypeAll() where e.canDie select e).ToList(); Plugin.allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); Plugin.enemyList = Plugin.enemies; } else { Plugin.enemies = (from e in Resources.FindObjectsOfTypeAll() where (Object)(object)e != (Object)null select e).ToList(); Plugin.allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); Plugin.enemyList = Plugin.enemies; } } else if (!Plugin.enemyList.SequenceEqual(Plugin.enemies)) { if (!Plugin.GetBool("General", "ImmortalAffected")) { Plugin.enemies = (from e in Resources.FindObjectsOfTypeAll() where (Object)(object)e != (Object)null && e.canDie select e).ToList(); Plugin.allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); Plugin.enemyList = Plugin.enemies; } else { Plugin.enemies = (from e in Resources.FindObjectsOfTypeAll() where (Object)(object)e != (Object)null select e).ToList(); Plugin.allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); Plugin.enemyList = Plugin.enemies; } } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("ExplosionConfig", "Damage"))) { ConfigEntry tempEntry2 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("ExplosionConfig", "Damage", 1f, "Damage explosions will do outside the kill radius"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry2); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Quick Sand Config", "Sink Time"))) { ConfigEntry tempEntry3 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Quick Sand Config", "Sink Time", 5f, "Time Until A Enemy Is Considered Sunk And Will Be Killed"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry3); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Quick Sand Config", "Slowing Speed"))) { ConfigEntry tempEntry4 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Quick Sand Config", "Slowing Speed", 33f, "Percentage of Original Speed Enemies Move In Quick Sand"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry4); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("TurretConfig", "Enemy Damage"))) { ConfigEntry tempEntry5 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("TurretConfig", "Enemy Damage", 1f, "Damage Turrets will Do To Enemies"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry5); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("TurretConfig", "Player Damage"))) { ConfigEntry tempEntry6 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("TurretConfig", "Player Damage", 50f, "Damage Turrets will Do To Players"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry6); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("TurretConfig", "HitOtherTurrets"))) { ConfigEntry tempEntry7 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("TurretConfig", "HitOtherTurrets", false, "If turrets can hit other turrets when firing.(Does not make them target other turrets)"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry7); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "QuicksandAllMobs"))) { ConfigEntry tempEntry8 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", "QuicksandAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Quicksand interactions."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry8); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "ExplodeAllMobs"))) { ConfigEntry tempEntry9 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", "ExplodeAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Mines."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry9); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "BoombaAllMobs"))) { ConfigEntry tempEntry10 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", "BoombaAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Boombas."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry10); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "SeamineAllMobs"))) { ConfigEntry tempEntry11 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", "SeamineAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Seamines."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry11); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "BerthaAllMobs"))) { ConfigEntry tempEntry12 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", "BerthaAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Big Berthas."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry12); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "TurretTargetAllMobs"))) { ConfigEntry tempEntry13 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", "TurretTargetAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Be Targeted By Turrets."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry13); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "TurretDamageAllMobs"))) { ConfigEntry tempEntry14 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", "TurretDamageAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Be Killed By Turrets."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry14); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "CheckForPlayersInside"))) { ConfigEntry tempEntry15 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", "CheckForPlayersInside", false, "Whether to check for players inside the dungeon before anything else occurs."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry15); } } foreach (EnemyType allEnemy in Plugin.allEnemies) { string text = Plugin.RemoveInvalidCharacters(allEnemy.enemyName); if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Quicksand Kill"))) { if (allEnemy.canDie) { ConfigEntry tempEntry16 = ((!text.ToLower().Equals("cutieflyai") && !text.ToLower().Equals("cutieflyobj") && !text.ToLower().Equals("cutiefly")) ? ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Quicksand Kill", true, "Is it killable by quicksand?") : ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Quicksand Kill", false, "Is it killable by quicksand?")); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry16); } } else { ConfigEntry tempEntry16 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Quicksand Kill", false, "Is it killable by quicksand?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry16); } } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Mine"))) { ConfigEntry tempEntry17 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Mine", allEnemy.canDie, "Does it set off the landmine or not?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry17); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Seamine"))) { ConfigEntry tempEntry18 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Seamine", allEnemy.canDie, "Does it set off the Surfaced Seamine or not?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry18); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Bertha"))) { ConfigEntry tempEntry19 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Bertha", allEnemy.canDie, "Does it set off the Surfaced Big Bertha or not?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry19); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Boomba"))) { ConfigEntry tempEntry20 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Boomba", allEnemy.canDie, "Does it set off the LethalThings Boomba or not?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry20); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Turret Target"))) { ConfigEntry tempEntry21 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Turret Target", allEnemy.canDie, "Is it targetable by turrets?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry21); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Turret Damage"))) { ConfigEntry tempEntry22 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind("Mobs", text + ".Turret Damage", allEnemy.canDie, "Is it damageable by turrets?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry22); } } } } public static int[] GetLateGameUpgradeTier(string upgradeName) { try { Type type = Plugin.lguAssembly.GetType("MoreShipUpgrades.API.UpgradeApi"); if (type == null) { Plugin.logger.LogError((object)"[FairAI] Could not find UpgradeApi type!"); return Array.Empty(); } MethodInfo method = type.GetMethod("GetRankableUpgradeNodes", BindingFlags.Static | BindingFlags.Public); if (method == null) { Plugin.logger.LogError((object)"[FairAI] Could not find GetRankableUpgradeNodes() method!"); return Array.Empty(); } object obj = method.Invoke(null, null); if (!(obj is IEnumerable enumerable)) { Plugin.logger.LogError((object)"[FairAI] Result is not an IEnumerable!"); return Array.Empty(); } foreach (object item in enumerable) { Type type2 = item.GetType(); PropertyInfo property = type2.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property2 = type2.GetProperty("MaxUpgrade", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property3 = type2.GetProperty("CurrentUpgrade", BindingFlags.Instance | BindingFlags.Public); string text = property?.GetValue(item)?.ToString() ?? "(unknown)"; if (!text.Equals("(unknown)") && text.Equals(upgradeName, StringComparison.OrdinalIgnoreCase)) { int num = (int)(property2?.GetValue(item) ?? ((object)0)); int num2 = (int)(property3?.GetValue(item) ?? ((object)0)); Plugin.logger.LogInfo((object)$"[FairAI] {text} — Current: {num2}, Max: {num}"); return new int[2] { num2, num }; } } } catch (Exception arg) { Plugin.logger.LogError((object)$"[FairAI] Error: {arg}"); } return Array.Empty(); } public static bool ReadSyncedEntryBool(object syncedEntry) { if (syncedEntry == null) { return false; } PropertyInfo property = syncedEntry.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); return property != null && (bool)property.GetValue(syncedEntry); } public static int ReadSyncedEntryInt(object syncedEntry) { if (syncedEntry == null) { return 0; } PropertyInfo property = syncedEntry.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); return (property != null) ? ((int)property.GetValue(syncedEntry)) : 0; } public static float CalculateDecreaseMultiplier() { Type rubberBootsType = Plugin.rubberBootsType; try { Type type = rubberBootsType.Assembly.GetType("MoreShipUpgrades.Misc.Upgrades.BaseUpgrade"); if (type == null) { return 0f; } object obj = type.GetMethod("GetConfiguration", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null); if (obj == null) { return 0f; } object obj2 = obj.GetType().GetProperty("RubberBootsConfiguration", BindingFlags.Instance | BindingFlags.Public)?.GetValue(obj); if (obj2 == null) { return 0f; } object syncedEntry = obj2.GetType().GetProperty("Enabled")?.GetValue(obj2); if (!ReadSyncedEntryBool(syncedEntry)) { return 0f; } MethodInfo method = type.GetMethod("GetActiveUpgrade", BindingFlags.Static | BindingFlags.Public); if (!(bool)method.Invoke(null, new object[1] { "Rubber Boots" })) { return 0f; } object syncedEntry2 = obj2.GetType().GetProperty("InitialEffect")?.GetValue(obj2); object syncedEntry3 = obj2.GetType().GetProperty("IncrementalEffect")?.GetValue(obj2); int num = ReadSyncedEntryInt(syncedEntry2); int num2 = ReadSyncedEntryInt(syncedEntry3); MethodInfo method2 = type.GetMethod("GetUpgradeLevel", BindingFlags.Static | BindingFlags.Public); int num3 = (int)method2.Invoke(null, new object[1] { "Rubber Boots" }) + 1; Plugin.logger.LogWarning((object)("Decrease: " + (float)(num + num2 * num3) / 100f)); return (float)(num + num2 * num3) / 100f; } catch (Exception arg) { Plugin.logger.LogError((object)$"CalculateDecreaseMultiplier reflection failed: {arg}"); return 0f; } } public static int ClearMovementHinderance(int defaultValue) { if (CalculateDecreaseMultiplier() >= 1f) { return 0; } return defaultValue; } public static float ReduceMovementHinderance(float defaultValue) { float num = CalculateDecreaseMultiplier(); return Mathf.Clamp(Mathf.Clamp(1f - num, 0f, 1f) * defaultValue, 1f, 100f); } } } namespace FairAI.Patches { public static class BoombaPatch { private static bool? _enabled; public static bool enabled { get { if (!_enabled.HasValue) { _enabled = Chainloader.PluginInfos.ContainsKey("evaisa.lethalthings"); } return _enabled.Value; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void PatchStart(ref RoombaAI __instance) { ((Component)__instance).gameObject.AddComponent(); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void PatchDoAIInterval(ref RoombaAI __instance) { //IL_0008: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: 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_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.AllowFairness(((Component)__instance).transform.position) || !Plugin.IsAgentOnNavMesh(((Component)__instance).gameObject) || (((EnemyAI)__instance).currentSearch == null && !((EnemyAI)__instance).movingTowardsTargetPlayer) || (!__instance.mineAudio.isPlaying && !__instance.mineFarAudio.isPlaying) || !((Component)__instance).GetComponent().IsActiveBomb()) { return; } Vector3 val = ((Component)__instance).transform.position + Vector3.up; Collider[] array = Physics.OverlapSphere(val, 6f, 2621448, (QueryTriggerInteraction)2); for (int i = 0; i < array.Length; i++) { float num = Vector3.Distance(val, ((Component)array[i]).transform.position); if ((num > 4f && Physics.Linecast(val, ((Component)array[i]).transform.position + Vector3.up * 0.3f, 256, (QueryTriggerInteraction)1)) || !((Object)(object)((Component)array[i]).gameObject.GetComponent() != (Object)null)) { continue; } EnemyAICollisionDetect component = ((Component)array[i]).gameObject.GetComponent(); if (!((Object)(object)((Component)component.mainScript).gameObject != (Object)(object)((Component)__instance).gameObject) || !Plugin.CanMob("BoombaAllMobs", ".Boomba", component.mainScript.enemyType.enemyName)) { continue; } if ((Object)(object)component != (Object)null && ((NetworkBehaviour)component.mainScript).IsOwner && !component.mainScript.isEnemyDead) { Object.Instantiate(StartOfRound.Instance.explosionPrefab, val, Quaternion.Euler(-90f, 0f, 0f), RoundManager.Instance.mapPropsContainer.transform).SetActive(true); if (num < 3f) { component.mainScript.KillEnemyOnOwnerClient(true); } else if (num < 6f) { component.mainScript.HitEnemyOnLocalClient(2, default(Vector3), (PlayerControllerB)null, false, -1); } } if (((NetworkBehaviour)__instance).IsServer) { ((EnemyAI)__instance).KillEnemy(true); } else { ((EnemyAI)__instance).KillEnemyServerRpc(true); } } } } internal class EnemyAIPatch { private static void BaseHitEnemy(EnemyAI ai, int force, PlayerControllerB playerWhoHit, bool playHitSFX, int hitID) { if (!((Object)(object)ai == (Object)null)) { if (playHitSFX && (Object)(object)ai.enemyType.hitBodySFX != (Object)null && !ai.isEnemyDead) { ai.creatureSFX.PlayOneShot(ai.enemyType.hitBodySFX); WalkieTalkie.TransmitOneShotAudio(ai.creatureSFX, ai.enemyType.hitBodySFX, 1f); } if ((Object)(object)ai.creatureVoice != (Object)null) { ai.creatureVoice.PlayOneShot(ai.enemyType.hitEnemyVoiceSFX); } if (ai.debugEnemyAI) { Debug.Log((object)$"Enemy #{ai.thisEnemyIndex} was hit with force of {force}"); } if ((Object)(object)playerWhoHit != (Object)null) { Debug.Log((object)$"Client #{playerWhoHit.playerClientId} hit enemy {((Object)((Component)ai.agent).transform).name} with force of {force}."); } } } public static void KillEnemyOnOwnerClientPatch(EnemyAI __instance, bool overrideDestroy = false) { if (overrideDestroy) { return; } int id = ((Object)__instance).GetInstanceID(); if (Plugin.sinkingProgress.ContainsKey(id)) { ((MonoBehaviour)__instance).StartCoroutine(Utils.WaitForTime(delegate { Plugin.sinkingProgress.Remove(id); Plugin.sinkingValues.Remove(id); Plugin.positions.Remove(id); __instance.KillEnemyOnOwnerClient(true); }, 1f)); } } public static bool BrackenHitEnemyPatch(ref FlowermanAI __instance, int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { BaseHitEnemy((EnemyAI)(object)__instance, force, playerWhoHit, playHitSFX, hitID); if (((EnemyAI)__instance).isEnemyDead) { return false; } FlowermanAI obj = __instance; ((EnemyAI)obj).enemyHP = ((EnemyAI)obj).enemyHP - force; if (((NetworkBehaviour)__instance).IsOwner) { if (((EnemyAI)__instance).enemyHP <= 0) { ((EnemyAI)__instance).KillEnemyOnOwnerClient(false); return false; } if (!Object.op_Implicit((Object)(object)playerWhoHit)) { Plugin.logger.LogDebug((object)"Bracken was hit by another enemy. Not changing its anger meter"); return false; } __instance.angerMeter = 11f; __instance.angerCheckInterval = 1f; __instance.AddToAngerMeter(0.1f); } return false; } public static bool HoardingBugHitEnemyPatch(ref HoarderBugAI __instance, int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { BaseHitEnemy((EnemyAI)(object)__instance, force, playerWhoHit, playHitSFX, hitID); if (((EnemyAI)__instance).isEnemyDead) { return false; } ((EnemyAI)__instance).creatureAnimator.SetTrigger("damage"); if (!Object.op_Implicit((Object)(object)playerWhoHit)) { Plugin.logger.LogDebug((object)"Hoarding bug was hit by another enemy. Not changing its anger meter"); } else { __instance.angryAtPlayer = playerWhoHit; HoarderBugAI obj = __instance; obj.angryTimer += 18f; } HoarderBugAI obj2 = __instance; ((EnemyAI)obj2).enemyHP = ((EnemyAI)obj2).enemyHP - force; if (((NetworkBehaviour)__instance).IsOwner && ((EnemyAI)__instance).enemyHP <= 0) { ((EnemyAI)__instance).KillEnemyOnOwnerClient(false); } return false; } } internal class LevelGenManPatch { public static void PatchAwake(ref LevelGenerationManager __instance) { Utils.SetupConfig(); } } internal class MineAIPatch { [CompilerGenerated] private sealed class d__3 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float waitTime; public Landmine mine; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(waitTime); <>1__state = 1; return true; case 1: <>1__state = -1; if (!((Object)(object)mine == (Object)null)) { if ((Object)(object)((Component)mine).GetComponent() != (Object)null) { ((Component)mine).GetComponent().Despawn(true); } else { Object.Destroy((Object)(object)((Component)mine).gameObject); } } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static void PatchOnTriggerEnter(ref Landmine __instance, Collider other, ref float ___pressMineDebounceTimer) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (Plugin.AllowFairness(((Component)__instance).transform.position)) { EnemyAICollisionDetect component = ((Component)other).gameObject.GetComponent(); if ((Object)(object)component != (Object)null && !component.mainScript.isEnemyDead && Plugin.CanMob("ExplodeAllMobs", ".Mine", component.mainScript.enemyType.enemyName.ToUpper())) { ___pressMineDebounceTimer = 0.5f; __instance.PressMineServerRpc(); } } } public static void PatchOnTriggerExit(ref Landmine __instance, Collider other, ref bool ___sendingExplosionRPC) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (Plugin.AllowFairness(((Component)__instance).transform.position)) { EnemyAICollisionDetect component = ((Component)other).gameObject.GetComponent(); if ((Object)(object)component != (Object)null && !component.mainScript.isEnemyDead && Plugin.CanMob("ExplodeAllMobs", ".Mine", component.mainScript.enemyType.enemyName.ToUpper()) && !__instance.hasExploded) { __instance.SetOffMineAnimation(); ___sendingExplosionRPC = true; __instance.ExplodeMineServerRpc(); } } } public static void DetonatePatch(ref Landmine __instance) { if (!((Object)(object)__instance == (Object)null)) { ((MonoBehaviour)__instance).StartCoroutine(WaitForUpdate(1.5f, __instance)); } } [IteratorStateMachine(typeof(d__3))] public static IEnumerator WaitForUpdate(float waitTime, Landmine mine) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(0) { waitTime = waitTime, mine = mine }; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void PatchSpawnExplosion(Vector3 explosionPosition, bool spawnExplosionEffect = false, float killRange = 1f, float damageRange = 1f, int nonLethalDamage = 50, float physicsForce = 0f, GameObject overridePrefab = null, bool goThroughCar = false) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_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) //IL_0052: 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_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) bool flag = true; Collider[] array = Physics.OverlapSphere(explosionPosition, 6f, 2621448, (QueryTriggerInteraction)2); for (int i = 0; i < array.Length; i++) { float num = Vector3.Distance(explosionPosition, ((Component)array[i]).transform.position); if (num > 4f && Physics.Linecast(explosionPosition, ((Component)array[i]).transform.position + Vector3.up * 0.3f, 256, (QueryTriggerInteraction)1)) { continue; } if (Plugin.surfacedEnabled && Plugin.surfacedAssembly != null) { Type type = Plugin.surfacedAssembly.GetType("Seamine"); if (type != null && (Object)(object)((Component)array[i]).gameObject.GetComponent(type) != (Object)null) { Component component = ((Component)array[i]).gameObject.GetComponent(type); FieldInfo field = type.GetField("mineActivated", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type.GetField("hasExploded", BindingFlags.Instance | BindingFlags.Public); if (!(bool)field2.GetValue(component) || !(bool)field.GetValue(component)) { break; } if (Plugin.AllowFairness(component.transform.position)) { MethodInfo method = type.GetMethod("TriggerMineOnLocalClientByExiting", BindingFlags.Instance | BindingFlags.NonPublic); method.Invoke(component, new object[0]); } } } if (!((Object)(object)((Component)array[i]).gameObject.GetComponent() != (Object)null)) { continue; } EnemyAICollisionDetect component2 = ((Component)array[i]).gameObject.GetComponent(); if ((Object)(object)component2 != (Object)null && ((NetworkBehaviour)component2.mainScript).IsOwner && !component2.mainScript.isEnemyDead) { if (num < killRange) { component2.mainScript.HitEnemyOnLocalClient(component2.mainScript.enemyHP, default(Vector3), (PlayerControllerB)null, false, -1); } else if (num < damageRange) { component2.mainScript.HitEnemyOnLocalClient(Mathf.RoundToInt(Plugin.GetFloat("ExplosionConfig", "Damage")), default(Vector3), (PlayerControllerB)null, false, -1); } } } } } internal class QuickSandPatch { public static bool OnTriggerStayPatch(ref QuicksandTrigger __instance, Collider other) { if (!__instance.isWater && (Object)(object)((Component)other).gameObject.GetComponent() != (Object)null && Plugin.GetBool("Mobs", "QuicksandAllMobs")) { EnemyAICollisionDetect component = ((Component)other).gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { EnemyAI mainScript = component.mainScript; if ((Object)(object)mainScript != (Object)null) { string enemyName = mainScript.enemyType.enemyName; if ((Object)(object)mainScript.agent != (Object)null && (Plugin.GetBool("Mobs", Plugin.RemoveInvalidCharacters(enemyName) + ".Quicksand Kill") || !enemyName.ToLower().Contains("cutiefly"))) { NavMeshAgent agent = mainScript.agent; float[] array = Plugin.SpeedAndAccelerationEnemyList(component); float num = (float)Plugin.GetInt("Quick Sand Config", "Slowing Speed") * 0.01f; if (array.Length != 0) { if (array[0] * num != agent.speed) { agent.speed = array[0] * num; } if (array[1] * num != agent.acceleration) { agent.acceleration = array[1] * num; } } } if (Plugin.GetBool("Mobs", Plugin.RemoveInvalidCharacters(mainScript.enemyType.enemyName) + ".Quicksand Kill")) { SetSinking(component); } } } } QuicksandEventsForPlayer(__instance, other); return false; } public static bool OnTriggerExitPatch(ref QuicksandTrigger __instance, Collider other) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((Component)other).gameObject.GetComponent() != (Object)null && Plugin.GetBool("Mobs", "QuicksandAllMobs")) { EnemyAICollisionDetect component = ((Component)other).gameObject.GetComponent(); EnemyAI mainScript = component.mainScript; int instanceID = ((Object)mainScript).GetInstanceID(); string enemyName = mainScript.enemyType.enemyName; if (!Plugin.positions.TryGetValue(instanceID, out var value)) { return false; } if (Plugin.GetBool("Mobs", Plugin.RemoveInvalidCharacters(enemyName) + ".Quicksand Kill") || !enemyName.ToLower().Contains("cutiefly")) { float[] array = Plugin.SpeedAndAccelerationEnemyList(component); if (array.Length != 0) { mainScript.agent.speed = array[0]; mainScript.agent.acceleration = array[1]; } } if (Plugin.GetBool("Mobs", Plugin.RemoveInvalidCharacters(enemyName) + ".Quicksand Kill")) { ((Component)mainScript).transform.position = new Vector3(((Component)mainScript).transform.position.x, value.y, ((Component)mainScript).transform.position.z); mainScript.SyncPositionToClients(); Plugin.sinkingValues[instanceID] = 0f; Plugin.sinkingProgress[instanceID] = 0f; } } else { __instance.OnExit(other); } return false; } public static bool StopSinkingLocalPlayerPatch(ref QuicksandTrigger __instance, PlayerControllerB playerScript) { if (__instance.sinkingLocalPlayer) { __instance.sinkingLocalPlayer = false; playerScript.sourcesCausingSinking = Mathf.Clamp(playerScript.sourcesCausingSinking - 1, 0, 100); playerScript.isMovementHindered = Mathf.Clamp(playerScript.isMovementHindered - 1, 0, 100); if (Plugin.rubberBootsType != null) { playerScript.hinderedMultiplier = Mathf.Clamp(playerScript.hinderedMultiplier / Utils.ReduceMovementHinderance(__instance.movementHinderance), 1f, 100f); } else { playerScript.hinderedMultiplier = Mathf.Clamp(playerScript.hinderedMultiplier / __instance.movementHinderance, 1f, 100f); } if (playerScript.isMovementHindered == 0 && __instance.isWater) { playerScript.isUnderwater = false; } } return false; } public static void SetSinking(EnemyAICollisionDetect enemy) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) EnemyAI mainScript = enemy.mainScript; int instanceID = ((Object)mainScript).GetInstanceID(); if (!Plugin.sinkingProgress.ContainsKey(instanceID)) { Plugin.sinkingProgress.Add(instanceID, 0f); } if (!Plugin.positions.ContainsKey(instanceID)) { Plugin.positions.Add(instanceID, ((Component)enemy).transform.position); } if (!Plugin.sinkingValues.ContainsKey(instanceID)) { Plugin.sinkingValues.Add(instanceID, 0f); } float num = Plugin.sinkingValues[instanceID]; if (num < Plugin.GetFloat("Quick Sand Config", "Sink Time")) { Bounds bounds = ((Component)enemy).GetComponent().bounds; float y = ((Bounds)(ref bounds)).size.y; float num2 = y * 0.5f; Plugin.sinkingProgress[instanceID] = Mathf.Clamp(Time.deltaTime / Plugin.GetFloat("Quick Sand Config", "Sink Time") / num2, 0f, 1f); Transform transform = ((Component)mainScript).transform; Vector3 position = transform.position; Vector3 val = position - Vector3.up * y; transform.position = Vector3.Lerp(position, val, Plugin.sinkingProgress[instanceID]); mainScript.SyncPositionToClients(); num = Mathf.Clamp(num + Time.deltaTime * 0.75f, 0f, Plugin.GetFloat("Quick Sand Config", "Sink Time")); if (Plugin.sinkingValues[instanceID] >= Plugin.GetFloat("Quick Sand Config", "Sink Time") - 0.01f) { mainScript.KillEnemyOnOwnerClient(mainScript.enemyType.destroyOnDeath); } if (!mainScript.isEnemyDead) { Plugin.sinkingValues[instanceID] = num; } } } public static void QuicksandEventsForPlayer(QuicksandTrigger trigger, Collider other) { if (trigger.isWater && ((Component)other).gameObject.CompareTag("Player")) { PlayerControllerB component = ((Component)other).gameObject.GetComponent(); if ((Object)(object)component != (Object)(object)GameNetworkManager.Instance.localPlayerController && (Object)(object)component != (Object)null && (Object)(object)component.underwaterCollider != (Object)(object)trigger) { component.underwaterCollider = ((Component)trigger).gameObject.GetComponent(); return; } } if (!trigger.isWater && !((Component)other).gameObject.CompareTag("Player")) { return; } PlayerControllerB component2 = ((Component)other).gameObject.GetComponent(); if ((Object)(object)component2 != (Object)(object)GameNetworkManager.Instance.localPlayerController) { return; } if ((trigger.isWater && component2.isInsideFactory != trigger.isInsideWater) || component2.isInElevator) { if (trigger.sinkingLocalPlayer) { trigger.StopSinkingLocalPlayer(component2); } return; } if (trigger.isWater && !component2.isUnderwater) { component2.underwaterCollider = ((Component)trigger).gameObject.GetComponent(); component2.isUnderwater = true; } component2.statusEffectAudioIndex = trigger.audioClipIndex; if (component2.isSinking) { return; } if (trigger.sinkingLocalPlayer) { if (!component2.CheckConditionsForSinkingInQuicksand()) { trigger.StopSinkingLocalPlayer(component2); } } else { if (!component2.CheckConditionsForSinkingInQuicksand()) { return; } Debug.Log((object)"Set local player to sinking!"); float movementHinderance = trigger.movementHinderance; trigger.sinkingLocalPlayer = true; component2.sourcesCausingSinking++; if (Plugin.rubberBootsType != null) { float num = Mathf.Clamp(1f - Utils.CalculateDecreaseMultiplier(), 0f, 1f); if (num == 0f) { Utils.ClearMovementHinderance(1); } else { component2.hinderedMultiplier = num; component2.isMovementHindered++; } Plugin.logger.LogWarning((object)("BootsMoveHinder: " + component2.isMovementHindered + " BootsHindMult: " + component2.hinderedMultiplier)); } else { component2.isMovementHindered++; component2.hinderedMultiplier *= movementHinderance; Plugin.logger.LogWarning((object)("MoveHinder: " + component2.isMovementHindered + " HindMult: " + component2.hinderedMultiplier)); } if (trigger.isWater) { component2.sinkingSpeedMultiplier = 0f; } else { component2.sinkingSpeedMultiplier = trigger.sinkingSpeedMultiplier; } } } } internal class RoundManagerPatch { public static void PatchStart(ref RoundManager __instance) { Utils.SetupConfig(); } } internal class StartOfRoundPatch { public static void PatchStart(ref StartOfRound __instance) { Utils.SetupConfig(); } public static void PatchUpdate(ref StartOfRound __instance) { if (Plugin.Can("CheckForPlayersInside")) { if (__instance.shipIsLeaving) { Plugin.playersEnteredInside = false; } else { Plugin.playersEnteredInside = Plugin.IsAPlayerInsideDungeon(); } } if (__instance.shipHasLanded && !Plugin.roundHasStarted) { Plugin.speeds = new Dictionary(); Plugin.roundHasStarted = true; } if (__instance.shipIsLeaving) { Plugin.roundHasStarted = false; } } } public static class SurfacedMinePatch { private static bool? _enabled; public static bool enabled { get { if (!_enabled.HasValue) { _enabled = Chainloader.PluginInfos.ContainsKey("Surfaced"); } return _enabled.Value; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void PatchBerthaOnTriggerEnter(ref Bertha __instance, Collider other) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) Type typeFromHandle = typeof(Bertha); if (!__instance.hasExploded && Plugin.AllowFairness(((Component)__instance).transform.position)) { EnemyAICollisionDetect component = ((Component)other).gameObject.GetComponent(); if ((Object)(object)component != (Object)null && !component.mainScript.isEnemyDead && Plugin.CanMob("BerthaAllMobs", ".Bertha", component.mainScript.enemyType.enemyName.ToUpper())) { MethodInfo method = typeFromHandle.GetMethod("TriggerMineOnLocalClientByExiting", BindingFlags.Instance | BindingFlags.NonPublic); method.Invoke(__instance, new object[1] { -1 }); } } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void PatchOnTriggerEnter(ref Seamine __instance, Collider other) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) Type typeFromHandle = typeof(Seamine); FieldInfo field = typeFromHandle.GetField("mineActivated", BindingFlags.Instance | BindingFlags.NonPublic); if (!__instance.hasExploded && (bool)field.GetValue(__instance) && Plugin.AllowFairness(((Component)__instance).transform.position)) { EnemyAICollisionDetect component = ((Component)other).gameObject.GetComponent(); if ((Object)(object)component != (Object)null && !component.mainScript.isEnemyDead && Plugin.CanMob("SeamineAllMobs", ".Seamine", component.mainScript.enemyType.enemyName.ToUpper())) { MethodInfo method = typeFromHandle.GetMethod("TriggerMineOnLocalClientByExiting", BindingFlags.Instance | BindingFlags.NonPublic); method.Invoke(__instance, Array.Empty()); } } } } } namespace FairAI.Component { internal class BoombaTimer : MonoBehaviour { [CompilerGenerated] private sealed class d__2 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public BoombaTimer <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this.SetActiveBomb(isActive: false); <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this.SetActiveBomb(isActive: true); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private bool isActiveBomb = false; private void Start() { ((MonoBehaviour)this).StartCoroutine(StartBombTimer()); Plugin.logger.LogInfo((object)"Boomba has been set active."); } [IteratorStateMachine(typeof(d__2))] public IEnumerator StartBombTimer() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__2(0) { <>4__this = this }; } public void SetActiveBomb(bool isActive) { isActiveBomb = isActive; } public bool IsActiveBomb() { return isActiveBomb; } } }