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.")]
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`).",
"Leave this empty to disable capturing.")]
public HashSet<string> CapturingActorTypes = new HashSet<string>();
@@ -225,17 +220,6 @@ namespace OpenRA.Mods.Common.AI
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.Name { get { return Name; } }
@@ -245,6 +229,7 @@ namespace OpenRA.Mods.Common.AI
public sealed class HackyAI : ITick, IBot, INotifyDamage
{
// DEPRECATED: Modules should use World.LocalRandom.
public MersenneTwister Random { get; private set; }
public readonly HackyAIInfo Info;
@@ -275,8 +260,6 @@ namespace OpenRA.Mods.Common.AI
BitArray resourceTypeIndices;
AISupportPowerManager supportPowerManager;
List<BaseBuilder> builders = new List<BaseBuilder>();
List<Actor> unitsHangingAroundTheBase = new List<Actor>();
@@ -324,8 +307,6 @@ namespace OpenRA.Mods.Common.AI
playerResource = p.PlayerActor.Trait<PlayerResources>();
tickModules = p.PlayerActor.TraitsImplementing<IBotTick>().ToArray();
supportPowerManager = new AISupportPowerManager(this, p);
foreach (var building in Info.BuildingQueues)
builders.Add(new BaseBuilder(this, building, p, playerPower, playerResource));
foreach (var defense in Info.DefenseQueues)
@@ -541,7 +522,6 @@ namespace OpenRA.Mods.Common.AI
AssignRolesToIdleUnits(self);
SetRallyPointsForNewProductionBuildings(self);
supportPowerManager.TryToUseSupportPower(self);
foreach (var b in builders)
b.Tick();

View File

@@ -125,7 +125,7 @@
<Compile Include="AI\BaseBuilder.cs" />
<Compile Include="AI\HackyAI.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\StateMachine.cs" />
<Compile Include="AI\States\AirStates.cs" />
@@ -133,7 +133,7 @@
<Compile Include="AI\States\NavyStates.cs" />
<Compile Include="AI\States\ProtectionStates.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\VocLoader.cs" />
<Compile Include="AudioLoaders\WavLoader.cs" />

View File

@@ -10,11 +10,11 @@
#endregion
using System.Collections.Generic;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.AI;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.AI
namespace OpenRA.Mods.Common.Traits
{
[Desc("Adds metadata for the AI bots.")]
public class SupportPowerDecision
@@ -112,7 +112,7 @@ namespace OpenRA.Mods.Common.AI
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>
public class Consideration

View File

@@ -10,37 +10,59 @@
#endregion
using System.Collections.Generic;
using OpenRA.Mods.Common.Traits;
using System.Linq;
using OpenRA.Mods.Common.AI;
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 Player player;
readonly FrozenActorLayer frozenLayer;
readonly SupportPowerManager supportPowerManager;
FrozenActorLayer frozenLayer;
SupportPowerManager supportPowerManager;
Dictionary<SupportPowerInstance, int> waitingPowers = new Dictionary<SupportPowerInstance, int>();
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 = p.World;
player = p;
frozenLayer = p.PlayerActor.Trait<FrozenActorLayer>();
supportPowerManager = p.PlayerActor.TraitOrDefault<SupportPowerManager>();
foreach (var decision in ai.Info.SupportPowerDecisions)
world = self.World;
player = self.Owner;
}
protected override void TraitEnabled(Actor self)
{
frozenLayer = player.PlayerActor.TraitOrDefault<FrozenActorLayer>();
supportPowerManager = player.PlayerActor.Trait<SupportPowerManager>();
foreach (var decision in Info.Decisions)
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)
{
if (sp.Disabled)
@@ -68,7 +90,7 @@ namespace OpenRA.Mods.Common.AI
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);
waitingPowers[sp] += powerDecision.GetNextScanTime(ai);
waitingPowers[sp] += powerDecision.GetNextScanTime(world);
continue;
}
@@ -78,7 +100,7 @@ namespace OpenRA.Mods.Common.AI
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);
waitingPowers[sp] += powerDecision.GetNextScanTime(ai);
waitingPowers[sp] += powerDecision.GetNextScanTime(world);
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
AIUtils.BotDebug("AI: {2} found new target location {0} for support power {1}.", attackLocation, sp.Info.OrderName, player.PlayerName);
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 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);
if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness)
continue;

View File

@@ -33,6 +33,11 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
"HarvesterEnemyAvoidanceRadius", "AssignRolesInterval"
};
readonly string[] supportPowerFields =
{
"SupportPowerDecisions"
};
public override IEnumerable<string> AfterUpdate(ModData modData)
{
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);
}
}
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);

View File

@@ -71,65 +71,6 @@ Player:
UnitLimits:
harv: 8
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:
Name: Watson
Type: watson
@@ -202,65 +143,6 @@ Player:
UnitLimits:
harv: 8
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:
Name: HAL 9001
Type: hal9001
@@ -335,7 +217,9 @@ Player:
UnitLimits:
harv: 8
SquadSize: 8
SupportPowerDecisions:
SupportPowerBotModule:
RequiresCondition: enable-cabal-ai || enable-watson-ai || enable-hal9001-ai
Decisions:
Airstrike:
OrderName: AirstrikePowerInfoOrder
MinimumAttractiveness: 2000

View File

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

View File

@@ -71,55 +71,6 @@ Player:
jeep: 4
ftrk: 4
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:
Name: Normal AI
Type: normal
@@ -211,55 +162,6 @@ Player:
jeep: 4
ftrk: 4
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:
Name: Turtle AI
Type: turtle
@@ -352,55 +254,6 @@ Player:
jeep: 4
ftrk: 4
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:
Name: Naval AI
Type: naval
@@ -468,7 +321,9 @@ Player:
UnitLimits:
harv: 8
SquadSize: 1
SupportPowerDecisions:
SupportPowerBotModule:
RequiresCondition: enable-rush-ai || enable-normal-ai || enable-turtle-ai || enable-naval-ai
Decisions:
spyplane:
OrderName: SovietSpyPlane
MinimumAttractiveness: 1