Convert AISupportPowerManager to module

This commit is contained in:
reaperrr
2018-11-04 02:59:16 +01:00
committed by Oliver Brakmann
parent c195699476
commit 451a38338b
8 changed files with 78 additions and 397 deletions

View File

@@ -187,11 +187,6 @@ namespace OpenRA.Mods.Common.AI
[Desc("What buildings should the AI have a maximum limit to build.")] [Desc("What buildings should the AI have a maximum limit to build.")]
public readonly Dictionary<string, int> BuildingLimits = null; 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> SupportPowerDecisions = new List<SupportPowerDecision>();
[Desc("Actor types that can capture other actors (via `Captures` or `ExternalCaptures`).", [Desc("Actor types that can capture other actors (via `Captures` or `ExternalCaptures`).",
"Leave this empty to disable capturing.")] "Leave this empty to disable capturing.")]
public HashSet<string> CapturingActorTypes = new HashSet<string>(); public HashSet<string> CapturingActorTypes = new HashSet<string>();
@@ -225,17 +220,6 @@ namespace OpenRA.Mods.Common.AI
return FieldLoader.Load<BuildingCategories>(categories.Value); return FieldLoader.Load<BuildingCategories>(categories.Value);
} }
static object LoadDecisions(MiniYaml yaml)
{
var ret = new List<SupportPowerDecision>();
var decisions = yaml.Nodes.FirstOrDefault(n => n.Key == "SupportPowerDecisions");
if (decisions != null)
foreach (var d in decisions.Value.Nodes)
ret.Add(new SupportPowerDecision(d.Value));
return ret;
}
string IBotInfo.Type { get { return Type; } } string IBotInfo.Type { get { return Type; } }
string IBotInfo.Name { get { return Name; } } string IBotInfo.Name { get { return Name; } }
@@ -245,6 +229,7 @@ namespace OpenRA.Mods.Common.AI
public sealed class HackyAI : ITick, IBot, INotifyDamage public sealed class HackyAI : ITick, IBot, INotifyDamage
{ {
// DEPRECATED: Modules should use World.LocalRandom.
public MersenneTwister Random { get; private set; } public MersenneTwister Random { get; private set; }
public readonly HackyAIInfo Info; public readonly HackyAIInfo Info;
@@ -275,8 +260,6 @@ namespace OpenRA.Mods.Common.AI
BitArray resourceTypeIndices; BitArray resourceTypeIndices;
AISupportPowerManager supportPowerManager;
List<BaseBuilder> builders = new List<BaseBuilder>(); List<BaseBuilder> builders = new List<BaseBuilder>();
List<Actor> unitsHangingAroundTheBase = new List<Actor>(); List<Actor> unitsHangingAroundTheBase = new List<Actor>();
@@ -324,8 +307,6 @@ namespace OpenRA.Mods.Common.AI
playerResource = p.PlayerActor.Trait<PlayerResources>(); playerResource = p.PlayerActor.Trait<PlayerResources>();
tickModules = p.PlayerActor.TraitsImplementing<IBotTick>().ToArray(); tickModules = p.PlayerActor.TraitsImplementing<IBotTick>().ToArray();
supportPowerManager = new AISupportPowerManager(this, p);
foreach (var building in Info.BuildingQueues) foreach (var building in Info.BuildingQueues)
builders.Add(new BaseBuilder(this, building, p, playerPower, playerResource)); builders.Add(new BaseBuilder(this, building, p, playerPower, playerResource));
foreach (var defense in Info.DefenseQueues) foreach (var defense in Info.DefenseQueues)
@@ -541,7 +522,6 @@ namespace OpenRA.Mods.Common.AI
AssignRolesToIdleUnits(self); AssignRolesToIdleUnits(self);
SetRallyPointsForNewProductionBuildings(self); SetRallyPointsForNewProductionBuildings(self);
supportPowerManager.TryToUseSupportPower(self);
foreach (var b in builders) foreach (var b in builders)
b.Tick(); b.Tick();

View File

@@ -125,7 +125,7 @@
<Compile Include="AI\BaseBuilder.cs" /> <Compile Include="AI\BaseBuilder.cs" />
<Compile Include="AI\HackyAI.cs" /> <Compile Include="AI\HackyAI.cs" />
<Compile Include="Traits\BotModules\HarvesterBotModule.cs" /> <Compile Include="Traits\BotModules\HarvesterBotModule.cs" />
<Compile Include="AI\AISupportPowerManager.cs" /> <Compile Include="Traits\BotModules\SupportPowerBotModule.cs" />
<Compile Include="AI\Squad.cs" /> <Compile Include="AI\Squad.cs" />
<Compile Include="AI\StateMachine.cs" /> <Compile Include="AI\StateMachine.cs" />
<Compile Include="AI\States\AirStates.cs" /> <Compile Include="AI\States\AirStates.cs" />
@@ -133,7 +133,7 @@
<Compile Include="AI\States\NavyStates.cs" /> <Compile Include="AI\States\NavyStates.cs" />
<Compile Include="AI\States\ProtectionStates.cs" /> <Compile Include="AI\States\ProtectionStates.cs" />
<Compile Include="AI\States\StateBase.cs" /> <Compile Include="AI\States\StateBase.cs" />
<Compile Include="AI\SupportPowerDecision.cs" /> <Compile Include="Traits\BotModules\BotModuleLogic\SupportPowerDecision.cs" />
<Compile Include="AudioLoaders\AudLoader.cs" /> <Compile Include="AudioLoaders\AudLoader.cs" />
<Compile Include="AudioLoaders\VocLoader.cs" /> <Compile Include="AudioLoaders\VocLoader.cs" />
<Compile Include="AudioLoaders\WavLoader.cs" /> <Compile Include="AudioLoaders\WavLoader.cs" />

View File

@@ -10,11 +10,11 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.AI;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.AI namespace OpenRA.Mods.Common.Traits
{ {
[Desc("Adds metadata for the AI bots.")] [Desc("Adds metadata for the AI bots.")]
public class SupportPowerDecision public class SupportPowerDecision
@@ -112,7 +112,7 @@ namespace OpenRA.Mods.Common.AI
return answer; return answer;
} }
public int GetNextScanTime(HackyAI ai) { return ai.Random.Next(MinimumScanTimeInterval, MaximumScanTimeInterval); } public int GetNextScanTime(World world) { return world.LocalRandom.Next(MinimumScanTimeInterval, MaximumScanTimeInterval); }
/// <summary>Makes up part of a decision, describing how to evaluate a target.</summary> /// <summary>Makes up part of a decision, describing how to evaluate a target.</summary>
public class Consideration public class Consideration

View File

@@ -10,37 +10,59 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Mods.Common.Traits; using System.Linq;
using OpenRA.Mods.Common.AI;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.AI namespace OpenRA.Mods.Common.Traits
{ {
class AISupportPowerManager [Desc("Manages bot support power handling.")]
public class SupportPowerBotModuleInfo : ConditionalTraitInfo, Requires<SupportPowerManagerInfo>
{
[Desc("Tells the AI how to use its support powers.")]
[FieldLoader.LoadUsing("LoadDecisions")]
public readonly List<SupportPowerDecision> Decisions = new List<SupportPowerDecision>();
static object LoadDecisions(MiniYaml yaml)
{
var ret = new List<SupportPowerDecision>();
var decisions = yaml.Nodes.FirstOrDefault(n => n.Key == "Decisions");
if (decisions != null)
foreach (var d in decisions.Value.Nodes)
ret.Add(new SupportPowerDecision(d.Value));
return ret;
}
public override object Create(ActorInitializer init) { return new SupportPowerBotModule(init.Self, this); }
}
public class SupportPowerBotModule : ConditionalTrait<SupportPowerBotModuleInfo>, IBotTick
{ {
readonly HackyAI ai;
readonly World world; readonly World world;
readonly Player player; readonly Player player;
readonly FrozenActorLayer frozenLayer; FrozenActorLayer frozenLayer;
readonly SupportPowerManager supportPowerManager; SupportPowerManager supportPowerManager;
Dictionary<SupportPowerInstance, int> waitingPowers = new Dictionary<SupportPowerInstance, int>(); Dictionary<SupportPowerInstance, int> waitingPowers = new Dictionary<SupportPowerInstance, int>();
Dictionary<string, SupportPowerDecision> powerDecisions = new Dictionary<string, SupportPowerDecision>(); Dictionary<string, SupportPowerDecision> powerDecisions = new Dictionary<string, SupportPowerDecision>();
public AISupportPowerManager(HackyAI ai, Player p) public SupportPowerBotModule(Actor self, SupportPowerBotModuleInfo info)
: base(info)
{ {
this.ai = ai; world = self.World;
world = p.World; player = self.Owner;
player = p; }
frozenLayer = p.PlayerActor.Trait<FrozenActorLayer>();
supportPowerManager = p.PlayerActor.TraitOrDefault<SupportPowerManager>(); protected override void TraitEnabled(Actor self)
foreach (var decision in ai.Info.SupportPowerDecisions) {
frozenLayer = player.PlayerActor.TraitOrDefault<FrozenActorLayer>();
supportPowerManager = player.PlayerActor.Trait<SupportPowerManager>();
foreach (var decision in Info.Decisions)
powerDecisions.Add(decision.OrderName, decision); powerDecisions.Add(decision.OrderName, decision);
} }
public void TryToUseSupportPower(Actor self) void IBotTick.BotTick(IBot bot)
{ {
if (supportPowerManager == null)
return;
foreach (var sp in supportPowerManager.Powers.Values) foreach (var sp in supportPowerManager.Powers.Values)
{ {
if (sp.Disabled) if (sp.Disabled)
@@ -68,7 +90,7 @@ namespace OpenRA.Mods.Common.AI
if (attackLocation == null) if (attackLocation == null)
{ {
AIUtils.BotDebug("AI: {1} can't find suitable coarse attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, player.PlayerName); AIUtils.BotDebug("AI: {1} can't find suitable coarse attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, player.PlayerName);
waitingPowers[sp] += powerDecision.GetNextScanTime(ai); waitingPowers[sp] += powerDecision.GetNextScanTime(world);
continue; continue;
} }
@@ -78,7 +100,7 @@ namespace OpenRA.Mods.Common.AI
if (attackLocation == null) if (attackLocation == null)
{ {
AIUtils.BotDebug("AI: {1} can't find suitable final attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, player.PlayerName); AIUtils.BotDebug("AI: {1} can't find suitable final attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, player.PlayerName);
waitingPowers[sp] += powerDecision.GetNextScanTime(ai); waitingPowers[sp] += powerDecision.GetNextScanTime(world);
continue; continue;
} }
@@ -86,7 +108,7 @@ namespace OpenRA.Mods.Common.AI
// Valid target found, delay by a few ticks to avoid rescanning before power fires via order // Valid target found, delay by a few ticks to avoid rescanning before power fires via order
AIUtils.BotDebug("AI: {2} found new target location {0} for support power {1}.", attackLocation, sp.Info.OrderName, player.PlayerName); AIUtils.BotDebug("AI: {2} found new target location {0} for support power {1}.", attackLocation, sp.Info.OrderName, player.PlayerName);
waitingPowers[sp] += 10; waitingPowers[sp] += 10;
ai.QueueOrder(new Order(sp.Key, supportPowerManager.Self, Target.FromCell(world, attackLocation.Value), false) { SuppressVisualFeedback = true }); bot.QueueOrder(new Order(sp.Key, supportPowerManager.Self, Target.FromCell(world, attackLocation.Value), false) { SuppressVisualFeedback = true });
} }
} }
} }
@@ -118,7 +140,7 @@ namespace OpenRA.Mods.Common.AI
var wbr = world.Map.CenterOfCell(br.ToCPos(map)); var wbr = world.Map.CenterOfCell(br.ToCPos(map));
var targets = world.ActorMap.ActorsInBox(wtl, wbr); var targets = world.ActorMap.ActorsInBox(wtl, wbr);
var frozenTargets = frozenLayer.FrozenActorsInRegion(region); var frozenTargets = frozenLayer != null ? frozenLayer.FrozenActorsInRegion(region) : Enumerable.Empty<FrozenActor>();
var consideredAttractiveness = powerDecision.GetAttractiveness(targets, player) + powerDecision.GetAttractiveness(frozenTargets, player); var consideredAttractiveness = powerDecision.GetAttractiveness(targets, player) + powerDecision.GetAttractiveness(frozenTargets, player);
if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness) if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness)
continue; continue;

View File

@@ -33,6 +33,11 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
"HarvesterEnemyAvoidanceRadius", "AssignRolesInterval" "HarvesterEnemyAvoidanceRadius", "AssignRolesInterval"
}; };
readonly string[] supportPowerFields =
{
"SupportPowerDecisions"
};
public override IEnumerable<string> AfterUpdate(ModData modData) public override IEnumerable<string> AfterUpdate(ModData modData)
{ {
var message = "You may want to check your AI yamls for possible redundant module entries.\n" + var message = "You may want to check your AI yamls for possible redundant module entries.\n" +
@@ -118,6 +123,21 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
requiresConditionNode.ReplaceValue(oldValue + " || " + conditionString); requiresConditionNode.ReplaceValue(oldValue + " || " + conditionString);
} }
} }
if (supportPowerFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
{
var spNode = new MiniYamlNode("SupportPowerBotModule@" + aiType, "");
spNode.AddNode(requiresCondition);
foreach (var spf in supportPowerFields)
{
var fieldNode = hackyAINode.LastChildMatching(spf);
if (fieldNode != null)
fieldNode.MoveAndRenameNode(hackyAINode, spNode, "Decisions");
}
addNodes.Add(spNode);
}
} }
addNodes.Add(defaultHarvNode); addNodes.Add(defaultHarvNode);

View File

@@ -71,65 +71,6 @@ Player:
UnitLimits: UnitLimits:
harv: 8 harv: 8
SquadSize: 15 SquadSize: 15
SupportPowerDecisions:
Airstrike:
OrderName: AirstrikePowerInfoOrder
MinimumAttractiveness: 2000
Consideration@1:
Against: Enemy
Types: Vehicle, Infantry
Attractiveness: 3
TargetMetric: Value
CheckRadius: 2c0
Consideration@2:
Against: Ally
Types: Ground, Water
Attractiveness: -20
TargetMetric: Value
CheckRadius: 2c0
Consideration@3:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: Value
CheckRadius: 2c0
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
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: HackyAI@Watson:
Name: Watson Name: Watson
Type: watson Type: watson
@@ -202,65 +143,6 @@ Player:
UnitLimits: UnitLimits:
harv: 8 harv: 8
SquadSize: 15 SquadSize: 15
SupportPowerDecisions:
Airstrike:
OrderName: AirstrikePowerInfoOrder
MinimumAttractiveness: 2000
Consideration@1:
Against: Enemy
Types: Vehicle, Infantry
Attractiveness: 3
TargetMetric: Value
CheckRadius: 2c0
Consideration@2:
Against: Ally
Types: Ground, Water
Attractiveness: -20
TargetMetric: Value
CheckRadius: 2c0
Consideration@3:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: Value
CheckRadius: 2c0
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
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: HackyAI@HAL9001:
Name: HAL 9001 Name: HAL 9001
Type: hal9001 Type: hal9001
@@ -335,7 +217,9 @@ Player:
UnitLimits: UnitLimits:
harv: 8 harv: 8
SquadSize: 8 SquadSize: 8
SupportPowerDecisions: SupportPowerBotModule:
RequiresCondition: enable-cabal-ai || enable-watson-ai || enable-hal9001-ai
Decisions:
Airstrike: Airstrike:
OrderName: AirstrikePowerInfoOrder OrderName: AirstrikePowerInfoOrder
MinimumAttractiveness: 2000 MinimumAttractiveness: 2000

View File

@@ -83,47 +83,6 @@ Player:
carryall: 4 carryall: 4
SquadSize: 8 SquadSize: 8
MaxBaseRadius: 40 MaxBaseRadius: 40
SupportPowerDecisions:
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
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
Fremen:
OrderName: ProduceActorPower.Fremen
Consideration@1:
Against: Ally
HackyAI@Vidius: HackyAI@Vidius:
Name: Vidious Name: Vidious
Type: vidious Type: vidious
@@ -208,47 +167,6 @@ Player:
carryall: 4 carryall: 4
SquadSize: 6 SquadSize: 6
MaxBaseRadius: 40 MaxBaseRadius: 40
SupportPowerDecisions:
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
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
Fremen:
OrderName: ProduceActorPower.Fremen
Consideration@1:
Against: Ally
HackyAI@Gladius: HackyAI@Gladius:
Name: Gladius Name: Gladius
Type: gladius Type: gladius
@@ -332,7 +250,9 @@ Player:
carryall: 4 carryall: 4
SquadSize: 10 SquadSize: 10
MaxBaseRadius: 40 MaxBaseRadius: 40
SupportPowerDecisions: SupportPowerBotModule:
RequiresCondition: enable-omnius-ai || enable-vidious-ai || enable-gladius-ai
Decisions:
Airstrike: Airstrike:
OrderName: AirstrikePowerInfoOrder OrderName: AirstrikePowerInfoOrder
MinimumAttractiveness: 2000 MinimumAttractiveness: 2000

View File

@@ -71,55 +71,6 @@ Player:
jeep: 4 jeep: 4
ftrk: 4 ftrk: 4
SquadSize: 20 SquadSize: 20
SupportPowerDecisions:
spyplane:
OrderName: SovietSpyPlane
MinimumAttractiveness: 1
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 5c0
paratroopers:
OrderName: SovietParatroopers
MinimumAttractiveness: 5
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 8c0
Consideration@2:
Against: Enemy
Types: Water
Attractiveness: -5
TargetMetric: None
CheckRadius: 8c0
parabombs:
OrderName: UkraineParabombs
MinimumAttractiveness: 1
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 5c0
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: HackyAI@NormalAI:
Name: Normal AI Name: Normal AI
Type: normal Type: normal
@@ -211,55 +162,6 @@ Player:
jeep: 4 jeep: 4
ftrk: 4 ftrk: 4
SquadSize: 40 SquadSize: 40
SupportPowerDecisions:
spyplane:
OrderName: SovietSpyPlane
MinimumAttractiveness: 1
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 5c0
paratroopers:
OrderName: SovietParatroopers
MinimumAttractiveness: 5
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 8c0
Consideration@2:
Against: Enemy
Types: Water
Attractiveness: -5
TargetMetric: None
CheckRadius: 8c0
parabombs:
OrderName: UkraineParabombs
MinimumAttractiveness: 1
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 5c0
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: HackyAI@TurtleAI:
Name: Turtle AI Name: Turtle AI
Type: turtle Type: turtle
@@ -352,55 +254,6 @@ Player:
jeep: 4 jeep: 4
ftrk: 4 ftrk: 4
SquadSize: 10 SquadSize: 10
SupportPowerDecisions:
spyplane:
OrderName: SovietSpyPlane
MinimumAttractiveness: 1
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 5c0
paratroopers:
OrderName: SovietParatroopers
MinimumAttractiveness: 5
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 8c0
Consideration@2:
Against: Enemy
Types: Water
Attractiveness: -5
TargetMetric: None
CheckRadius: 8c0
parabombs:
OrderName: UkraineParabombs
MinimumAttractiveness: 1
Consideration@1:
Against: Enemy
Types: Structure
Attractiveness: 1
TargetMetric: None
CheckRadius: 5c0
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: HackyAI@NavalAI:
Name: Naval AI Name: Naval AI
Type: naval Type: naval
@@ -468,7 +321,9 @@ Player:
UnitLimits: UnitLimits:
harv: 8 harv: 8
SquadSize: 1 SquadSize: 1
SupportPowerDecisions: SupportPowerBotModule:
RequiresCondition: enable-rush-ai || enable-normal-ai || enable-turtle-ai || enable-naval-ai
Decisions:
spyplane: spyplane:
OrderName: SovietSpyPlane OrderName: SovietSpyPlane
MinimumAttractiveness: 1 MinimumAttractiveness: 1