Ensure the target location can be pathed to by all units in the squad, so the squad won't get stuck if some units can't make it. Improve the choice of leader for the squad. We attempt to a choose a leader whose locomotor is the most restrictive in terms of passable terrain. This maximises the chance that the squad will be able to follow the leader along the path to the target. We also keep this choice of leader as the squad advances, this avoids the squad constantly switching leaders and regrouping backwards in some cases.
142 lines
3.6 KiB
C#
142 lines
3.6 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright (c) The OpenRA Developers and Contributors
|
|
* This file is part of OpenRA, which is free software. It is made
|
|
* available to you under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation, either version 3 of
|
|
* the License, or (at your option) any later version. For more
|
|
* information, see COPYING.
|
|
*/
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using OpenRA.Mods.Common.Activities;
|
|
using OpenRA.Traits;
|
|
|
|
namespace OpenRA.Mods.Common.Traits.BotModules.Squads
|
|
{
|
|
abstract class StateBase
|
|
{
|
|
protected static void GoToRandomOwnBuilding(Squad squad)
|
|
{
|
|
var loc = RandomBuildingLocation(squad);
|
|
foreach (var a in squad.Units)
|
|
squad.Bot.QueueOrder(new Order("Move", a, Target.FromCell(squad.World, loc), false));
|
|
}
|
|
|
|
protected static CPos RandomBuildingLocation(Squad 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;
|
|
}
|
|
|
|
protected static bool BusyAttack(Actor a)
|
|
{
|
|
if (a.IsIdle)
|
|
return false;
|
|
|
|
var activity = a.CurrentActivity;
|
|
var type = activity.GetType();
|
|
if (type == typeof(Attack) || type == typeof(FlyAttack))
|
|
return true;
|
|
|
|
var next = activity.NextActivity;
|
|
if (next == null)
|
|
return false;
|
|
|
|
var nextType = next.GetType();
|
|
if (nextType == typeof(Attack) || nextType == typeof(FlyAttack))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
protected static bool CanAttackTarget(Actor a, Actor target)
|
|
{
|
|
if (!a.Info.HasTraitInfo<AttackBaseInfo>())
|
|
return false;
|
|
|
|
var targetTypes = target.GetEnabledTargetTypes();
|
|
if (targetTypes.IsEmpty)
|
|
return false;
|
|
|
|
var arms = a.TraitsImplementing<Armament>();
|
|
foreach (var arm in arms)
|
|
{
|
|
if (arm.IsTraitDisabled)
|
|
continue;
|
|
|
|
if (arm.Weapon.IsValidTarget(targetTypes))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected virtual bool ShouldFlee(Squad squad, Func<IReadOnlyCollection<Actor>, bool> flee)
|
|
{
|
|
if (!squad.IsValid)
|
|
return false;
|
|
|
|
var dangerRadius = squad.SquadManager.Info.DangerScanRadius;
|
|
var units = squad.World.FindActorsInCircle(squad.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.IsPreferredEnemyUnit(unit) && unit.Info.HasTraitInfo<AttackBaseInfo>())
|
|
.ToList();
|
|
if (enemyAroundUnit.Count == 0)
|
|
return false;
|
|
|
|
return flee(enemyAroundUnit);
|
|
}
|
|
|
|
protected static bool IsRearming(Actor a)
|
|
{
|
|
return !a.IsIdle && (a.CurrentActivity.ActivitiesImplementing<Resupply>().Any() || a.CurrentActivity.ActivitiesImplementing<ReturnToBase>().Any());
|
|
}
|
|
|
|
protected static bool FullAmmo(IEnumerable<AmmoPool> ammoPools)
|
|
{
|
|
foreach (var ap in ammoPools)
|
|
if (!ap.HasFullAmmo)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
protected static bool HasAmmo(IEnumerable<AmmoPool> ammoPools)
|
|
{
|
|
foreach (var ap in ammoPools)
|
|
if (!ap.HasAmmo)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
protected static bool ReloadsAutomatically(IEnumerable<AmmoPool> ammoPools, Rearmable rearmable)
|
|
{
|
|
if (rearmable == null)
|
|
return true;
|
|
|
|
foreach (var ap in ammoPools)
|
|
if (!rearmable.Info.AmmoPools.Contains(ap.Info.Name))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|