AI Support Power Meta Data implemented.
Changes included: Decision can be defined for the AI support powers, governing their targeting. Each decision can be made up of multiple considerations.
This commit is contained in:
@@ -23,14 +23,25 @@ namespace OpenRA.Mods.RA.AI
|
||||
{
|
||||
public sealed class HackyAIInfo : IBotInfo, ITraitInfo
|
||||
{
|
||||
[Desc("Ingame name this bot uses.")]
|
||||
public readonly string Name = "Unnamed Bot";
|
||||
|
||||
[Desc("Minimum number of units AI must have before attacking.")]
|
||||
public readonly int SquadSize = 8;
|
||||
|
||||
[Desc("Production queues AI uses for buildings.")]
|
||||
public readonly string[] BuildingQueues = { "Building" };
|
||||
|
||||
[Desc("Production queues AI uses for defenses.")]
|
||||
public readonly string[] DefenseQueues = { "Defense" };
|
||||
|
||||
[Desc("Delay (in ticks) between giving out orders to units.")]
|
||||
public readonly int AssignRolesInterval = 20;
|
||||
|
||||
[Desc("Delay (in ticks) between attempting rush attacks.")]
|
||||
public readonly int RushInterval = 600;
|
||||
|
||||
[Desc("Delay (in ticks) between updating squads.")]
|
||||
public readonly int AttackForceInterval = 30;
|
||||
|
||||
[Desc("How long to wait (in ticks) between structure production checks when there is no active production.")]
|
||||
@@ -63,26 +74,39 @@ namespace OpenRA.Mods.RA.AI
|
||||
[Desc("Radius in cells around the center of the base to expand.")]
|
||||
public readonly int MaxBaseRadius = 20;
|
||||
|
||||
[Desc("Production queues AI uses for producing units.")]
|
||||
public readonly string[] UnitQueues = { "Vehicle", "Infantry", "Plane", "Ship", "Aircraft" };
|
||||
|
||||
[Desc("Should the AI repair its buildings if damaged?")]
|
||||
public readonly bool ShouldRepairBuildings = true;
|
||||
|
||||
string IBotInfo.Name { get { return this.Name; } }
|
||||
|
||||
[Desc("What units to the AI should build.", "What % of the total army must be this type of unit.")]
|
||||
[FieldLoader.LoadUsing("LoadUnits")]
|
||||
public readonly Dictionary<string, float> UnitsToBuild = null;
|
||||
|
||||
[Desc("What buildings to the AI should build.", "What % of the total base must be this type of building.")]
|
||||
[FieldLoader.LoadUsing("LoadBuildings")]
|
||||
public readonly Dictionary<string, float> BuildingFractions = null;
|
||||
|
||||
[Desc("Tells the AI what unit types fall under the same common name.")]
|
||||
[FieldLoader.LoadUsing("LoadUnitsCommonNames")]
|
||||
public readonly Dictionary<string, string[]> UnitsCommonNames = null;
|
||||
|
||||
[Desc("Tells the AI what building types fall under the same common name.")]
|
||||
[FieldLoader.LoadUsing("LoadBuildingsCommonNames")]
|
||||
public readonly Dictionary<string, string[]> BuildingCommonNames = null;
|
||||
|
||||
[Desc("What buildings should the AI have max limits n.", "What is the limit of the building.")]
|
||||
[FieldLoader.LoadUsing("LoadBuildingLimits")]
|
||||
public readonly Dictionary<string, int> BuildingLimits = null;
|
||||
|
||||
// TODO Update OpenRA.Utility/Command.cs#L300 to first handle lists and also read nested ones
|
||||
[Desc("Tells the AI how to use its support powers.")]
|
||||
[FieldLoader.LoadUsing("LoadDecisions")]
|
||||
public readonly List<SupportPowerDecision> PowerDecisions = new List<SupportPowerDecision>();
|
||||
|
||||
static object LoadList<T>(MiniYaml y, string field)
|
||||
{
|
||||
var nd = y.ToDictionary();
|
||||
@@ -99,6 +123,16 @@ namespace OpenRA.Mods.RA.AI
|
||||
|
||||
static object LoadBuildingLimits(MiniYaml y) { return LoadList<int>(y, "BuildingLimits"); }
|
||||
|
||||
static object LoadDecisions(MiniYaml yaml)
|
||||
{
|
||||
var ret = new List<SupportPowerDecision>();
|
||||
foreach (var d in yaml.Nodes)
|
||||
if (d.Key.Split('@')[0] == "SupportPowerDecision")
|
||||
ret.Add(new SupportPowerDecision(d.Value));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public object Create(ActorInitializer init) { return new HackyAI(this, init); }
|
||||
}
|
||||
|
||||
@@ -113,6 +147,9 @@ namespace OpenRA.Mods.RA.AI
|
||||
public CPos baseCenter { get; private set; }
|
||||
public Player p { get; private set; }
|
||||
|
||||
Dictionary<SupportPowerInstance, int> waitingPowers = new Dictionary<SupportPowerInstance, int>();
|
||||
Dictionary<string, SupportPowerDecision> powerDecisions = new Dictionary<string, SupportPowerDecision>();
|
||||
|
||||
PowerManager playerPower;
|
||||
SupportPowerManager supportPowerMngr;
|
||||
PlayerResources playerResource;
|
||||
@@ -142,6 +179,9 @@ namespace OpenRA.Mods.RA.AI
|
||||
{
|
||||
Info = info;
|
||||
world = init.world;
|
||||
|
||||
foreach (var decision in info.PowerDecisions)
|
||||
powerDecisions.Add(decision.OrderName, decision);
|
||||
}
|
||||
|
||||
public static void BotDebug(string s, params object[] args)
|
||||
@@ -695,46 +735,120 @@ namespace OpenRA.Mods.RA.AI
|
||||
foreach (var kv in powers)
|
||||
{
|
||||
var sp = kv.Value;
|
||||
if (sp.Ready)
|
||||
{
|
||||
var attackLocation = FindAttackLocationToSupportPower(5);
|
||||
if (attackLocation == null)
|
||||
return;
|
||||
// Add power to dictionary if not in delay dictionary yet
|
||||
if (!waitingPowers.ContainsKey(sp))
|
||||
waitingPowers.Add(sp, 0);
|
||||
|
||||
if (waitingPowers[sp] > 0)
|
||||
waitingPowers[sp]--;
|
||||
|
||||
// If we have recently tried and failed to find a use location for a power, then do not try again until later
|
||||
var isDelayed = (waitingPowers[sp] > 0);
|
||||
if (sp.Ready && !isDelayed && powerDecisions.ContainsKey(sp.Info.OrderName))
|
||||
{
|
||||
var powerDecision = powerDecisions[sp.Info.OrderName];
|
||||
if (powerDecision == null)
|
||||
{
|
||||
BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", sp.Info.OrderName);
|
||||
continue;
|
||||
}
|
||||
|
||||
var attackLocation = FindCoarseAttackLocationToSupportPower(sp);
|
||||
if (attackLocation == null)
|
||||
{
|
||||
BotDebug("AI: {1} can't find suitable coarse attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, p.PlayerName);
|
||||
waitingPowers[sp] += powerDecision.GetNextScanTime(this);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found a target location, check for precise target
|
||||
attackLocation = FindFineAttackLocationToSupportPower(sp, (CPos)attackLocation);
|
||||
if (attackLocation == null)
|
||||
{
|
||||
BotDebug("AI: {1} can't find suitable final attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, p.PlayerName);
|
||||
waitingPowers[sp] += powerDecision.GetNextScanTime(this);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Valid target found, delay by a few ticks to avoid rescanning before power fires via order
|
||||
BotDebug("AI: {2} found new target location {0} for support power {1}.", attackLocation, sp.Info.OrderName, p.PlayerName);
|
||||
waitingPowers[sp] += 10;
|
||||
world.IssueOrder(new Order(sp.Info.OrderName, supportPowerMngr.self, false) { TargetLocation = attackLocation.Value, SuppressVisualFeedback = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CPos? FindAttackLocationToSupportPower(int radiusOfPower)
|
||||
///<summary>Scans the map in chunks, evaluating all actors in each.</summary>
|
||||
CPos? FindCoarseAttackLocationToSupportPower(SupportPowerInstance readyPower)
|
||||
{
|
||||
CPos? resLoc = null;
|
||||
var countUnits = 0;
|
||||
|
||||
var x = (world.Map.MapSize.X % radiusOfPower) == 0 ? world.Map.MapSize.X : world.Map.MapSize.X + radiusOfPower;
|
||||
var y = (world.Map.MapSize.Y % radiusOfPower) == 0 ? world.Map.MapSize.Y : world.Map.MapSize.Y + radiusOfPower;
|
||||
|
||||
for (var i = 0; i < x; i += radiusOfPower * 2)
|
||||
CPos? bestLocation = null;
|
||||
var bestAttractiveness = 0;
|
||||
var powerDecision = powerDecisions[readyPower.Info.OrderName];
|
||||
if (powerDecision == null)
|
||||
{
|
||||
for (var j = 0; j < y; j += radiusOfPower * 2)
|
||||
{
|
||||
var pos = world.Map.CenterOfCell(new CPos(i, j));
|
||||
var targets = world.FindActorsInCircle(pos, WRange.FromCells(radiusOfPower)).ToList();
|
||||
var enemies = targets.Where(unit => p.Stances[unit.Owner] == Stance.Enemy).ToList();
|
||||
var ally = targets.Where(unit => p.Stances[unit.Owner] == Stance.Ally || unit.Owner == p).ToList();
|
||||
BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", readyPower.Info.OrderName);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (enemies.Count < ally.Count || !enemies.Any())
|
||||
var checkRadius = powerDecision.CoarseScanRadius;
|
||||
for (var i = 0; i < world.Map.MapSize.X; i += checkRadius)
|
||||
{
|
||||
for (var j = 0; j < world.Map.MapSize.Y; j += checkRadius)
|
||||
{
|
||||
var consideredAttractiveness = 0;
|
||||
|
||||
var tl = world.Map.CenterOfCell(new CPos(i, j));
|
||||
var br = world.Map.CenterOfCell(new CPos(i + checkRadius, j + checkRadius));
|
||||
var targets = world.ActorMap.ActorsInBox(tl, br);
|
||||
|
||||
consideredAttractiveness = powerDecision.GetAttractiveness(targets, p);
|
||||
if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness)
|
||||
continue;
|
||||
|
||||
if (enemies.Count > countUnits)
|
||||
{
|
||||
countUnits = enemies.Count;
|
||||
resLoc = enemies.Random(random).Location;
|
||||
}
|
||||
bestAttractiveness = consideredAttractiveness;
|
||||
bestLocation = new CPos(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
return resLoc;
|
||||
return bestLocation;
|
||||
}
|
||||
|
||||
///<summary>Detail scans an area, evaluating positions.</summary>
|
||||
CPos? FindFineAttackLocationToSupportPower(SupportPowerInstance readyPower, CPos checkPos, int extendedRange = 1)
|
||||
{
|
||||
CPos? bestLocation = null;
|
||||
var bestAttractiveness = 0;
|
||||
var powerDecision = powerDecisions[readyPower.Info.OrderName];
|
||||
if (powerDecision == null)
|
||||
{
|
||||
BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", readyPower.Info.OrderName);
|
||||
return null;
|
||||
}
|
||||
|
||||
var checkRadius = powerDecision.CoarseScanRadius;
|
||||
var fineCheck = powerDecision.FineScanRadius;
|
||||
for (var i = (0 - extendedRange); i <= (checkRadius + extendedRange); i += fineCheck)
|
||||
{
|
||||
var x = checkPos.X + i;
|
||||
|
||||
for (var j = (0 - extendedRange); j <= (checkRadius + extendedRange); j += fineCheck)
|
||||
{
|
||||
var y = checkPos.Y + j;
|
||||
var pos = world.Map.CenterOfCell(new CPos(x, y));
|
||||
var consideredAttractiveness = 0;
|
||||
consideredAttractiveness += powerDecision.GetAttractiveness(pos, p);
|
||||
|
||||
if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness)
|
||||
continue;
|
||||
|
||||
bestAttractiveness = consideredAttractiveness;
|
||||
bestLocation = new CPos(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
return bestLocation;
|
||||
}
|
||||
|
||||
internal IEnumerable<ProductionQueue> FindQueues(string category)
|
||||
|
||||
155
OpenRA.Mods.RA/AI/SupportPowerDecision.cs
Normal file
155
OpenRA.Mods.RA/AI/SupportPowerDecision.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA;
|
||||
using OpenRA.Mods.RA.AI;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
[Desc("Adds metadata for the AI bots.")]
|
||||
public class SupportPowerDecision
|
||||
{
|
||||
[Desc("What is the minimum attractiveness we will use this power for?")]
|
||||
public readonly int MinimumAttractiveness = 1;
|
||||
|
||||
[Desc("What support power does this decision apply to?")]
|
||||
public readonly string OrderName = "AirstrikePowerInfoOrder";
|
||||
|
||||
[Desc("What is the coarse scan radius of this power?","For finding the general target area, before doing a detail scan","Should be 10 or more to avoid lag")]
|
||||
public readonly int CoarseScanRadius = 20;
|
||||
|
||||
[Desc("What is the fine scan radius of this power?", "For doing a detailed scan in the general target area.", "Minimum is 1")]
|
||||
public readonly int FineScanRadius = 2;
|
||||
|
||||
[FieldLoader.LoadUsing("LoadConsiderations")]
|
||||
[Desc("The decisions associated with this power")]
|
||||
readonly List<Consideration> Considerations = new List<Consideration>();
|
||||
|
||||
[Desc("Minimum ticks to wait until next Decision scan attempt.")]
|
||||
public readonly int MinimumScanTimeInterval = 250;
|
||||
|
||||
[Desc("Maximum ticks to wait until next Decision scan attempt.")]
|
||||
public readonly int MaximumScanTimeInterval = 262;
|
||||
|
||||
public SupportPowerDecision(MiniYaml yaml)
|
||||
{
|
||||
FieldLoader.Load(this, yaml);
|
||||
}
|
||||
|
||||
static object LoadConsiderations(MiniYaml yaml)
|
||||
{
|
||||
var ret = new List<Consideration>();
|
||||
foreach (var d in yaml.Nodes)
|
||||
if (d.Key.Split('@')[0] == "Consideration")
|
||||
ret.Add(new Consideration(d.Value));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///<summary>Evaluates the attractiveness of a position according to all considerations</summary>
|
||||
public int GetAttractiveness(WPos pos, Player firedBy)
|
||||
{
|
||||
var answer = 0;
|
||||
var world = firedBy.World;
|
||||
var targetTile = world.Map.CellContaining(pos);
|
||||
|
||||
if (!world.Map.Contains(targetTile))
|
||||
return 0;
|
||||
|
||||
foreach (var consideration in Considerations)
|
||||
{
|
||||
var radiusToUse = new WRange(consideration.CheckRadius.Range);
|
||||
|
||||
var checkActors = world.FindActorsInCircle(pos, radiusToUse);
|
||||
foreach (var scrutinized in checkActors)
|
||||
answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner]);
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
///<summary>Evaluates the attractiveness of a group of actors according to all considerations</summary>
|
||||
public int GetAttractiveness(IEnumerable<Actor> actors, Player firedBy)
|
||||
{
|
||||
var answer = 0;
|
||||
|
||||
foreach (var consideration in Considerations)
|
||||
foreach (var scrutinized in actors)
|
||||
answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner]);
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
public int GetNextScanTime(HackyAI ai) { return ai.random.Next(MinimumScanTimeInterval, MaximumScanTimeInterval); }
|
||||
|
||||
///<summary>Makes up part of a decision, describing how to evaluate a target.</summary>
|
||||
class Consideration
|
||||
{
|
||||
public enum DecisionMetric { Health, Value, None };
|
||||
|
||||
[Desc("Against whom should this power be used?", "Allowed keywords: Ally, Neutral, Enemy")]
|
||||
public readonly Stance Against = Stance.Enemy;
|
||||
|
||||
[Desc("What types should the desired targets of this power be?")]
|
||||
public readonly string[] Types = { "Air", "Ground", "Water" };
|
||||
|
||||
[Desc("How attractive are these types of targets?")]
|
||||
public readonly int Attractiveness = 100;
|
||||
|
||||
[Desc("Weight the target attractiveness by this property", "Allowed keywords: Health, Value, None")]
|
||||
public readonly DecisionMetric TargetMetric = DecisionMetric.None;
|
||||
|
||||
[Desc("What is the check radius of this decision?")]
|
||||
public readonly WRange CheckRadius = WRange.FromCells(5);
|
||||
|
||||
public Consideration(MiniYaml yaml)
|
||||
{
|
||||
FieldLoader.Load(this, yaml);
|
||||
}
|
||||
|
||||
///<summary>Evaluates a single actor according to the rules defined in this consideration</summary>
|
||||
public int GetAttractiveness(Actor a, Stance stance)
|
||||
{
|
||||
if (stance != Against)
|
||||
return 0;
|
||||
|
||||
if (a == null)
|
||||
return 0;
|
||||
|
||||
var targetable = a.TraitOrDefault<ITargetable>();
|
||||
if (targetable == null)
|
||||
return 0;
|
||||
|
||||
if (Types.Intersect(targetable.TargetTypes).Any())
|
||||
{
|
||||
switch (TargetMetric)
|
||||
{
|
||||
case DecisionMetric.Value:
|
||||
var valueInfo = a.Info.Traits.GetOrDefault<ValuedInfo>();
|
||||
return (valueInfo != null) ? valueInfo.Cost * Attractiveness : 0;
|
||||
|
||||
case DecisionMetric.Health:
|
||||
var health = a.TraitOrDefault<Health>();
|
||||
return (health != null) ? (health.HP / health.MaxHP) * Attractiveness : 0;
|
||||
|
||||
default:
|
||||
return Attractiveness;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,7 @@
|
||||
<Compile Include="Air\Aircraft.cs" />
|
||||
<Compile Include="Air\AttackHeli.cs" />
|
||||
<Compile Include="Air\AttackPlane.cs" />
|
||||
<Compile Include="AI\SupportPowerDecision.cs" />
|
||||
<Compile Include="Crates\DuplicateUnitCrateAction.cs" />
|
||||
<Compile Include="Power.cs" />
|
||||
<Compile Include="Effects\Beacon.cs" />
|
||||
|
||||
@@ -65,6 +65,58 @@ Player:
|
||||
heli: 5%
|
||||
orca: 5%
|
||||
SquadSize: 15
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 2000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Infantry
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
SupportPowerDecision@IonCannonPower:
|
||||
OrderName: IonCannonPowerInfoOrder
|
||||
MinimumAttractiveness: 1000
|
||||
FineScanRadius: 2
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Air, Tank, Vehicle, Infantry, Water
|
||||
Attractiveness: 2
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@3:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 3c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
HackyAI@Watson:
|
||||
Name: Watson
|
||||
BuildingCommonNames:
|
||||
@@ -131,6 +183,58 @@ Player:
|
||||
jeep: 20%
|
||||
mtnk: 50%
|
||||
SquadSize: 15
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 2000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Infantry
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
SupportPowerDecision@IonCannonPower:
|
||||
OrderName: IonCannonPowerInfoOrder
|
||||
MinimumAttractiveness: 1000
|
||||
FineScanRadius: 2
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Air, Tank, Vehicle, Infantry, Water
|
||||
Attractiveness: 2
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@3:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 3c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
HackyAI@HAL9001:
|
||||
Name: HAL 9001
|
||||
BuildingCommonNames:
|
||||
@@ -199,3 +303,55 @@ Player:
|
||||
htnk: 50%
|
||||
orca: 10%
|
||||
SquadSize: 8
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 2000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Infantry
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
SupportPowerDecision@IonCannonPower:
|
||||
OrderName: IonCannonPowerInfoOrder
|
||||
MinimumAttractiveness: 1000
|
||||
FineScanRadius: 2
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Air, Tank, Vehicle, Infantry, Water
|
||||
Attractiveness: 2
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@3:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 3c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
|
||||
@@ -324,7 +324,7 @@
|
||||
Selectable:
|
||||
Priority: 3
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground, C4
|
||||
TargetTypes: Ground, C4, Structure
|
||||
Armor:
|
||||
Type: Wood
|
||||
Building:
|
||||
|
||||
@@ -107,6 +107,57 @@ Player:
|
||||
combato: 100%
|
||||
SquadSize: 8
|
||||
MaxBaseRadius: 40
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 2000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry
|
||||
Attractiveness: 2
|
||||
TargetMetric: Value
|
||||
CheckRadius: 3c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@3:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 4c0
|
||||
SupportPowerDecision@Paratroopers:
|
||||
OrderName: ParatroopersPowerInfoOrder
|
||||
MinimumAttractiveness: 5
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry
|
||||
Attractiveness: -5
|
||||
TargetMetric: None
|
||||
CheckRadius: 4c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
HackyAI@Vidius:
|
||||
Name: Vidious
|
||||
UnitQueues: Infantry, Vehicle, Armor, Starport
|
||||
@@ -215,6 +266,57 @@ Player:
|
||||
combato: 100%
|
||||
SquadSize: 6
|
||||
MaxBaseRadius: 40
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 2000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry
|
||||
Attractiveness: 2
|
||||
TargetMetric: Value
|
||||
CheckRadius: 3c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@3:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 4c0
|
||||
SupportPowerDecision@Paratroopers:
|
||||
OrderName: ParatroopersPowerInfoOrder
|
||||
MinimumAttractiveness: 5
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry
|
||||
Attractiveness: -5
|
||||
TargetMetric: None
|
||||
CheckRadius: 4c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
HackyAI@Gladius:
|
||||
Name: Gladius
|
||||
UnitQueues: Infantry, Vehicle, Armor, Starport
|
||||
@@ -323,3 +425,54 @@ Player:
|
||||
combato: 100%
|
||||
SquadSize: 10
|
||||
MaxBaseRadius: 40
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 2000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry
|
||||
Attractiveness: 2
|
||||
TargetMetric: Value
|
||||
CheckRadius: 3c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 2c0
|
||||
Consideration@3:
|
||||
Against: Ally
|
||||
Types: Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 4c0
|
||||
SupportPowerDecision@Paratroopers:
|
||||
OrderName: ParatroopersPowerInfoOrder
|
||||
MinimumAttractiveness: 5
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry
|
||||
Attractiveness: -5
|
||||
TargetMetric: None
|
||||
CheckRadius: 4c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
Selectable:
|
||||
Priority: 2
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground, C4
|
||||
TargetTypes: Ground, C4, Structure
|
||||
Building:
|
||||
Dimensions: 1,1
|
||||
Footprint: x
|
||||
|
||||
@@ -52,6 +52,45 @@ Player:
|
||||
2tnk: 25%
|
||||
3tnk: 50%
|
||||
SquadSize: 20
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 1
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 5c0
|
||||
SupportPowerDecision@Paratroopers:
|
||||
OrderName: ParatroopersPowerInfoOrder
|
||||
MinimumAttractiveness: 5
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry, Defense
|
||||
Attractiveness: -10
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
HackyAI@NormalAI:
|
||||
Name: Normal AI
|
||||
BuildingCommonNames:
|
||||
@@ -119,6 +158,45 @@ Player:
|
||||
ca: 10%
|
||||
pt: 10%
|
||||
SquadSize: 40
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 1
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 5c0
|
||||
SupportPowerDecision@Paratroopers:
|
||||
OrderName: ParatroopersPowerInfoOrder
|
||||
MinimumAttractiveness: 5
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry, Defense
|
||||
Attractiveness: -10
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
HackyAI@TurtleAI:
|
||||
Name: Turtle AI
|
||||
BuildingCommonNames:
|
||||
@@ -185,6 +263,45 @@ Player:
|
||||
ca: 10%
|
||||
pt: 10%
|
||||
SquadSize: 10
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 1
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 5c0
|
||||
SupportPowerDecision@Paratroopers:
|
||||
OrderName: ParatroopersPowerInfoOrder
|
||||
MinimumAttractiveness: 5
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry, Defense
|
||||
Attractiveness: -10
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
HackyAI@NavalAI:
|
||||
Name: Naval AI
|
||||
BuildingCommonNames:
|
||||
@@ -238,4 +355,43 @@ Player:
|
||||
ca: 20%
|
||||
pt: 10%
|
||||
SquadSize: 1
|
||||
SupportPowerDecision@Airstrike:
|
||||
OrderName: AirstrikePowerInfoOrder
|
||||
MinimumAttractiveness: 1
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 5c0
|
||||
SupportPowerDecision@Paratroopers:
|
||||
OrderName: ParatroopersPowerInfoOrder
|
||||
MinimumAttractiveness: 5
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
Consideration@2:
|
||||
Against: Enemy
|
||||
Types: Vehicle, Tank, Infantry, Defense
|
||||
Attractiveness: -10
|
||||
TargetMetric: None
|
||||
CheckRadius: 10c0
|
||||
SupportPowerDecision@NukePower:
|
||||
OrderName: NukePowerInfoOrder
|
||||
MinimumAttractiveness: 3000
|
||||
Consideration@1:
|
||||
Against: Enemy
|
||||
Types: Structure
|
||||
Attractiveness: 1
|
||||
TargetMetric: Value
|
||||
CheckRadius: 5c0
|
||||
Consideration@2:
|
||||
Against: Ally
|
||||
Types: Air, Ground, Water
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
Selectable:
|
||||
Voice: VehicleVoice
|
||||
TargetableUnit:
|
||||
TargetTypes: Ground, C4, Repair
|
||||
TargetTypes: Ground, C4, Repair, Vehicle
|
||||
Repairable:
|
||||
Chronoshiftable:
|
||||
Passenger:
|
||||
@@ -73,7 +73,7 @@
|
||||
Selectable:
|
||||
Voice: VehicleVoice
|
||||
TargetableUnit:
|
||||
TargetTypes: Ground, C4, Repair
|
||||
TargetTypes: Ground, C4, Repair, Tank
|
||||
Repairable:
|
||||
Chronoshiftable:
|
||||
Passenger:
|
||||
@@ -268,7 +268,7 @@
|
||||
Selectable:
|
||||
Priority: 3
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground, C4, DetonateAttack
|
||||
TargetTypes: Ground, C4, DetonateAttack, Structure
|
||||
Building:
|
||||
Dimensions: 1,1
|
||||
Footprint: x
|
||||
@@ -310,6 +310,11 @@
|
||||
LuaScriptEvents:
|
||||
Demolishable:
|
||||
ScriptTriggers:
|
||||
|
||||
^Defense:
|
||||
Inherits: ^Building
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground, C4, DetonateAttack, Structure, Defense
|
||||
|
||||
^Wall:
|
||||
AppearsOnRadar:
|
||||
|
||||
@@ -276,7 +276,7 @@ PDOX:
|
||||
Amount: -200
|
||||
|
||||
TSLA:
|
||||
Inherits: ^Building
|
||||
Inherits: ^Defense
|
||||
Buildable:
|
||||
Queue: Defense
|
||||
BuildPaletteOrder: 80
|
||||
@@ -319,7 +319,7 @@ TSLA:
|
||||
Amount: -150
|
||||
|
||||
AGUN:
|
||||
Inherits: ^Building
|
||||
Inherits: ^Defense
|
||||
Buildable:
|
||||
Queue: Defense
|
||||
BuildPaletteOrder: 90
|
||||
@@ -400,7 +400,7 @@ DOME:
|
||||
Amount: -40
|
||||
|
||||
PBOX:
|
||||
Inherits: ^Building
|
||||
Inherits: ^Defense
|
||||
Tooltip:
|
||||
Name: Pillbox
|
||||
Description: Static defense with a fireport for a\ngarrisoned soldier.
|
||||
@@ -445,7 +445,7 @@ PBOX:
|
||||
Amount: -15
|
||||
|
||||
HBOX:
|
||||
Inherits: ^Building
|
||||
Inherits: ^Defense
|
||||
Tooltip:
|
||||
Name: Camo Pillbox
|
||||
Description: Camouflaged static defense with a fireport\nfor a garrisoned soldier.
|
||||
@@ -493,7 +493,7 @@ HBOX:
|
||||
Amount: -15
|
||||
|
||||
GUN:
|
||||
Inherits: ^Building
|
||||
Inherits: ^Defense
|
||||
Buildable:
|
||||
Queue: Defense
|
||||
BuildPaletteOrder: 70
|
||||
@@ -533,7 +533,7 @@ GUN:
|
||||
Amount: -40
|
||||
|
||||
FTUR:
|
||||
Inherits: ^Building
|
||||
Inherits: ^Defense
|
||||
Buildable:
|
||||
Queue: Defense
|
||||
BuildPaletteOrder: 60
|
||||
@@ -571,7 +571,7 @@ FTUR:
|
||||
Amount: -20
|
||||
|
||||
SAM:
|
||||
Inherits: ^Building
|
||||
Inherits: ^Defense
|
||||
Buildable:
|
||||
Queue: Defense
|
||||
BuildPaletteOrder: 100
|
||||
|
||||
Reference in New Issue
Block a user