using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Landfall.TABS; using Landfall.TABS.AI; using Landfall.TABS.AI.Components; using Landfall.TABS.AI.Components.Tags; using Landfall.TABS.AI.Systems; using Landfall.TABS.GameState; using Microsoft.CodeAnalysis; using Unity.Entities; using Unity.Mathematics; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SmarterAI")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SmarterAI")] [assembly: AssemblyTitle("SmarterAI")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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; } } } namespace SmarterAI { public class Bootstrap : MonoBehaviour { private static Bootstrap _instance; private SmartTargetingSystem _system; public static void Ensure() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("SmarterAI_Bootstrap"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent(); } } private void Update() { if (_system == null && World.Active != null) { _system = World.Active.GetOrCreateManager(); } } public static bool InBattle() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 GameStateManager service = ServiceLocator.GetService(); if (service != null) { return (int)service.GameState == 1; } return false; } } public static class MountUtils { private static readonly string[] MountNameKeys = new string[5] { "horse", "raptor", "chariot", "elephant", "mammoth" }; public static string Normalize(string name) { if (string.IsNullOrEmpty(name)) { return ""; } return name.ToLowerInvariant().Replace("prefabs_vb", "").Replace("unitbases_vb", "") .Replace("(clone)", "") .Trim(); } public static bool IsMount(Unit unit) { if ((Object)(object)unit == (Object)null) { return false; } string text = Normalize(((Object)unit).name); for (int i = 0; i < MountNameKeys.Length; i++) { if (text.Contains(MountNameKeys[i])) { return true; } } try { if ((Object)(object)unit.unitBlueprint != (Object)null && (Object)(object)unit.unitBlueprint.UnitBase != (Object)null) { string text2 = Normalize(((Object)unit.unitBlueprint.UnitBase).name); for (int j = 0; j < MountNameKeys.Length; j++) { if (text2.Contains(MountNameKeys[j])) { return true; } } } } catch { } return false; } } [HarmonyPatch(typeof(Unit), "Start")] internal static class UnitStartPatch { private static void Postfix(Unit __instance) { if (Plugin.Enabled.Value && !((Object)(object)__instance == (Object)null)) { if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } bool num = MountUtils.IsMount(__instance) || __instance.IsRider; float value = Plugin.TurnSpeedMultiplier.Value; if (!num && value > 0.01f && value != 1f) { __instance.turnSpeed *= value; } } } } [HarmonyPatch(typeof(UnitAPI), "SetAttackTarget")] internal static class SetAttackTargetPatch { private static void Prefix(UnitAPI __instance, float3 targetPos, Rigidbody mainRig, DataHandler unitData, ref TargetData targetData, ref bool canSeeTarget, bool startAttack) { if (!Plugin.Enabled.Value || (Object)(object)__instance == (Object)null) { return; } Unit component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return; } SmartBrain component2 = ((Component)__instance).GetComponent(); if ((Object)(object)component2 != (Object)null && component2.SuppressAttack) { canSeeTarget = false; } bool num = RangedHelper.IsRanged(component, __instance); if (num && Plugin.ExtendedFireRange.Value && targetData.TargetInAttackRange == 0) { float num2 = RangedHelper.GetAttackRange(component, __instance) * Plugin.FireRangeMult.Value; if (targetData.DistanceToTarget <= num2) { targetData.TargetInAttackRange = 1; if (component.InRangeAttackCooldown > 0f) { component.InRangeAttackCooldown = 0f; } } } if (((num && Plugin.FriendlyFireCheck.Value) & canSeeTarget) && (Object)(object)mainRig != (Object)null && RangedHelper.FriendlyBlocked(__instance, component, mainRig)) { canSeeTarget = false; } } } internal static class RangedHelper { private static readonly List UnitCache = new List(); private static float _nextRefresh; public static bool FriendlyBlocked(UnitAPI api, Unit self, Rigidbody targetRig) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0129: 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_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) Vector3 rightWeaponPosition = api.GetRightWeaponPosition(); Vector3 val = targetRig.position - rightWeaponPosition; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.01f) { return false; } Vector3 val2 = val / magnitude; float value = Plugin.FriendlyObstacleMinDistance.Value; float value2 = Plugin.FriendlyBlockRadius.Value; Team team = self.Team; Transform root = ((Component)self).transform.root; List units = GetUnits(); for (int i = 0; i < units.Count; i++) { Unit val3 = units[i]; if ((Object)(object)val3 == (Object)null || (Object)(object)val3 == (Object)(object)self || val3.Team != team || (Object)(object)val3.data == (Object)null || (Object)(object)val3.data.mainRig == (Object)null || val3.data.Dead || (Object)(object)((Component)val3).transform.root == (Object)(object)root) { continue; } Vector3 position = val3.data.mainRig.position; float num = Vector3.Dot(position - rightWeaponPosition, val2); if (!(num < value) && !(num > magnitude * Plugin.BlockMaxFraction.Value)) { Vector3 val4 = rightWeaponPosition + val2 * num; Vector3 val5 = position - val4; val5.y = 0f; if (!(Mathf.Abs(position.y - val4.y) > 2f) && ((Vector3)(ref val5)).magnitude < value2) { Plugin.Dbg("[SmarterAI] shot blocked by friendly " + ((Object)val3).name); return true; } } } return false; } public static List GetUnits() { if (Time.time >= _nextRefresh) { _nextRefresh = Time.time + 0.5f; UnitCache.Clear(); Unit[] array = Object.FindObjectsOfType(); for (int i = 0; i < array.Length; i++) { UnitCache.Add(array[i]); } } return UnitCache; } public static bool IsRanged(WeaponHandler wh, UnitAPI api) { if ((Object)(object)api != (Object)null && api.IsRangedUnit) { return true; } if ((Object)(object)wh != (Object)null) { if ((Object)(object)wh.rightWeapon != (Object)null && wh.rightWeapon.isRange) { return true; } if ((Object)(object)wh.leftWeapon != (Object)null && wh.leftWeapon.isRange) { return true; } } return false; } public static bool IsRanged(Unit unit, UnitAPI api) { if ((Object)(object)api == (Object)null) { return false; } if (api.IsRangedUnit) { return true; } if ((Object)(object)unit != (Object)null && (Object)(object)unit.WeaponHandler != (Object)null) { return IsRanged(unit.WeaponHandler, api); } return false; } public static float GetAttackRange(Unit unit, UnitAPI api) { float num = 0f; WeaponHandler val = (((Object)(object)unit != (Object)null) ? unit.WeaponHandler : null); if ((Object)(object)val != (Object)null) { if ((Object)(object)val.rightWeapon != (Object)null) { num = Mathf.Max(num, val.rightWeapon.maxRange); } if ((Object)(object)val.leftWeapon != (Object)null) { num = Mathf.Max(num, val.leftWeapon.maxRange); } } if (num <= 0.01f && (Object)(object)api != (Object)null) { num = api.GetAttackRange(); } if (num <= 0.01f && (Object)(object)unit != (Object)null) { num = unit.m_AttackDistance; } return Mathf.Max(0.01f, num); } } [HarmonyPatch(typeof(WeaponHandler), "Attack")] internal static class WeaponAttackRangePatch { private static readonly Dictionary OriginalRanges = new Dictionary(); private static bool IsRangedUnit(WeaponHandler wh, UnitAPI api) { return RangedHelper.IsRanged(wh, api); } private static void Prefix(WeaponHandler __instance) { if (!Plugin.Enabled.Value || !Plugin.ExtendedFireRange.Value || (Object)(object)__instance == (Object)null) { return; } UnitAPI component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && IsRangedUnit(__instance, component)) { float value = Plugin.FireRangeMult.Value; float[] array = new float[2]; int num = 0; if ((Object)(object)__instance.rightWeapon != (Object)null) { array[num++] = __instance.rightWeapon.maxRange; Weapon rightWeapon = __instance.rightWeapon; rightWeapon.maxRange *= value; } if ((Object)(object)__instance.leftWeapon != (Object)null) { array[num++] = __instance.leftWeapon.maxRange; Weapon leftWeapon = __instance.leftWeapon; leftWeapon.maxRange *= value; } OriginalRanges[((Object)__instance).GetInstanceID()] = array; } } private static void Postfix(WeaponHandler __instance) { if (!((Object)(object)__instance == (Object)null) && OriginalRanges.TryGetValue(((Object)__instance).GetInstanceID(), out var value)) { OriginalRanges.Remove(((Object)__instance).GetInstanceID()); int num = 0; if ((Object)(object)__instance.rightWeapon != (Object)null && num < value.Length && value[num] > 0f) { __instance.rightWeapon.maxRange = value[num++]; } if ((Object)(object)__instance.leftWeapon != (Object)null && num < value.Length && value[num] > 0f) { __instance.leftWeapon.maxRange = value[num++]; } } } } [HarmonyPatch(typeof(UnitAPI), "SetLookDirection")] internal static class LookDirectionOverridePatch { private static void Prefix(UnitAPI __instance, ref Vector3 localDirection) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Enabled.Value && !((Object)(object)__instance == (Object)null)) { SmartBrain component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null && component.TryGetDesiredDirection(out var dir)) { localDirection = dir; } } } } [HarmonyPatch(typeof(UnitAPI), "SetMovementSpeed")] internal static class MovementSpeedOverridePatch { private static void Prefix(UnitAPI __instance, ref float movementSpeed) { if (Plugin.Enabled.Value && !((Object)(object)__instance == (Object)null)) { SmartBrain component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null && component.TryGetDesiredSpeed(out var speed)) { movementSpeed = speed; } } } } [HarmonyPatch(typeof(Weapon), "Awake")] internal static class SpreadPatch { private static void Postfix(Weapon __instance) { if (!Plugin.Enabled.Value || (Object)(object)__instance == (Object)null) { return; } RangeWeapon val = (RangeWeapon)(object)((__instance is RangeWeapon) ? __instance : null); if ((Object)(object)val == (Object)null) { return; } if (Plugin.DisableCowardPenalty.Value) { val.extraSpreadInMelee = 0f; val.extraCDInMelee = 0f; } if (Plugin.SpreadEnabled.Value) { float value = Plugin.AddedSpread.Value; if (!(value <= 0f)) { float num = Mathf.Max(0.01f, __instance.maxRange); float num2 = Plugin.SpreadReferenceRange.Value / num; float num3 = value * num2; float spread = val.spread; val.spread = Mathf.Sqrt(spread * spread + num3 * num3); } } } } [BepInPlugin("local.smarterai", "Tactics", "1.12.0")] public class Plugin : BaseUnityPlugin { public const string GUID = "local.smarterai"; public const string Name = "Tactics"; public const string Version = "1.12.0"; public static ManualLogSource Log; public static ConfigEntry Enabled; public static ConfigEntry DebugLog; public static ConfigEntry TurnSpeedMultiplier; public static ConfigEntry SmarterTargeting; public static ConfigEntry CrowdWeight; public static ConfigEntry RetargetInterval; public static ConfigEntry SwitchMargin; public static ConfigEntry RangedThreshold; public static ConfigEntry Spacing; public static ConfigEntry SeparationRadius; public static ConfigEntry SeparationWeight; public static ConfigEntry ObstacleRadius; public static ConfigEntry ObstacleWidth; public static ConfigEntry ObstacleWeight; public static ConfigEntry FlankMinDistance; public static ConfigEntry FlankStrength; public static ConfigEntry ExtendedFireRange; public static ConfigEntry FireRangeMult; public static ConfigEntry RangedKite; public static ConfigEntry FleeRangeMult; public static ConfigEntry FleeMaxDistance; public static ConfigEntry TurnBackDelay; public static ConfigEntry MinFleeTime; public static ConfigEntry TurnCompleteAngle; public static ConfigEntry MaxTurnTime; public static ConfigEntry FleeSpeed; public static ConfigEntry FleeExitBuffer; public static ConfigEntry FleeDistanceFactor; public static ConfigEntry KiteOnlyWithoutMelee; public static ConfigEntry AwaitShotDuration; public static ConfigEntry MinKiteRange; public static ConfigEntry MapClamp; public static ConfigEntry BoundsMargin; public static ConfigEntry DisableCowardPenalty; public static ConfigEntry SpreadEnabled; public static ConfigEntry AddedSpread; public static ConfigEntry SpreadReferenceRange; public static ConfigEntry FriendlyFireCheck; public static ConfigEntry FriendlyObstacleMinDistance; public static ConfigEntry FriendlyBlockRadius; public static ConfigEntry BlockMaxFraction; private void Awake() { //IL_05a8: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Master switch."); DebugLog = ((BaseUnityPlugin)this).Config.Bind("General", "DebugLog", false, "Verbose logging."); TurnSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("General", "TurnSpeedMultiplier", 5f, "Global multiplier on unit turn speed (how fast they rotate to face a new direction)."); SmarterTargeting = ((BaseUnityPlugin)this).Config.Bind("1_Targeting", "Enabled", true, "Melee units re-pick targets preferring enemies that fewer allies already aim at."); CrowdWeight = ((BaseUnityPlugin)this).Config.Bind("1_Targeting", "CrowdWeight", 0.25f, "Weight of 'already targeted by N allies' in target scoring. Vanilla is 0.05. Higher = spread out more."); RetargetInterval = ((BaseUnityPlugin)this).Config.Bind("1_Targeting", "RetargetInterval", 0.6f, "Seconds between target re-picks per unit (prevents path thrashing)."); SwitchMargin = ((BaseUnityPlugin)this).Config.Bind("1_Targeting", "SwitchMargin", 2f, "New target must score this much better than the current one to switch (hysteresis)."); RangedThreshold = ((BaseUnityPlugin)this).Config.Bind("1_Targeting", "RangedThreshold", 5f, "Attack range above which a unit counts as ranged (target re-pick only affects melee)."); Spacing = ((BaseUnityPlugin)this).Config.Bind("2_Spacing", "Enabled", true, "Melee units keep space from nearby units (both teams), steer around blockers, and fan out when approaching."); SeparationRadius = ((BaseUnityPlugin)this).Config.Bind("2_Spacing", "SeparationRadius", 0.4f, "Keep-away radius between units (m)."); SeparationWeight = ((BaseUnityPlugin)this).Config.Bind("2_Spacing", "SeparationWeight", 2.5f, "Strength of the separation push."); ObstacleRadius = ((BaseUnityPlugin)this).Config.Bind("2_Spacing", "ObstacleRadius", 3f, "Units ahead closer than this are treated as path obstacles (m)."); ObstacleWidth = ((BaseUnityPlugin)this).Config.Bind("2_Spacing", "ObstacleWidth", 1.2f, "Lateral corridor half-width for obstacle detection (m)."); ObstacleWeight = ((BaseUnityPlugin)this).Config.Bind("2_Spacing", "ObstacleWeight", 4f, "Strength of obstacle avoidance steer."); FlankMinDistance = ((BaseUnityPlugin)this).Config.Bind("2_Spacing", "FlankMinDistance", 4f, "Beyond this distance to target, melee units add a lateral (flanking) offset (m)."); FlankStrength = ((BaseUnityPlugin)this).Config.Bind("2_Spacing", "FlankStrength", 0f, "Strength of the flanking offset. 0 = off (keeps units on the nav path)."); ExtendedFireRange = ((BaseUnityPlugin)this).Config.Bind("3_RangedFire", "Enabled", true, "Ranged units may open fire at FireRangeMult x range; they still only stand still inside normal range."); FireRangeMult = ((BaseUnityPlugin)this).Config.Bind("3_RangedFire", "FireRangeMult", 1.5f, "Fire range multiplier."); RangedKite = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "Enabled", true, "After a ranged unit attacks while an enemy is within FleeRangeMult x range, it turns and flees until its weapon is ready again."); FleeRangeMult = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "FleeRangeMult", 1.2f, "Flee trigger distance as a multiplier of attack range."); FleeMaxDistance = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "FleeMaxDistance", 15f, "Absolute cap for the flee trigger distance (m), so long-range units do not flee from far-away enemies."); TurnBackDelay = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "TurnBackDelay", 1f, "Seconds to wait facing the enemy before resuming fire after turning back."); MinFleeTime = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "MinFleeTime", 0.6f, "Minimum seconds a unit keeps fleeing once it starts (makes the retreat actually visible)."); TurnCompleteAngle = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "TurnCompleteAngle", 30f, "A unit counts as 'facing' its desired direction below this angle (degrees). Turning happens in place before moving."); MaxTurnTime = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "MaxTurnTime", 0.4f, "After this many seconds of turning in place, the unit starts running even if not fully turned."); FleeSpeed = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "FleeSpeed", 1f, "Movement speed while fleeing."); FleeExitBuffer = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "FleeExitBuffer", 2f, "Fleeing only stops when the closest enemy is beyond trigger distance + this buffer (m)."); FleeDistanceFactor = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "FleeDistanceFactor", 0.5f, "Flee destination = self + away-from-enemy direction * this * attack range. If that point has no ground / is blocked / off-map, the unit does NOT flee."); KiteOnlyWithoutMelee = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "KiteOnlyWithoutMelee", true, "Only units with NO melee weapon kite; units with a melee sidearm keep fighting."); AwaitShotDuration = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "AwaitShotDuration", 1.5f, "Time the unit holds its firing stance (covers attack windup + shot) before it re-evaluates fleeing."); MinKiteRange = ((BaseUnityPlugin)this).Config.Bind("4_Kite", "MinKiteRange", 6f, "Units whose weapon range is below this never kite (keeps short-range 'ranged' units like ninjas fighting in melee)."); MapClamp = ((BaseUnityPlugin)this).Config.Bind("5_MapBounds", "Enabled", true, "Clamp movement destinations to the map circle, keeping units from pathing off the land."); BoundsMargin = ((BaseUnityPlugin)this).Config.Bind("5_MapBounds", "BoundsMargin", 0.5f, "Extra margin inside the map edge (m)."); DisableCowardPenalty = ((BaseUnityPlugin)this).Config.Bind("8_Coward", "Enabled", true, "Disable the vanilla 'coward' mechanic where some shooters get extra spread and longer attack cooldown when enemies are too close."); SpreadEnabled = ((BaseUnityPlugin)this).Config.Bind("7_Spread", "Enabled", true, "Add extra spread to ranged weapons, in quadrature: newSpread = sqrt(old^2 + AddedSpread^2). Low-spread units get a big penalty, high-spread units barely change."); AddedSpread = ((BaseUnityPlugin)this).Config.Bind("7_Spread", "AddedSpread", 3f, "Base quadrature spread. Final added = AddedSpread * (SpreadReferenceRange / weapon range)."); SpreadReferenceRange = ((BaseUnityPlugin)this).Config.Bind("7_Spread", "SpreadReferenceRange", 10f, "Weapon range whose accuracy factor is 1 (roughly a javelin). Longer ranges get a proportionally smaller spread penalty."); FriendlyFireCheck = ((BaseUnityPlugin)this).Config.Bind("6_FriendlyFire", "Enabled", true, "Ranged units treat friendly units further than FriendlyObstacleMinDistance as line-of-sight obstacles."); FriendlyObstacleMinDistance = ((BaseUnityPlugin)this).Config.Bind("6_FriendlyFire", "FriendlyObstacleMinDistance", 1f, "Friendlies closer than this do NOT block the shot (m)."); FriendlyBlockRadius = ((BaseUnityPlugin)this).Config.Bind("6_FriendlyFire", "FriendlyBlockRadius", 0.35f, "A friendly blocks the shot only if its body passes within this distance of the firing line (m)."); BlockMaxFraction = ((BaseUnityPlugin)this).Config.Bind("6_FriendlyFire", "BlockMaxFraction", 0.6f, "Only friendlies within this fraction of the shot distance count as cover."); new Harmony("local.smarterai").PatchAll(); Bootstrap.Ensure(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Tactics 1.12.0 loaded."); } public static void Dbg(string msg) { if (DebugLog != null && DebugLog.Value) { Log.LogInfo((object)msg); } } } public class SmartBrain : MonoBehaviour { private enum FleeState { None, Fleeing, TurnBack, AwaitingShot } private Unit _unit; private UnitAPI _api; private DataHandler _data; private WeaponHandler _wh; private FleeState _flee; private float _turnBackTimer; private float _awaitShotTimer; private float _fleeStartTime; private float _flankSide = 1f; private float _strafeSide = 1f; private bool _blockedCached; private float _nextBlockedCheck; private float _blockedSince = -1f; private float _nextScan; private Vector3 _sepCache; private Vector3 _avoidCache; private Vector3 _headingSmoothed; private Vector3 _fleeDest; private bool _fleeDestValid; private float _nextDestCheck; private static int _mapLayerMask = -2; private int _computedFrame = -1; private bool _hasDirOverride; private bool _hasSpeedOverride; private Vector3 _desiredDir; private float _desiredSpeed; private bool _isMount; private float _nextEnemyScan; private float _closestEnemyDist = float.PositiveInfinity; private Vector3 _closestEnemyPos; private bool _computeLogged; private static int _brainCount; private static int _dirOverrides; private static int _speedOverrides; private static float _nextHeartbeat; public bool SuppressAttack { get { if (_flee != FleeState.Fleeing) { return _flee == FleeState.TurnBack; } return true; } } private static int MapLayerMask { get { if (_mapLayerMask == -2) { _mapLayerMask = LayerMask.GetMask(new string[1] { "Map" }); } return _mapLayerMask; } } private void Start() { _unit = ((Component)this).GetComponent(); _data = ((Component)this).GetComponentInChildren(); _api = ((Component)this).GetComponent(); _wh = ((Component)this).GetComponentInChildren(); if ((Object)(object)_wh == (Object)null && (Object)(object)_unit != (Object)null) { _wh = _unit.WeaponHandler; } _isMount = MountUtils.IsMount(_unit) || ((Object)(object)_unit != (Object)null && _unit.IsRider); Plugin.Log.LogInfo((object)("[SmarterAI] brain attached to " + (((Object)(object)_unit != (Object)null) ? ((Object)_unit).name : ((Object)this).name) + " mount=" + _isMount + " ranged=" + IsRanged())); _brainCount++; int instanceID = ((Object)this).GetInstanceID(); _flankSide = ((instanceID % 3 - 1 >= 0) ? 1f : (-1f)); _strafeSide = ((instanceID % 2 == 0) ? 1f : (-1f)); } private bool IsMount() { if (_isMount) { return true; } return false; } private bool IsRanged() { if ((Object)(object)_api != (Object)null && _api.IsRangedUnit) { return true; } if ((Object)(object)_wh != (Object)null) { if ((Object)(object)_wh.rightWeapon != (Object)null && _wh.rightWeapon.isRange) { return true; } if ((Object)(object)_wh.leftWeapon != (Object)null && _wh.leftWeapon.isRange) { return true; } } return false; } private float GetAttackRange() { return RangedHelper.GetAttackRange(_unit, _api); } private bool HasMeleeWeapon() { if ((Object)(object)_wh != (Object)null) { if ((Object)(object)_wh.rightWeapon != (Object)null && !_wh.rightWeapon.isRange) { return true; } if ((Object)(object)_wh.leftWeapon != (Object)null && !_wh.leftWeapon.isRange) { return true; } } return false; } private void ScanClosestEnemy(Vector3 myPos) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00d7: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextEnemyScan) { return; } _nextEnemyScan = Time.time + 0.15f; _closestEnemyDist = float.PositiveInfinity; Team team = _unit.Team; List units = RangedHelper.GetUnits(); for (int i = 0; i < units.Count; i++) { Unit val = units[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)_unit) && val.Team != team && !((Object)(object)val.data == (Object)null) && !((Object)(object)val.data.mainRig == (Object)null) && !val.data.Dead) { float num = Vector3.Distance(myPos, val.data.mainRig.position); if (num < _closestEnemyDist) { _closestEnemyDist = num; _closestEnemyPos = val.data.mainRig.position; } } } } private float GetFleeTriggerDistance() { return Mathf.Min(GetAttackRange() * Plugin.FleeRangeMult.Value, Plugin.FleeMaxDistance.Value); } private bool WeaponReady() { Weapon val = null; if ((Object)(object)_wh != (Object)null) { val = _wh.rightWeapon; if ((Object)(object)val == (Object)null) { val = _wh.leftWeapon; } } if ((Object)(object)val == (Object)null) { return true; } return val.internalCounter >= val.internalCooldown; } private float FacingAngleTo(Vector3 worldDir) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_data == (Object)null || (Object)(object)_data.characterForwardObject == (Object)null) { return 0f; } Vector3 forward = _data.characterForwardObject.forward; forward.y = 0f; Vector3 val = worldDir; val.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.001f || ((Vector3)(ref val)).sqrMagnitude < 0.001f) { return 0f; } return Vector3.Angle(forward, val); } private bool ComputeFleeDestination(Vector3 myPos, Vector3 enemyPos, out Vector3 dest) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00c9: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) Vector3 val = myPos - enemyPos; val.y = 0f; dest = Vector3.zero; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { return false; } ((Vector3)(ref val)).Normalize(); dest = myPos + val * (GetAttackRange() * Plugin.FleeDistanceFactor.Value); if ((Object)(object)MapSettings.Instance != (Object)null) { Vector3 mapCenter = MapSettings.Instance.m_mapCenter; float num = MapSettings.Instance.m_mapRadius - Plugin.BoundsMargin.Value; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(dest.x - mapCenter.x, dest.z - mapCenter.z); if (((Vector2)(ref val2)).magnitude > num) { return false; } } RaycastHit[] array = Physics.RaycastAll(dest + Vector3.up * 8f, Vector3.down, 25f); if (array == null || array.Length == 0) { return false; } bool flag = false; for (int i = 0; i < array.Length; i++) { RaycastHit val3 = array[i]; if (!((Object)(object)((RaycastHit)(ref val3)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent() != (Object)null) && !(((RaycastHit)(ref val3)).point.y < myPos.y - 2.5f)) { flag = true; break; } } if (!flag) { return false; } int mapLayerMask = MapLayerMask; if (mapLayerMask != 0) { Vector3 val4 = myPos + Vector3.up * 0.6f; Vector3 val5 = dest - val4; val5.y = 0f; float magnitude = ((Vector3)(ref val5)).magnitude; if (magnitude > 0.01f && Physics.Raycast(val4, val5 / magnitude, magnitude, mapLayerMask)) { return false; } } return true; } private void RefreshFleeDestination(Vector3 myPos, Vector3 enemyPos) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time < _nextDestCheck)) { _nextDestCheck = Time.time + 0.25f; _fleeDestValid = ComputeFleeDestination(myPos, enemyPos, out _fleeDest); } } public bool TryGetDesiredDirection(out Vector3 dir) { //IL_0008: 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) Compute(); dir = _desiredDir; if (_hasDirOverride) { _dirOverrides++; } return _hasDirOverride; } public bool TryGetDesiredSpeed(out float speed) { Compute(); speed = _desiredSpeed; if (_hasSpeedOverride) { _speedOverrides++; } return _hasSpeedOverride; } private static void Heartbeat(SmartBrain self) { if (Time.time >= _nextHeartbeat) { _nextHeartbeat = Time.time + 5f; Plugin.Log.LogInfo((object)("[SmarterAI] heartbeat brains=" + _brainCount + " dirOverrides/5s=" + _dirOverrides + " speedOverrides/5s=" + _speedOverrides)); _dirOverrides = 0; _speedOverrides = 0; } } private void Compute() { if (_computedFrame == Time.frameCount) { return; } _computedFrame = Time.frameCount; try { ComputeInner(); } catch (Exception ex) { if (!_computeLogged) { _computeLogged = true; Plugin.Log.LogError((object)("[SmarterAI] SmartBrain.Compute error: " + ex)); } } } private void ComputeInner() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_067c: Unknown result type (might be due to invalid IL or missing references) //IL_0681: Unknown result type (might be due to invalid IL or missing references) //IL_069c: Unknown result type (might be due to invalid IL or missing references) //IL_06a2: Unknown result type (might be due to invalid IL or missing references) //IL_06aa: Unknown result type (might be due to invalid IL or missing references) //IL_06b0: Unknown result type (might be due to invalid IL or missing references) //IL_06c8: Unknown result type (might be due to invalid IL or missing references) //IL_06cf: Unknown result type (might be due to invalid IL or missing references) //IL_06d5: Unknown result type (might be due to invalid IL or missing references) //IL_06dc: Unknown result type (might be due to invalid IL or missing references) //IL_06e1: Unknown result type (might be due to invalid IL or missing references) //IL_06e2: Unknown result type (might be due to invalid IL or missing references) //IL_06e7: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0739: Unknown result type (might be due to invalid IL or missing references) //IL_0743: Unknown result type (might be due to invalid IL or missing references) //IL_074c: Unknown result type (might be due to invalid IL or missing references) //IL_0756: Unknown result type (might be due to invalid IL or missing references) //IL_0706: Unknown result type (might be due to invalid IL or missing references) //IL_070b: Unknown result type (might be due to invalid IL or missing references) //IL_0770: Unknown result type (might be due to invalid IL or missing references) //IL_0777: Unknown result type (might be due to invalid IL or missing references) //IL_077c: Unknown result type (might be due to invalid IL or missing references) //IL_077e: Unknown result type (might be due to invalid IL or missing references) //IL_0785: Unknown result type (might be due to invalid IL or missing references) //IL_078d: Unknown result type (might be due to invalid IL or missing references) //IL_0793: Unknown result type (might be due to invalid IL or missing references) //IL_079a: Unknown result type (might be due to invalid IL or missing references) //IL_07a2: Unknown result type (might be due to invalid IL or missing references) //IL_07a7: Unknown result type (might be due to invalid IL or missing references) //IL_07a8: Unknown result type (might be due to invalid IL or missing references) //IL_07ad: Unknown result type (might be due to invalid IL or missing references) //IL_0829: Unknown result type (might be due to invalid IL or missing references) //IL_082e: Unknown result type (might be due to invalid IL or missing references) //IL_0834: Unknown result type (might be due to invalid IL or missing references) //IL_0839: Unknown result type (might be due to invalid IL or missing references) //IL_083f: Unknown result type (might be due to invalid IL or missing references) //IL_0840: Unknown result type (might be due to invalid IL or missing references) //IL_07cc: Unknown result type (might be due to invalid IL or missing references) //IL_07d1: Unknown result type (might be due to invalid IL or missing references) //IL_0887: Unknown result type (might be due to invalid IL or missing references) //IL_088c: Unknown result type (might be due to invalid IL or missing references) //IL_088d: Unknown result type (might be due to invalid IL or missing references) //IL_0892: Unknown result type (might be due to invalid IL or missing references) //IL_0896: Unknown result type (might be due to invalid IL or missing references) //IL_089b: Unknown result type (might be due to invalid IL or missing references) //IL_089d: Unknown result type (might be due to invalid IL or missing references) //IL_08a2: Unknown result type (might be due to invalid IL or missing references) //IL_08a4: Unknown result type (might be due to invalid IL or missing references) //IL_08a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0a39: Unknown result type (might be due to invalid IL or missing references) //IL_0a3b: Unknown result type (might be due to invalid IL or missing references) //IL_0a41: Unknown result type (might be due to invalid IL or missing references) //IL_0a43: Unknown result type (might be due to invalid IL or missing references) //IL_0a72: Unknown result type (might be due to invalid IL or missing references) //IL_0a73: Unknown result type (might be due to invalid IL or missing references) //IL_05da: Unknown result type (might be due to invalid IL or missing references) //IL_05df: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_05f4: Unknown result type (might be due to invalid IL or missing references) //IL_05f9: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Unknown result type (might be due to invalid IL or missing references) //IL_0604: Unknown result type (might be due to invalid IL or missing references) //IL_0609: Unknown result type (might be due to invalid IL or missing references) //IL_0aa8: Unknown result type (might be due to invalid IL or missing references) //IL_0aae: Unknown result type (might be due to invalid IL or missing references) //IL_0ab4: Unknown result type (might be due to invalid IL or missing references) //IL_0ac3: Unknown result type (might be due to invalid IL or missing references) //IL_0ac8: Unknown result type (might be due to invalid IL or missing references) //IL_0ace: Unknown result type (might be due to invalid IL or missing references) //IL_0add: Unknown result type (might be due to invalid IL or missing references) //IL_0ae2: Unknown result type (might be due to invalid IL or missing references) //IL_0a8b: Unknown result type (might be due to invalid IL or missing references) //IL_0a8d: Unknown result type (might be due to invalid IL or missing references) //IL_0a9c: Unknown result type (might be due to invalid IL or missing references) //IL_0aa1: Unknown result type (might be due to invalid IL or missing references) //IL_0628: Unknown result type (might be due to invalid IL or missing references) //IL_062d: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_0ae7: Unknown result type (might be due to invalid IL or missing references) //IL_0459: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_0b1f: Unknown result type (might be due to invalid IL or missing references) //IL_0b26: Unknown result type (might be due to invalid IL or missing references) //IL_0b3b: Unknown result type (might be due to invalid IL or missing references) //IL_0b40: Unknown result type (might be due to invalid IL or missing references) //IL_0b4c: Unknown result type (might be due to invalid IL or missing references) //IL_0b51: Unknown result type (might be due to invalid IL or missing references) //IL_0b17: Unknown result type (might be due to invalid IL or missing references) //IL_0b18: Unknown result type (might be due to invalid IL or missing references) //IL_094e: Unknown result type (might be due to invalid IL or missing references) //IL_0953: Unknown result type (might be due to invalid IL or missing references) //IL_0955: Unknown result type (might be due to invalid IL or missing references) //IL_0956: Unknown result type (might be due to invalid IL or missing references) //IL_0958: Unknown result type (might be due to invalid IL or missing references) //IL_095d: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Unknown result type (might be due to invalid IL or missing references) //IL_09a8: Unknown result type (might be due to invalid IL or missing references) //IL_09aa: Unknown result type (might be due to invalid IL or missing references) //IL_09af: Unknown result type (might be due to invalid IL or missing references) //IL_09b1: Unknown result type (might be due to invalid IL or missing references) //IL_09b3: Unknown result type (might be due to invalid IL or missing references) //IL_0986: Unknown result type (might be due to invalid IL or missing references) //IL_0988: Unknown result type (might be due to invalid IL or missing references) //IL_098c: Unknown result type (might be due to invalid IL or missing references) //IL_099c: Unknown result type (might be due to invalid IL or missing references) //IL_09a1: Unknown result type (might be due to invalid IL or missing references) //IL_09a6: Unknown result type (might be due to invalid IL or missing references) //IL_09cf: Unknown result type (might be due to invalid IL or missing references) //IL_09d1: Unknown result type (might be due to invalid IL or missing references) //IL_09e1: Unknown result type (might be due to invalid IL or missing references) //IL_09e3: Unknown result type (might be due to invalid IL or missing references) //IL_0a02: Unknown result type (might be due to invalid IL or missing references) //IL_0a04: Unknown result type (might be due to invalid IL or missing references) //IL_0a08: Unknown result type (might be due to invalid IL or missing references) //IL_0a18: Unknown result type (might be due to invalid IL or missing references) //IL_0a1d: Unknown result type (might be due to invalid IL or missing references) //IL_0a22: Unknown result type (might be due to invalid IL or missing references) _hasDirOverride = false; _hasSpeedOverride = false; Heartbeat(this); if (!Plugin.Enabled.Value || (Object)(object)_unit == (Object)null || (Object)(object)_data == (Object)null || (Object)(object)_api == (Object)null || _data.Dead || !_api.Active || _api.IsRemotelyControlled || _api.IsPossessed || !Bootstrap.InBattle() || _isMount) { return; } Vector3 val = (((Object)(object)_data.mainRig != (Object)null) ? _data.mainRig.position : ((Component)this).transform.position); Rigidbody targetMainRig = _data.targetMainRig; Vector3 val2 = Vector3.zero; float num = 0f; if ((Object)(object)targetMainRig != (Object)null) { Vector3 val3 = targetMainRig.position - val; val3.y = 0f; num = ((Vector3)(ref val3)).magnitude; if (num > 0.001f) { val2 = val3 / num; } } bool flag = IsRanged(); Vector3 val7; if (flag) { if (Plugin.RangedKite.Value && !IsMount() && GetAttackRange() >= Plugin.MinKiteRange.Value && (!Plugin.KiteOnlyWithoutMelee.Value || !HasMeleeWeapon())) { ScanClosestEnemy(val); float fleeTriggerDistance = GetFleeTriggerDistance(); float num2 = fleeTriggerDistance + Plugin.FleeExitBuffer.Value; bool flag2 = _closestEnemyDist < float.PositiveInfinity; bool flag3 = flag2 && _closestEnemyDist < fleeTriggerDistance; bool flag4 = !flag2 || _closestEnemyDist > num2; if (_flee == FleeState.None && flag3) { RefreshFleeDestination(val, _closestEnemyPos); _nextDestCheck = 0f; RefreshFleeDestination(val, _closestEnemyPos); if (_fleeDestValid) { _flee = FleeState.Fleeing; _fleeStartTime = Time.time; Plugin.Dbg("[SmarterAI] " + ((Object)_unit).name + " starts kiting toward safe ground"); } } if (_flee == FleeState.Fleeing) { if (flag4) { _flee = FleeState.None; } else if (WeaponReady() && Time.time - _fleeStartTime >= Plugin.MinFleeTime.Value) { _flee = FleeState.TurnBack; _turnBackTimer = Plugin.TurnBackDelay.Value; } else if (flag2) { RefreshFleeDestination(val, _closestEnemyPos); if (!_fleeDestValid) { _flee = FleeState.None; return; } Vector3 val4 = _fleeDest - val; val4.y = 0f; if (((Vector3)(ref val4)).sqrMagnitude > 0.04f) { Vector3 worldDir = (_desiredDir = ((Vector3)(ref val4)).normalized); _hasDirOverride = true; bool flag5 = FacingAngleTo(worldDir) <= Plugin.TurnCompleteAngle.Value; bool flag6 = Time.time - _fleeStartTime >= Plugin.MaxTurnTime.Value; _desiredSpeed = ((flag5 || flag6) ? Plugin.FleeSpeed.Value : 0f); _hasSpeedOverride = true; } else { _desiredSpeed = 0f; _hasSpeedOverride = true; } return; } } if (_flee == FleeState.TurnBack) { if (flag4) { _flee = FleeState.None; } else { Vector3 val5 = Vector3.zero; if ((Object)(object)targetMainRig != (Object)null && ((Vector3)(ref val2)).sqrMagnitude > 0.001f) { val5 = val2; } else if (flag2) { val5 = _closestEnemyPos - val; val5.y = 0f; } if (((Vector3)(ref val5)).sqrMagnitude > 0.001f) { _desiredDir = ((Vector3)(ref val5)).normalized; _hasDirOverride = true; _desiredSpeed = 0f; _hasSpeedOverride = true; } if (FacingAngleTo(_desiredDir) <= Plugin.TurnCompleteAngle.Value) { _turnBackTimer -= Time.deltaTime; } if (!(_turnBackTimer <= 0f)) { return; } _flee = FleeState.AwaitingShot; _awaitShotTimer = Plugin.AwaitShotDuration.Value; } } if (_flee == FleeState.AwaitingShot) { if (flag4) { _flee = FleeState.None; } else { Vector3 val6 = Vector3.zero; if ((Object)(object)targetMainRig != (Object)null && ((Vector3)(ref val2)).sqrMagnitude > 0.001f) { val6 = val2; } else if (flag2) { val6 = _closestEnemyPos - val; val6.y = 0f; } if (((Vector3)(ref val6)).sqrMagnitude > 0.001f) { _desiredDir = ((Vector3)(ref val6)).normalized; _hasDirOverride = true; _desiredSpeed = 0f; _hasSpeedOverride = true; } _awaitShotTimer -= Time.deltaTime; if (_awaitShotTimer <= 0f) { _flee = FleeState.None; } } } } if (Plugin.FriendlyFireCheck.Value && (Object)(object)targetMainRig != (Object)null && num > 0.001f && (_flee == FleeState.None || _flee == FleeState.AwaitingShot)) { if (Time.time >= _nextBlockedCheck) { _nextBlockedCheck = Time.time + 0.2f; _blockedCached = RangedHelper.FriendlyBlocked(_api, _unit, targetMainRig); if (_blockedCached && _blockedSince < 0f) { _blockedSince = Time.time; } if (!_blockedCached) { _blockedSince = -1f; } } if (_blockedCached) { if (_blockedSince > 0f && Time.time - _blockedSince > 1.5f) { _strafeSide = 0f - _strafeSide; _blockedSince = Time.time; } val7 = Vector3.Cross(Vector3.up, val2); Vector3 val8 = ((Vector3)(ref val7)).normalized * _strafeSide + val2 * 0.25f; val8.y = 0f; if (((Vector3)(ref val8)).sqrMagnitude > 0.001f) { _desiredDir = ((Vector3)(ref val8)).normalized; _hasDirOverride = true; _dirOverrides++; _desiredSpeed = 1.5f; _hasSpeedOverride = true; } return; } } } if (Plugin.MapClamp.Value && (Object)(object)MapSettings.Instance != (Object)null) { Vector3 mapCenter = MapSettings.Instance.m_mapCenter; float num3 = MapSettings.Instance.m_mapRadius - Plugin.BoundsMargin.Value; Vector2 val9 = default(Vector2); ((Vector2)(ref val9))..ctor(val.x - mapCenter.x, val.z - mapCenter.z); if (((Vector2)(ref val9)).magnitude > num3) { Vector3 val10 = new Vector3(mapCenter.x, val.y, mapCenter.z) - val; val10.y = 0f; if (((Vector3)(ref val10)).sqrMagnitude > 0.001f) { _desiredDir = ((Vector3)(ref val10)).normalized; _hasDirOverride = true; _desiredSpeed = 2f; _hasSpeedOverride = true; } return; } if ((Object)(object)targetMainRig != (Object)null) { Vector2 val11 = default(Vector2); ((Vector2)(ref val11))..ctor(targetMainRig.position.x - mapCenter.x, targetMainRig.position.z - mapCenter.z); if (((Vector2)(ref val11)).magnitude > num3) { Vector2 val12 = ((Vector2)(ref val11)).normalized * num3; Vector3 val13 = new Vector3(mapCenter.x + val12.x, val.y, mapCenter.z + val12.y) - val; val13.y = 0f; if (((Vector3)(ref val13)).sqrMagnitude > 0.001f) { _desiredDir = ((Vector3)(ref val13)).normalized; _hasDirOverride = true; } return; } } } if (!Plugin.Spacing.Value || flag || (Object)(object)targetMainRig == (Object)null || num < 0.001f || _data.distanceToTarget > 20f) { return; } float num4 = GetAttackRange() + 1f; if (num <= num4) { _sepCache = Vector3.zero; _avoidCache = Vector3.zero; _headingSmoothed = val2; return; } if (Time.time >= _nextScan) { _nextScan = Time.time + 0.1f * (0.8f + 0.4f * ((float)(((Object)this).GetInstanceID() & 0x3FF) / 1023f)); val7 = Vector3.Cross(Vector3.up, val2); Vector3 normalized = ((Vector3)(ref val7)).normalized; Vector3 val14 = Vector3.zero; Vector3 val15 = Vector3.zero; float value = Plugin.SeparationRadius.Value; float value2 = Plugin.ObstacleRadius.Value; float value3 = Plugin.ObstacleWidth.Value; List units = RangedHelper.GetUnits(); for (int i = 0; i < units.Count; i++) { Unit val16 = units[i]; if ((Object)(object)val16 == (Object)null || (Object)(object)val16 == (Object)(object)_unit || (Object)(object)val16.data == (Object)null || (Object)(object)val16.data.mainRig == (Object)null || val16.data.Dead) { continue; } Vector3 position = val16.data.mainRig.position; Vector3 val17 = val - position; val17.y = 0f; float magnitude = ((Vector3)(ref val17)).magnitude; if (magnitude < 0.001f) { continue; } if (magnitude < value) { val14 += val17 / magnitude * (1f - magnitude / value); } Vector3 val18 = -val17; float num5 = Vector3.Dot(val18, val2); if (num5 > 0f && num5 < value2 && num5 < num && Mathf.Abs(Vector3.Dot(val18, normalized)) < value3) { float num6 = Mathf.Sign(Vector3.Dot(normalized, val17)); if (num6 == 0f) { num6 = _flankSide; } val15 += normalized * num6 * (1f - num5 / value2); } } _sepCache = val14; _avoidCache = val15; } if (!(((Vector3)(ref _sepCache)).sqrMagnitude > 0.0025f) && !(((Vector3)(ref _avoidCache)).sqrMagnitude > 0.0025f)) { _headingSmoothed = val2; return; } Vector3 val19 = ((((Vector3)(ref _avoidCache)).sqrMagnitude > 0.0025f) ? (val2 * 0.35f + _avoidCache * Plugin.ObstacleWeight.Value + _sepCache * Plugin.SeparationWeight.Value) : (val2 + _sepCache * Plugin.SeparationWeight.Value)); val19.y = 0f; if (!(((Vector3)(ref val19)).sqrMagnitude < 0.001f)) { if (((Vector3)(ref _headingSmoothed)).sqrMagnitude < 0.001f) { _headingSmoothed = val2; } _headingSmoothed = Vector3.Slerp(_headingSmoothed, ((Vector3)(ref val19)).normalized, Mathf.Clamp01(Time.deltaTime * 7f)); _desiredDir = ((Vector3)(ref _headingSmoothed)).normalized; _hasDirOverride = true; } } } public class SmartTargetingSystem : ComponentSystem { private ComponentGroup _units; private ComponentGroup _targets; private readonly Dictionary _nextRetarget = new Dictionary(); private static bool _announced; protected override void OnCreateManager() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) _units = ((ComponentSystemBase)this).GetComponentGroup((ComponentType[])(object)new ComponentType[8] { ComponentType.ReadOnly(), ComponentType.Create(), ComponentType.ReadOnly(), ComponentType.ReadOnly(), ComponentType.ReadOnly(), ComponentType.ReadOnly(), ComponentType.Subtractive(), ComponentType.Subtractive() }); _targets = ((ComponentSystemBase)this).GetComponentGroup((ComponentType[])(object)new ComponentType[9] { ComponentType.ReadOnly(), ComponentType.ReadOnly(), ComponentType.ReadOnly(), ComponentType.ReadOnly(), ComponentType.Create(), ComponentType.ReadOnly(), ComponentType.Create(), ComponentType.Subtractive(), ComponentType.Subtractive() }); } protected override void OnUpdate() { try { OnUpdateInner(); } catch (Exception ex) { Plugin.Log.LogError((object)("[SmarterAI] SmartTargetingSystem error: " + ex)); } } private void OnUpdateInner() { //IL_008d: 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_00ab: 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_00c9: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: 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) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Enabled.Value || !Plugin.SmarterTargeting.Value || !Bootstrap.InBattle()) { return; } if (!_announced) { _announced = true; Plugin.Log.LogInfo((object)"[SmarterAI] SmartTargetingSystem active in battle."); } float value = Plugin.CrowdWeight.Value; TeamSystem existingManager = ((ComponentSystemBase)this).World.GetExistingManager(); float value2 = Plugin.RangedThreshold.Value; float value3 = Plugin.RetargetInterval.Value; float value4 = Plugin.SwitchMargin.Value; float time = Time.time; for (int i = 0; i <= 1; i++) { _units.SetFilter(new Team { Value = i }); _targets.SetFilter(new Team { Value = 1 - i }); EntityArray entityArray = _units.GetEntityArray(); ComponentDataArray componentDataArray = _units.GetComponentDataArray(); ComponentDataArray componentDataArray2 = _units.GetComponentDataArray(); ComponentDataArray componentDataArray3 = _units.GetComponentDataArray(); EntityArray entityArray2 = _targets.GetEntityArray(); ComponentDataArray componentDataArray4 = _targets.GetComponentDataArray(); ComponentDataArray componentDataArray5 = _targets.GetComponentDataArray(); ComponentDataArray componentDataArray6 = _targets.GetComponentDataArray(); if (((EntityArray)(ref entityArray)).Length == 0 || ((EntityArray)(ref entityArray2)).Length == 0) { _units.ResetFilter(); _targets.ResetFilter(); continue; } float[] array = new float[((EntityArray)(ref entityArray2)).Length]; for (int j = 0; j < ((EntityArray)(ref entityArray2)).Length; j++) { array[j] = componentDataArray6[j].Value; } for (int k = 0; k < ((EntityArray)(ref entityArray)).Length; k++) { Range val = componentDataArray3[k]; if (val.AttackRange >= value2) { continue; } if (existingManager != null) { DataHandler dataHandler = existingManager.GetDataHandler(((EntityArray)(ref entityArray))[k]); if ((Object)(object)dataHandler != (Object)null && (Object)(object)dataHandler.unit != (Object)null && (MountUtils.IsMount(dataHandler.unit) || dataHandler.unit.IsRider)) { continue; } } Entity val2 = ((EntityArray)(ref entityArray))[k]; if (_nextRetarget.TryGetValue(val2, out var value5) && time < value5) { Entity target = componentDataArray[k].Target; if (!(target != Entity.Null)) { continue; } for (int l = 0; l < ((EntityArray)(ref entityArray2)).Length; l++) { if (((EntityArray)(ref entityArray2))[l] == target) { array[l] += 1f; break; } } continue; } _nextRetarget[val2] = time + value3 * (0.8f + 0.4f * ((float)(val2.Index & 0x3FF) / 1023f)); float3 value6 = componentDataArray2[k].Value; int num = -1; float num2 = float.MinValue; float num3 = float.MinValue; Entity target2 = componentDataArray[k].Target; for (int m = 0; m < ((EntityArray)(ref entityArray2)).Length; m++) { float num4 = (0f - math.length(componentDataArray4[m].Value - value6)) / componentDataArray5[m].Value - array[m] * val.AttackRange * value; if (((EntityArray)(ref entityArray2))[m] == target2) { num3 = num4; } if (num4 > num2) { num2 = num4; num = m; } } if (num < 0) { continue; } if (target2 != Entity.Null && num3 != float.MinValue && num2 < num3 + value4) { for (int n = 0; n < ((EntityArray)(ref entityArray2)).Length; n++) { if (((EntityArray)(ref entityArray2))[n] == target2) { num = n; break; } } } Entity val3 = ((EntityArray)(ref entityArray2))[num]; if (target2 != val3) { componentDataArray[k] = new HasTargetTag { Target = val3 }; ((ComponentSystemBase)this).EntityManager.SetComponentData(((EntityArray)(ref entityArray2))[num], new IsTarget { Targetee = val2 }); } array[num] += 1f; } _units.ResetFilter(); _targets.ResetFilter(); } } } }