Convert AIHarvesterManager into *Module
This commit is contained in:
@@ -1,94 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2018 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, 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.Mods.Common.Pathfinder;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.AI
|
||||
{
|
||||
class AIHarvesterManager
|
||||
{
|
||||
readonly HackyAI ai;
|
||||
readonly World world;
|
||||
readonly IPathFinder pathfinder;
|
||||
readonly DomainIndex domainIndex;
|
||||
readonly ResourceLayer resLayer;
|
||||
readonly ResourceClaimLayer claimLayer;
|
||||
|
||||
public AIHarvesterManager(HackyAI ai, Player p)
|
||||
{
|
||||
this.ai = ai;
|
||||
world = p.World;
|
||||
pathfinder = world.WorldActor.Trait<IPathFinder>();
|
||||
domainIndex = world.WorldActor.Trait<DomainIndex>();
|
||||
resLayer = world.WorldActor.TraitOrDefault<ResourceLayer>();
|
||||
claimLayer = world.WorldActor.TraitOrDefault<ResourceClaimLayer>();
|
||||
}
|
||||
|
||||
CPos FindNextResource(Actor actor, Harvester harv)
|
||||
{
|
||||
var locomotorInfo = actor.Info.TraitInfo<MobileInfo>().LocomotorInfo;
|
||||
|
||||
Func<CPos, bool> isValidResource = cell =>
|
||||
domainIndex.IsPassable(actor.Location, cell, locomotorInfo) &&
|
||||
harv.CanHarvestCell(actor, cell) &&
|
||||
claimLayer.CanClaimCell(actor, cell);
|
||||
|
||||
var path = pathfinder.FindPath(
|
||||
PathSearch.Search(world, locomotorInfo, actor, true, isValidResource)
|
||||
.WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), ai.Info.HarvesterEnemyAvoidanceRadius)
|
||||
.Where(u => !u.IsDead && actor.Owner.Stances[u.Owner] == Stance.Enemy)
|
||||
.Sum(u => Math.Max(WDist.Zero.Length, ai.Info.HarvesterEnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length)))
|
||||
.FromPoint(actor.Location));
|
||||
|
||||
if (path.Count == 0)
|
||||
return CPos.Zero;
|
||||
|
||||
return path[0];
|
||||
}
|
||||
|
||||
public void Tick(List<Actor> harvesters)
|
||||
{
|
||||
if (resLayer == null || resLayer.IsResourceLayerEmpty)
|
||||
return;
|
||||
|
||||
// Find idle harvesters and give them orders:
|
||||
foreach (var harvester in harvesters)
|
||||
{
|
||||
var harv = harvester.Trait<Harvester>();
|
||||
if (!harv.IsEmpty)
|
||||
continue;
|
||||
|
||||
if (!harvester.IsIdle)
|
||||
{
|
||||
var act = harvester.CurrentActivity;
|
||||
if (!harv.LastSearchFailed || act.NextActivity == null || act.NextActivity.GetType() != typeof(FindResources))
|
||||
continue;
|
||||
}
|
||||
|
||||
var para = harvester.TraitOrDefault<Parachutable>();
|
||||
if (para != null && para.IsInAir)
|
||||
continue;
|
||||
|
||||
// Tell the idle harvester to quit slacking:
|
||||
var newSafeResourcePatch = FindNextResource(harvester, harv);
|
||||
HackyAI.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(harvester, newSafeResourcePatch));
|
||||
ai.QueueOrder(new Order("Harvest", harvester, Target.FromCell(world, newSafeResourcePatch), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,7 +281,6 @@ namespace OpenRA.Mods.Common.AI
|
||||
|
||||
BitArray resourceTypeIndices;
|
||||
|
||||
AIHarvesterManager harvManager;
|
||||
AISupportPowerManager supportPowerManager;
|
||||
|
||||
List<BaseBuilder> builders = new List<BaseBuilder>();
|
||||
@@ -291,10 +290,6 @@ namespace OpenRA.Mods.Common.AI
|
||||
// Units that the ai already knows about. Any unit not on this list needs to be given a role.
|
||||
List<Actor> activeUnits = new List<Actor>();
|
||||
|
||||
// Harvesters are usually listed under ExcludeFromSquads, so they're not included in the activeUnits list, but still needed in AIHarvesterManager.
|
||||
// TODO: Consider adding an explicit UnitsCommonNames.Harvester category.
|
||||
List<Actor> harvesters = new List<Actor>();
|
||||
|
||||
public const int FeedbackTime = 30; // ticks; = a bit over 1s. must be >= netlag.
|
||||
|
||||
public readonly World World;
|
||||
@@ -335,7 +330,6 @@ namespace OpenRA.Mods.Common.AI
|
||||
playerResource = p.PlayerActor.Trait<PlayerResources>();
|
||||
botOrderManager = p.PlayerActor.Trait<BotOrderManager>();
|
||||
|
||||
harvManager = new AIHarvesterManager(this, p);
|
||||
supportPowerManager = new AISupportPowerManager(this, p);
|
||||
|
||||
foreach (var building in Info.BuildingQueues)
|
||||
@@ -600,7 +594,6 @@ namespace OpenRA.Mods.Common.AI
|
||||
|
||||
activeUnits.RemoveAll(unitCannotBeOrdered);
|
||||
unitsHangingAroundTheBase.RemoveAll(unitCannotBeOrdered);
|
||||
harvesters.RemoveAll(unitCannotBeOrdered);
|
||||
|
||||
if (--rushTicks <= 0)
|
||||
{
|
||||
@@ -619,7 +612,6 @@ namespace OpenRA.Mods.Common.AI
|
||||
{
|
||||
assignRolesTicks = Info.AssignRolesInterval;
|
||||
FindNewUnits(self);
|
||||
harvManager.Tick(harvesters);
|
||||
InitializeBase(self, true);
|
||||
}
|
||||
|
||||
@@ -723,13 +715,10 @@ namespace OpenRA.Mods.Common.AI
|
||||
void FindNewUnits(Actor self)
|
||||
{
|
||||
var newUnits = self.World.ActorsHavingTrait<IPositionable>()
|
||||
.Where(a => a.Owner == Player && !activeUnits.Contains(a) && !harvesters.Contains(a));
|
||||
.Where(a => a.Owner == Player && !activeUnits.Contains(a));
|
||||
|
||||
foreach (var a in newUnits)
|
||||
{
|
||||
if (a.Info.HasTraitInfo<HarvesterInfo>())
|
||||
harvesters.Add(a);
|
||||
|
||||
if (Info.UnitsCommonNames.Mcv.Contains(a.Info.Name) || Info.UnitsCommonNames.ExcludeFromSquads.Contains(a.Info.Name))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
<Compile Include="AI\BaseBuilder.cs" />
|
||||
<Compile Include="AI\BotOrderManager.cs" />
|
||||
<Compile Include="AI\HackyAI.cs" />
|
||||
<Compile Include="AI\AIHarvesterManager.cs" />
|
||||
<Compile Include="Traits\BotModules\HarvesterBotModule.cs" />
|
||||
<Compile Include="AI\AISupportPowerManager.cs" />
|
||||
<Compile Include="AI\Squad.cs" />
|
||||
<Compile Include="AI\StateMachine.cs" />
|
||||
@@ -937,6 +937,7 @@
|
||||
<Compile Include="UpdateRules\Rules\20180923\AddRearmable.cs" />
|
||||
<Compile Include="UpdateRules\Rules\20180923\MergeAttackPlaneAndHeli.cs" />
|
||||
<Compile Include="UpdateRules\Rules\20180923\AddBotOrderManager.cs" />
|
||||
<Compile Include="UpdateRules\Rules\20180923\AddHarvesterBotModule.cs" />
|
||||
<Compile Include="Traits\Player\PlayerResources.cs" />
|
||||
<Compile Include="UtilityCommands\DumpSequenceSheetsCommand.cs" />
|
||||
<Compile Include="Traits\Render\WithBuildingRepairDecoration.cs" />
|
||||
|
||||
133
OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs
Normal file
133
OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2018 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, 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.Mods.Common.AI;
|
||||
using OpenRA.Mods.Common.Pathfinder;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Put this on the Player actor. Manages bot harvesters to ensure they always continue harvesting as long as there are resources on the map.")]
|
||||
public class HarvesterBotModuleInfo : ConditionalTraitInfo, Requires<BotOrderManagerInfo>
|
||||
{
|
||||
[Desc("Interval (in ticks) between giving out orders to idle harvesters.")]
|
||||
public readonly int ScanForIdleHarvestersInterval = 20;
|
||||
|
||||
[Desc("Avoid enemy actors nearby when searching for a new resource patch. Should be somewhere near the max weapon range.")]
|
||||
public readonly WDist HarvesterEnemyAvoidanceRadius = WDist.FromCells(8);
|
||||
|
||||
public override object Create(ActorInitializer init) { return new HarvesterBotModule(init.Self, this); }
|
||||
}
|
||||
|
||||
public class HarvesterBotModule : ConditionalTrait<HarvesterBotModuleInfo>, ITick
|
||||
{
|
||||
readonly World world;
|
||||
readonly Player player;
|
||||
readonly Predicate<Actor> unitCannotBeOrdered;
|
||||
IPathFinder pathfinder;
|
||||
DomainIndex domainIndex;
|
||||
ResourceLayer resLayer;
|
||||
ResourceClaimLayer claimLayer;
|
||||
BotOrderManager botOrderManager;
|
||||
List<Actor> harvesters = new List<Actor>();
|
||||
int scanForIdleHarvestersTicks;
|
||||
|
||||
public HarvesterBotModule(Actor self, HarvesterBotModuleInfo info)
|
||||
: base(info)
|
||||
{
|
||||
world = self.World;
|
||||
player = self.Owner;
|
||||
unitCannotBeOrdered = a => a.Owner != self.Owner || a.IsDead || !a.IsInWorld;
|
||||
}
|
||||
|
||||
protected override void TraitEnabled(Actor self)
|
||||
{
|
||||
pathfinder = world.WorldActor.Trait<IPathFinder>();
|
||||
domainIndex = world.WorldActor.Trait<DomainIndex>();
|
||||
resLayer = world.WorldActor.TraitOrDefault<ResourceLayer>();
|
||||
claimLayer = world.WorldActor.TraitOrDefault<ResourceClaimLayer>();
|
||||
botOrderManager = self.Owner.PlayerActor.Trait<BotOrderManager>();
|
||||
scanForIdleHarvestersTicks = Info.ScanForIdleHarvestersInterval;
|
||||
}
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
{
|
||||
if (IsTraitDisabled)
|
||||
return;
|
||||
|
||||
if (resLayer == null || resLayer.IsResourceLayerEmpty)
|
||||
return;
|
||||
|
||||
if (--scanForIdleHarvestersTicks > 0)
|
||||
return;
|
||||
|
||||
harvesters.RemoveAll(unitCannotBeOrdered);
|
||||
scanForIdleHarvestersTicks = Info.ScanForIdleHarvestersInterval;
|
||||
|
||||
// Find new harvesters
|
||||
// TODO: Look for a more performance-friendly way to update this list
|
||||
var newHarvesters = world.ActorsHavingTrait<Harvester>().Where(a => a.Owner == player && !harvesters.Contains(a));
|
||||
foreach (var a in newHarvesters)
|
||||
harvesters.Add(a);
|
||||
|
||||
// Find idle harvesters and give them orders:
|
||||
foreach (var harvester in harvesters)
|
||||
{
|
||||
var harv = harvester.Trait<Harvester>();
|
||||
if (!harv.IsEmpty)
|
||||
continue;
|
||||
|
||||
if (!harvester.IsIdle)
|
||||
{
|
||||
var act = harvester.CurrentActivity;
|
||||
if (!harv.LastSearchFailed || act.NextActivity == null || act.NextActivity.GetType() != typeof(FindResources))
|
||||
continue;
|
||||
}
|
||||
|
||||
var para = harvester.TraitOrDefault<Parachutable>();
|
||||
if (para != null && para.IsInAir)
|
||||
continue;
|
||||
|
||||
// Tell the idle harvester to quit slacking:
|
||||
var newSafeResourcePatch = FindNextResource(harvester, harv);
|
||||
AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(harvester, newSafeResourcePatch));
|
||||
botOrderManager.QueueOrder(new Order("Harvest", harvester, Target.FromCell(world, newSafeResourcePatch), false));
|
||||
}
|
||||
}
|
||||
|
||||
CPos FindNextResource(Actor actor, Harvester harv)
|
||||
{
|
||||
var locomotorInfo = actor.Info.TraitInfo<MobileInfo>().LocomotorInfo;
|
||||
|
||||
Func<CPos, bool> isValidResource = cell =>
|
||||
domainIndex.IsPassable(actor.Location, cell, locomotorInfo) &&
|
||||
harv.CanHarvestCell(actor, cell) &&
|
||||
claimLayer.CanClaimCell(actor, cell);
|
||||
|
||||
var path = pathfinder.FindPath(
|
||||
PathSearch.Search(world, locomotorInfo, actor, true, isValidResource)
|
||||
.WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius)
|
||||
.Where(u => !u.IsDead && actor.Owner.Stances[u.Owner] == Stance.Enemy)
|
||||
.Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length)))
|
||||
.FromPoint(actor.Location));
|
||||
|
||||
if (path.Count == 0)
|
||||
return CPos.Zero;
|
||||
|
||||
return path[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2018 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, 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;
|
||||
|
||||
namespace OpenRA.Mods.Common.UpdateRules.Rules
|
||||
{
|
||||
public class AddHarvesterBotModule : UpdateRule
|
||||
{
|
||||
public override string Name { get { return "Split HackyAI harvester handling to HarvesterBotModule"; } }
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Some properties and all harvester handling have been moved from HackyAI\n" +
|
||||
"to the new HarvesterBotModule.";
|
||||
}
|
||||
}
|
||||
|
||||
bool messageShown;
|
||||
|
||||
readonly string[] harvesterFields =
|
||||
{
|
||||
"HarvesterEnemyAvoidanceRadius", "AssignRolesInterval"
|
||||
};
|
||||
|
||||
public override IEnumerable<string> AfterUpdate(ModData modData)
|
||||
{
|
||||
var message = "You may want to check your AI yamls for possible redundant module entries.\n" +
|
||||
"Additionally, make sure the Player actor has the ConditionManager trait and add it manually if it doesn't.";
|
||||
|
||||
if (!messageShown)
|
||||
yield return message;
|
||||
|
||||
messageShown = true;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
|
||||
{
|
||||
if (actorNode.Key != "Player")
|
||||
yield break;
|
||||
|
||||
var hackyAIs = actorNode.ChildrenMatching("HackyAI");
|
||||
if (!hackyAIs.Any())
|
||||
yield break;
|
||||
|
||||
var addNodes = new List<MiniYamlNode>();
|
||||
|
||||
// We add a 'default' HarvesterBotModule in any case,
|
||||
// and only add more for AIs that define custom values for one of its fields.
|
||||
var defaultHarvNode = new MiniYamlNode("HarvesterBotModule", "");
|
||||
|
||||
foreach (var hackyAINode in hackyAIs)
|
||||
{
|
||||
// HackyAIInfo.Name might contain spaces, so Type is better suited to be used as condition name
|
||||
var aiType = hackyAINode.LastChildMatching("Type").NodeValue<string>();
|
||||
var conditionString = "enable-" + aiType + "-ai";
|
||||
var requiresCondition = new MiniYamlNode("RequiresCondition", conditionString);
|
||||
var conditionNode = hackyAINode.LastChildMatching("Condition");
|
||||
if (conditionNode == null)
|
||||
{
|
||||
var enableModule = new MiniYamlNode("Condition", conditionString);
|
||||
hackyAINode.AddNode(enableModule);
|
||||
}
|
||||
|
||||
if (harvesterFields.Any(f => hackyAINode.ChildrenMatching(f).Any()))
|
||||
{
|
||||
var harvNode = new MiniYamlNode("HarvesterBotModule@" + aiType, "");
|
||||
harvNode.AddNode(requiresCondition);
|
||||
|
||||
foreach (var hf in harvesterFields)
|
||||
{
|
||||
var fieldNode = hackyAINode.LastChildMatching(hf);
|
||||
if (fieldNode != null)
|
||||
{
|
||||
if (hf == "AssignRolesInterval")
|
||||
fieldNode.MoveAndRenameNode(hackyAINode, harvNode, "ScanForIdleHarvestersInterval");
|
||||
else
|
||||
fieldNode.MoveNode(hackyAINode, harvNode);
|
||||
}
|
||||
}
|
||||
|
||||
addNodes.Add(harvNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We want the default module to be enabled for every AI that didn't customise one of its fields,
|
||||
// so we need to update RequiresCondition to be enabled on any of the conditions granted by these AIs,
|
||||
// but only if the condition hasn't been added yet.
|
||||
var requiresConditionNode = defaultHarvNode.LastChildMatching("RequiresCondition");
|
||||
if (requiresConditionNode == null)
|
||||
defaultHarvNode.AddNode(requiresCondition);
|
||||
else
|
||||
{
|
||||
var oldValue = requiresConditionNode.NodeValue<string>();
|
||||
if (oldValue.Contains(conditionString))
|
||||
continue;
|
||||
|
||||
requiresConditionNode.ReplaceValue(oldValue + " || " + conditionString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addNodes.Add(defaultHarvNode);
|
||||
|
||||
foreach (var node in addNodes)
|
||||
actorNode.AddNode(node);
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,7 @@ namespace OpenRA.Mods.Common.UpdateRules
|
||||
new RequireProductionType(),
|
||||
new CloakRequiresConditionToPause(),
|
||||
new AddBotOrderManager(),
|
||||
new AddHarvesterBotModule(),
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ Player:
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
Condition: enable-cabal-ai
|
||||
HackyAI@Watson:
|
||||
Name: Watson
|
||||
Type: watson
|
||||
@@ -262,6 +263,7 @@ Player:
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
Condition: enable-watson-ai
|
||||
HackyAI@HAL9001:
|
||||
Name: HAL 9001
|
||||
Type: hal9001
|
||||
@@ -395,3 +397,6 @@ Player:
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
Condition: enable-hal9001-ai
|
||||
HarvesterBotModule:
|
||||
RequiresCondition: enable-cabal-ai || enable-watson-ai || enable-hal9001-ai
|
||||
|
||||
@@ -58,3 +58,4 @@ Player:
|
||||
GrantConditionOnPrerequisiteManager:
|
||||
ResourceStorageWarning:
|
||||
PlayerExperience:
|
||||
ConditionManager:
|
||||
|
||||
@@ -125,6 +125,7 @@ Player:
|
||||
OrderName: ProduceActorPower.Fremen
|
||||
Consideration@1:
|
||||
Against: Ally
|
||||
Condition: enable-omnius-ai
|
||||
HackyAI@Vidius:
|
||||
Name: Vidious
|
||||
Type: vidious
|
||||
@@ -250,6 +251,7 @@ Player:
|
||||
OrderName: ProduceActorPower.Fremen
|
||||
Consideration@1:
|
||||
Against: Ally
|
||||
Condition: enable-vidious-ai
|
||||
HackyAI@Gladius:
|
||||
Name: Gladius
|
||||
Type: gladius
|
||||
@@ -374,3 +376,6 @@ Player:
|
||||
OrderName: ProduceActorPower.Fremen
|
||||
Consideration@1:
|
||||
Against: Ally
|
||||
Condition: enable-gladius-ai
|
||||
HarvesterBotModule:
|
||||
RequiresCondition: enable-omnius-ai || enable-vidious-ai || enable-gladius-ai
|
||||
|
||||
@@ -144,3 +144,4 @@ Player:
|
||||
ResourceStorageWarning:
|
||||
AdviceInterval: 26
|
||||
PlayerExperience:
|
||||
ConditionManager:
|
||||
|
||||
@@ -105,6 +105,8 @@ Player:
|
||||
DefaultCashDropdownLocked: True
|
||||
DefaultCashDropdownVisible: False
|
||||
DefaultCash: 50
|
||||
-ConditionManager:
|
||||
-HarvesterBotModule:
|
||||
-HackyAI@RushAI:
|
||||
-HackyAI@NormalAI:
|
||||
-HackyAI@NavalAI:
|
||||
|
||||
@@ -121,6 +121,7 @@ Player:
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
Condition: enable-rush-ai
|
||||
HackyAI@NormalAI:
|
||||
Name: Normal AI
|
||||
Type: normal
|
||||
@@ -261,6 +262,7 @@ Player:
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
Condition: enable-normal-ai
|
||||
HackyAI@TurtleAI:
|
||||
Name: Turtle AI
|
||||
Type: turtle
|
||||
@@ -402,6 +404,7 @@ Player:
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
Condition: enable-turtle-ai
|
||||
HackyAI@NavalAI:
|
||||
Name: Naval AI
|
||||
Type: naval
|
||||
@@ -518,3 +521,6 @@ Player:
|
||||
Attractiveness: -10
|
||||
TargetMetric: Value
|
||||
CheckRadius: 7c0
|
||||
Condition: enable-naval-ai
|
||||
HarvesterBotModule:
|
||||
RequiresCondition: enable-rush-ai || enable-normal-ai || enable-turtle-ai || enable-naval-ai
|
||||
|
||||
@@ -143,3 +143,4 @@ Player:
|
||||
Sequence: veteran
|
||||
ResourceStorageWarning:
|
||||
PlayerExperience:
|
||||
ConditionManager:
|
||||
|
||||
@@ -78,3 +78,6 @@ Player:
|
||||
medic: 3
|
||||
repair: 3
|
||||
SquadSize: 20
|
||||
Condition: enable-test-ai
|
||||
HarvesterBotModule:
|
||||
RequiresCondition: enable-test-ai
|
||||
|
||||
@@ -114,3 +114,4 @@ Player:
|
||||
Id: unrestricted
|
||||
ResourceStorageWarning:
|
||||
PlayerExperience:
|
||||
ConditionManager:
|
||||
|
||||
Reference in New Issue
Block a user