Exemple #1
0
        protected virtual bool ShouldFlee(SquadCA squad, Func <IEnumerable <Actor>, bool> flee)
        {
            if (!squad.IsValid)
            {
                return(false);
            }

            var randomSquadUnit = squad.Units.Random(squad.Random);
            var dangerRadius    = squad.SquadManager.Info.DangerScanRadius;
            var units           = squad.World.FindActorsInCircle(randomSquadUnit.CenterPosition, WDist.FromCells(dangerRadius)).ToList();

            // If there are any own buildings within the DangerRadius, don't flee
            // PERF: Avoid LINQ
            foreach (var u in units)
            {
                if (u.Owner == squad.Bot.Player && u.Info.HasTraitInfo <BuildingInfo>())
                {
                    return(false);
                }
            }

            var enemyAroundUnit = units.Where(unit => squad.SquadManager.IsEnemyUnit(unit) && unit.Info.HasTraitInfo <AttackBaseInfo>());

            if (!enemyAroundUnit.Any())
            {
                return(false);
            }

            return(flee(enemyAroundUnit));
        }
Exemple #2
0
        protected Actor ThreatScan(SquadCA owner, Actor teamLeader, WDist scanRadius)
        {
            var enemies = owner.World.FindActorsInCircle(teamLeader.CenterPosition, scanRadius)
                          .Where(a => owner.SquadManager.IsEnemyUnit(a) && owner.SquadManager.IsNotHiddenUnit(a));

            return(enemies.ClosestTo(teamLeader.CenterPosition));
        }
Exemple #3
0
        protected Actor FindClosestEnemy(SquadCA owner)
        {
            var first = owner.Units.First();

            // Navy squad AI can exploit enemy naval production to find path, if any.
            // (Way better than finding a nearest target which is likely to be on Ground)
            // You might be tempted to move these lookups into Activate() but that causes null reference exception.
            var domainIndex   = first.World.WorldActor.Trait <DomainIndex>();
            var locomotorInfo = first.Info.TraitInfo <MobileInfo>().LocomotorInfo;

            var navalProductions = owner.World.ActorsHavingTrait <Building>().Where(a
                                                                                    => owner.SquadManager.Info.NavalProductionTypes.Contains(a.Info.Name) &&
                                                                                    domainIndex.IsPassable(first.Location, a.Location, locomotorInfo) &&
                                                                                    a.AppearsHostileTo(first));

            if (navalProductions.Any())
            {
                var nearest = navalProductions.ClosestTo(first);

                // Return nearest when it is FAR enough.
                // If the naval production is within MaxBaseRadius, it implies that
                // this squad is close to enemy territory and they should expect a naval combat;
                // closest enemy makes more sense in that case.
                if ((nearest.Location - first.Location).LengthSquared > owner.SquadManager.Info.MaxBaseRadius * owner.SquadManager.Info.MaxBaseRadius)
                {
                    return(nearest);
                }
            }

            return(owner.SquadManager.FindClosestEnemy(first.CenterPosition));
        }
Exemple #4
0
        protected static Actor FindDefenselessTarget(SquadCA owner)
        {
            Actor target = null;

            FindSafePlace(owner, out target, true);
            return(target);
        }
Exemple #5
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            if (!owner.IsTargetValid)
            {
                var closestEnemy = FindClosestEnemy(owner);
                if (closestEnemy != null)
                {
                    owner.TargetActor = closestEnemy;
                }
                else
                {
                    owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsFleeState(), true);
                    return;
                }
            }

            foreach (var a in owner.Units)
            {
                if (!BusyAttack(a))
                {
                    owner.Bot.QueueOrder(new Order("Attack", a, Target.FromCell(owner.World, owner.TargetActor.Location), false));
                }
            }

            if (ShouldFlee(owner))
            {
                owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsFleeState(), true);
            }
        }
Exemple #6
0
        protected static CPos?FindSafePlace(SquadCA owner, out Actor detectedEnemyTarget, bool needTarget)
        {
            var map          = owner.World.Map;
            var dangerRadius = owner.SquadManager.Info.DangerScanRadius;

            detectedEnemyTarget = null;

            var columnCount  = (map.MapSize.X + dangerRadius - 1) / dangerRadius;
            var rowCount     = (map.MapSize.Y + dangerRadius - 1) / dangerRadius;
            var checkIndices = Exts.MakeArray(columnCount * rowCount, i => i).Shuffle(owner.World.LocalRandom);

            foreach (var i in checkIndices)
            {
                var pos = new CPos((i % columnCount) * dangerRadius + dangerRadius / 2, (i / columnCount) * dangerRadius + dangerRadius / 2);
                if (NearToPosSafely(owner, map.CenterOfCell(pos), out detectedEnemyTarget))
                {
                    if (needTarget && detectedEnemyTarget == null)
                    {
                        continue;
                    }

                    return(pos);
                }
            }

            return(null);
        }
Exemple #7
0
        public static SquadCA Deserialize(IBot bot, SquadManagerBotModuleCA squadManager, MiniYaml yaml)
        {
            var   type        = SquadTypeCA.Rush;
            Actor targetActor = null;

            var typeNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Type");

            if (typeNode != null)
            {
                type = FieldLoader.GetValue <SquadTypeCA>("Type", typeNode.Value.Value);
            }

            var targetNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Target");

            if (targetNode != null)
            {
                targetActor = squadManager.World.GetActorById(FieldLoader.GetValue <uint>("ActiveUnits", targetNode.Value.Value));
            }

            var squad = new SquadCA(bot, squadManager, type, targetActor);

            var unitsNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Units");

            if (unitsNode != null)
            {
                squad.Units.AddRange(FieldLoader.GetValue <uint[]>("Units", unitsNode.Value.Value)
                                     .Select(a => squadManager.World.GetActorById(a)));
            }

            return(squad);
        }
Exemple #8
0
        // Retreat units from combat, or for supply only in idle
        protected void Retreat(SquadCA owner, bool resupplyonly)
        {
            // Reload units.
            foreach (var a in owner.Units)
            {
                var ammoPools = a.TraitsImplementing <AmmoPool>().ToArray();
                if (!ReloadsAutomatically(ammoPools, a.TraitOrDefault <Rearmable>()) && !FullAmmo(ammoPools))
                {
                    if (IsRearming(a))
                    {
                        continue;
                    }

                    owner.Bot.QueueOrder(new Order("ReturnToBase", a, false));
                    continue;
                }
                else if (!resupplyonly)
                {
                    owner.Bot.QueueOrder(new Order("Move", a, Target.FromCell(owner.World, RandomBuildingLocation(owner)), false));
                }
            }

            // Repair units. One by one to avoid give out mass orders
            foreach (var a in owner.Units)
            {
                if (IsRearming(a))
                {
                    continue;
                }

                Actor repairBuilding = null;
                var   orderId        = "Repair";
                var   health         = a.TraitOrDefault <IHealth>();

                if (health != null && health.DamageState > DamageState.Undamaged)
                {
                    var repairable = a.TraitOrDefault <Repairable>();
                    if (repairable != null)
                    {
                        repairBuilding = repairable.FindRepairBuilding(a);
                    }
                    else
                    {
                        var repairableNear = a.TraitOrDefault <RepairableNearCA>();
                        if (repairableNear != null)
                        {
                            orderId        = "RepairNear";
                            repairBuilding = repairableNear.FindRepairBuilding(a);
                        }
                    }

                    if (repairBuilding != null)
                    {
                        owner.Bot.QueueOrder(new Order(orderId, a, Target.FromActor(repairBuilding), true));
                        break;
                    }
                }
            }
        }
Exemple #9
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            // rescan target to prevent being ambushed and die without fight
            // return to AttackMove state for formation
            var teamLeader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition);

            if (teamLeader == null)
            {
                return;
            }
            var teamTail         = owner.Units.MaxByOrDefault(a => (a.CenterPosition - owner.TargetActor.CenterPosition).LengthSquared);
            var attackScanRadius = WDist.FromCells(owner.SquadManager.Info.AttackScanRadius);
            var cannotRetaliate  = false;
            var targetActor      = ThreatScan(owner, teamLeader, attackScanRadius) ?? ThreatScan(owner, teamTail, attackScanRadius);

            if (targetActor == null)
            {
                owner.TargetActor = null;
                owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsAttackMoveState(), true);
                return;
            }
            else
            {
                cannotRetaliate   = true;
                owner.TargetActor = targetActor;

                foreach (var a in owner.Units)
                {
                    if (!BusyAttack(a))
                    {
                        if (CanAttackTarget(a, targetActor))
                        {
                            owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false));
                            cannotRetaliate = false;
                        }
                        else
                        {
                            owner.Bot.QueueOrder(new Order("AttackMove", a, Target.FromCell(owner.World, teamLeader.Location), false));
                        }
                    }
                    else
                    {
                        cannotRetaliate = false;
                    }
                }
            }

            if (ShouldFlee(owner) || cannotRetaliate)
            {
                owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsFleeState(), true);
                return;
            }
        }
Exemple #10
0
        public void Tick(SquadCA owner)
        {
            var cannotRetaliate = false;

            // Basic check
            if (!owner.IsValid)
            {
                return;
            }

            TeamLeader = owner.Units.FirstOrDefault();
            if (TeamLeader == null)
            {
                return;
            }

            // Rescan target to prevent being ambushed and die without fight
            // If there is no threat around, return to AttackMove state for formation
            var attackScanRadius = WDist.FromCells(owner.SquadManager.Info.AttackScanRadius);
            var targetActor      = ThreatScan(owner, TeamLeader, attackScanRadius);

            if (targetActor == null)
            {
                owner.TargetActor = GetRandomValuableTarget(owner);
                owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsAttackMoveState(), true);
                return;
            }
            else
            {
                cannotRetaliate   = true;
                owner.TargetActor = targetActor;

                foreach (var a in owner.Units)
                {
                    if (!BusyAttack(a))
                    {
                        if (CanAttackTarget(a, targetActor))
                        {
                            owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false));
                            cannotRetaliate = false;
                        }
                        else
                        {
                            owner.Bot.QueueOrder(new Order("AttackMove", a, Target.FromCell(owner.World, TeamLeader.Location), false));
                        }
                    }
                    else
                    {
                        cannotRetaliate = false;
                    }
                }
            }

            if (ShouldFlee(owner) || cannotRetaliate)
            {
                owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsFleeState(), true);
            }
        }
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            if (!owner.IsTargetValid)
            {
                var closestEnemy = FindClosestEnemy(owner);
                if (closestEnemy != null)
                {
                    owner.TargetActor = closestEnemy;
                }
                else
                {
                    owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsFleeStateCA(), false);
                    return;
                }
            }

            var leader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition);

            if (leader.Location != lastLeaderLocation)
            {
                lastLeaderLocation = leader.Location;
                lastUpdatedTick    = owner.World.WorldTick;
            }

            if (owner.TargetActor != lastTarget)
            {
                lastTarget      = owner.TargetActor;
                lastUpdatedTick = owner.World.WorldTick;
            }

            // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds
            // This works around the squad being stuck trying to attack-move to a location
            // that they cannot path to, generating expensive pathfinding calls each tick.
            if (owner.World.WorldTick > lastUpdatedTick + 63)
            {
                owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsIdleState(), true);
                return;
            }

            foreach (var a in owner.Units)
            {
                if (!BusyAttack(a))
                {
                    owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false));
                }
            }

            if (ShouldFlee(owner))
            {
                owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsFleeStateCA(), false);
            }
        }
Exemple #12
0
        protected static void GoToRandomOwnBuilding(SquadCA squad)
        {
            var loc = RandomBuildingLocation(squad);

            foreach (var a in squad.Units)
            {
                squad.Bot.QueueOrder(new Order("Move", a, Target.FromCell(squad.World, loc), false));
            }
        }
Exemple #13
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            Retreat(owner, true, true, true);
            owner.FuzzyStateMachine.ChangeState(owner, new UnitsForProtectionIdleState(), true);
        }
Exemple #14
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            Retreat(owner, false);
            owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsIdleState(), true);
        }
Exemple #15
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            Retreat(owner, flee: true, rearm: true, repair: true);
            owner.FuzzyStateMachine.ChangeState(owner, new AirIdleStateCA(), false);
        }
Exemple #16
0
        protected Actor GetRandomValuableTarget(SquadCA owner)
        {
            var manager            = owner.SquadManager;
            var mustDestroyedEnemy = manager.World.ActorsHavingTrait <MustBeDestroyed>(t => t.Info.RequiredForShortGame)
                                     .Where(a => manager.IsEnemyUnit(a) && manager.IsNotHiddenUnit(a)).ToArray();

            if (!mustDestroyedEnemy.Any())
            {
                return(FindClosestEnemy(owner));
            }

            return(mustDestroyedEnemy.Random(owner.World.LocalRandom));
        }
Exemple #17
0
        protected static CPos RandomBuildingLocation(SquadCA squad)
        {
            var location  = squad.SquadManager.GetRandomBaseCenter();
            var buildings = squad.World.ActorsHavingTrait <Building>()
                            .Where(a => a.Owner == squad.Bot.Player).ToList();

            if (buildings.Count > 0)
            {
                location = buildings.Random(squad.Random).Location;
            }

            return(location);
        }
Exemple #18
0
        // Retreat units from combat, or for supply only in idle
        protected virtual void Retreat(SquadCA owner, bool resupplyonly)
        {
            // Repair units. One by one to avoid give out mass orders
            var alreadysend = false;

            foreach (var a in owner.Units)
            {
                if (IsRearming(a))
                {
                    continue;
                }

                Actor repairBuilding = null;
                var   orderId        = "Repair";
                var   health         = a.TraitOrDefault <IHealth>();

                if (!alreadysend && health != null && health.DamageState > DamageState.Undamaged)
                {
                    var repairable = a.TraitOrDefault <Repairable>();
                    if (repairable != null)
                    {
                        repairBuilding = repairable.FindRepairBuilding(a);
                    }
                    else
                    {
                        var repairableNear = a.TraitOrDefault <RepairableNearCA>();
                        if (repairableNear != null)
                        {
                            orderId        = "RepairNear";
                            repairBuilding = repairableNear.FindRepairBuilding(a);
                        }
                    }

                    if (repairBuilding != null)
                    {
                        owner.Bot.QueueOrder(new Order(orderId, a, Target.FromActor(repairBuilding), false));
                        alreadysend = true;
                        continue;
                    }
                    else if (!resupplyonly)
                    {
                        owner.Bot.QueueOrder(new Order("Move", a, Target.FromCell(owner.World, RandomBuildingLocation(owner)), false));
                    }
                }
                else if (!resupplyonly)
                {
                    owner.Bot.QueueOrder(new Order("Move", a, Target.FromCell(owner.World, RandomBuildingLocation(owner)), false));
                }
            }
        }
Exemple #19
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            // Check if we have an enemy naval yard this tick
            var first            = owner.Units.First();
            var domainIndex      = first.World.WorldActor.Trait <DomainIndex>();
            var locomotorInfo    = first.Info.TraitInfo <MobileInfo>().LocomotorInfo;
            var navalProductions = owner.World.ActorsHavingTrait <Building>().Where(a
                                                                                    => owner.SquadManager.Info.NavalProductionTypes.Contains(a.Info.Name) &&
                                                                                    domainIndex.IsPassable(first.Location, a.Location, locomotorInfo) &&
                                                                                    a.AppearsHostileTo(first));

            // if target is dead or if we have a newly built naval yard this tick invalidate the current target and select a new one.
            if (!owner.IsTargetValid || (navalProductions.Any() && !hadNavalYard))
            {
                var closestEnemy = FindClosestEnemy(owner);
                if (closestEnemy != null)
                {
                    owner.TargetActor = closestEnemy;
                }
                else
                {
                    owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsFleeState(), true);
                    hadNavalYard = false;
                    return;
                }
            }

            // Save whether we had an Enemy naval yard this tick.
            hadNavalYard = navalProductions.Any();

            foreach (var a in owner.Units)
            {
                owner.Bot.QueueOrder(new Order("AttackMove", a, Target.FromCell(owner.World, owner.TargetActor.Location), false));
            }

            if (ShouldFlee(owner))
            {
                owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsFleeState(), true);
                hadNavalYard = false;
            }
        }
Exemple #20
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            if (!owner.IsTargetValid)
            {
                var closestEnemy = FindClosestEnemy(owner);
                if (closestEnemy == null)
                {
                    return;
                }

                owner.TargetActor = closestEnemy;
            }

            var enemyUnits = owner.World.FindActorsInCircle(owner.TargetActor.CenterPosition, WDist.FromCells(owner.SquadManager.Info.IdleScanRadius))
                             .Where(owner.SquadManager.IsEnemyUnit).ToList();

            if (enemyUnits.Count == 0)
            {
                Retreat(owner, false, true, true);
                return;
            }

            if (AttackOrFleeFuzzyCA.Default.CanAttack(owner.Units, enemyUnits))
            {
                foreach (var u in owner.Units)
                {
                    owner.Bot.QueueOrder(new Order("AttackMove", u, Target.FromCell(owner.World, owner.TargetActor.Location), false));
                }

                // We have gathered sufficient units. Attack the nearest enemy unit.
                owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsAttackMoveState(), true);
            }
            else
            {
                owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsFleeState(), true);
            }
        }
Exemple #21
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            if (!owner.IsTargetValid)
            {
                var closestEnemy = FindClosestEnemy(owner);
                if (closestEnemy == null)
                {
                    return;
                }

                owner.TargetActor = closestEnemy;
            }

            var enemyUnits = owner.World.FindActorsInCircle(owner.TargetActor.CenterPosition, WDist.FromCells(owner.SquadManager.Info.IdleScanRadius))
                             .Where(owner.SquadManager.IsEnemyUnit).ToList();

            if (enemyUnits.Count == 0)
            {
                Retreat(owner, false, true, true);
                return;
            }

            if (AttackOrFleeFuzzyCA.Default.CanAttack(owner.Units, enemyUnits))
            {
                // We have gathered sufficient units. Attack the nearest enemy unit.
                // Inform human allies about AI's rush attack.
                owner.Bot.QueueOrder(new Order("PlaceBeacon", owner.SquadManager.Player.PlayerActor, Target.FromCell(owner.World, owner.TargetActor.Location), false)
                {
                    SuppressVisualFeedback = true
                });
                owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsAttackMoveState(), true);
            }
            else
            {
                owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsFleeState(), true);
            }
        }
Exemple #22
0
        protected static bool NearToPosSafely(SquadCA owner, WPos loc, out Actor detectedEnemyTarget)
        {
            detectedEnemyTarget = null;
            var dangerRadius   = owner.SquadManager.Info.DangerScanRadius;
            var unitsAroundPos = owner.World.FindActorsInCircle(loc, WDist.FromCells(dangerRadius))
                                 .Where(owner.SquadManager.IsPreferredEnemyUnit).ToList();

            if (!unitsAroundPos.Any())
            {
                return(true);
            }

            if (CountAntiAirUnits(unitsAroundPos) < owner.Units.Count)
            {
                detectedEnemyTarget = unitsAroundPos.Random(owner.Random);
                return(true);
            }

            return(false);
        }
Exemple #23
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            if (!owner.IsTargetValid)
            {
                owner.TargetActor = owner.SquadManager.FindClosestEnemy(owner.CenterPosition, WDist.FromCells(owner.SquadManager.Info.ProtectionScanRadius));

                if (owner.TargetActor == null)
                {
                    Retreat(owner, false, true, true);
                    return;
                }
            }

            owner.FuzzyStateMachine.ChangeState(owner, new UnitsForProtectionAttackState(), true);
        }
Exemple #24
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            if (!owner.IsTargetValid)
            {
                var closestEnemy = FindClosestEnemy(owner);
                if (closestEnemy == null)
                {
                    return;
                }

                owner.TargetActor = closestEnemy;
            }

            var enemyUnits = owner.World.FindActorsInCircle(owner.TargetActor.CenterPosition, WDist.FromCells(owner.SquadManager.Info.IdleScanRadius))
                             .Where(owner.SquadManager.IsPreferredEnemyUnit).ToList();

            if (enemyUnits.Count == 0)
            {
                Retreat(owner, flee: false, rearm: true, repair: true);
                return;
            }

            if (AttackOrFleeFuzzyCA.Default.CanAttack(owner.Units, enemyUnits))
            {
                // We have gathered sufficient units. Attack the nearest enemy unit.
                owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsAttackMoveState(), false);
            }
            else
            {
                owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsFleeStateCA(), false);
            }
        }
Exemple #25
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            if (ShouldFlee(owner))
            {
                owner.FuzzyStateMachine.ChangeState(owner, new AirFleeStateCA(), false);
                return;
            }

            var e = FindDefenselessTarget(owner);

            if (e == null)
            {
                Retreat(owner, flee: false, rearm: true, repair: true);
                return;
            }

            owner.TargetActor = e;
            owner.FuzzyStateMachine.ChangeState(owner, new AirAttackStateCA(), false);
        }
Exemple #26
0
 public void Deactivate(SquadCA owner)
 {
 }
Exemple #27
0
 public void Activate(SquadCA owner)
 {
 }
Exemple #28
0
        public void Tick(SquadCA owner)
        {
            if (!owner.IsValid)
            {
                return;
            }

            if (!owner.IsTargetValid)
            {
                var a            = owner.Units.Random(owner.Random);
                var closestEnemy = owner.SquadManager.FindClosestEnemy(a.CenterPosition);
                if (closestEnemy != null)
                {
                    owner.TargetActor = closestEnemy;
                }
                else
                {
                    owner.FuzzyStateMachine.ChangeState(owner, new AirFleeStateCA(), false);
                    return;
                }
            }

            var leader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition);

            var unitsAroundPos = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.SquadManager.Info.DangerScanRadius))
                                 .Where(a => owner.SquadManager.IsPreferredEnemyUnit(a) && owner.SquadManager.IsNotHiddenUnit(a));

            // Check if get ambushed.
            if (CountAntiAirUnits(unitsAroundPos) > owner.Units.Count)
            {
                owner.FuzzyStateMachine.ChangeState(owner, new AirFleeStateCA(), false);
                return;
            }

            var          cannotRetaliate  = true;
            List <Actor> resupplyingUnits = new List <Actor>();
            List <Actor> backingoffUnits  = new List <Actor>();
            List <Actor> attackingUnits   = new List <Actor>();

            foreach (var a in owner.Units)
            {
                if (BusyAttack(a))
                {
                    cannotRetaliate = false;
                    continue;
                }

                var ammoPools = a.TraitsImplementing <AmmoPool>().ToArray();
                if (!ReloadsAutomatically(ammoPools, a.TraitOrDefault <Rearmable>()))
                {
                    if (IsRearming(a))
                    {
                        continue;
                    }

                    if (!HasAmmo(ammoPools))
                    {
                        resupplyingUnits.Add(a);
                        continue;
                    }
                }

                if (CanAttackTarget(a, owner.TargetActor))
                {
                    cannotRetaliate = false;
                    attackingUnits.Add(a);
                }
                else
                {
                    if (!FullAmmo(ammoPools))
                    {
                        resupplyingUnits.Add(a);
                        continue;
                    }

                    backingoffUnits.Add(a);
                }
            }

            if (cannotRetaliate)
            {
                owner.FuzzyStateMachine.ChangeState(owner, new AirFleeStateCA(), false);
                return;
            }

            owner.Bot.QueueOrder(new Order("ReturnToBase", null, false, groupedActors: resupplyingUnits.ToArray()));
            owner.Bot.QueueOrder(new Order("Attack", null, Target.FromActor(owner.TargetActor), false, groupedActors: attackingUnits.ToArray()));
            owner.Bot.QueueOrder(new Order("Move", null, Target.FromCell(owner.World, RandomBuildingLocation(owner)), false, groupedActors: backingoffUnits.ToArray()));
        }
Exemple #29
0
 // Checks the number of anti air enemies around units
 protected virtual bool ShouldFlee(SquadCA owner)
 {
     return(ShouldFlee(owner, enemies => CountAntiAirUnits(enemies) > owner.Units.Count));
 }
Exemple #30
0
 public static bool NearToPosSafely(SquadCA owner, WPos loc)
 {
     return(NearToPosSafely(owner, loc, out _));
 }