Add a bot type identifier.
This commit is contained in:
@@ -106,8 +106,9 @@ namespace OpenRA
|
|||||||
Color = client.Color;
|
Color = client.Color;
|
||||||
if (client.Bot != null)
|
if (client.Bot != null)
|
||||||
{
|
{
|
||||||
|
var botInfo = world.Map.Rules.Actors["player"].TraitInfos<IBotInfo>().First(b => b.Type == client.Bot);
|
||||||
var botsOfSameType = world.LobbyInfo.Clients.Where(c => c.Bot == client.Bot).ToArray();
|
var botsOfSameType = world.LobbyInfo.Clients.Where(c => c.Bot == client.Bot).ToArray();
|
||||||
PlayerName = botsOfSameType.Length == 1 ? client.Bot : "{0} {1}".F(client.Bot, botsOfSameType.IndexOf(client) + 1);
|
PlayerName = botsOfSameType.Length == 1 ? botInfo.Name : "{0} {1}".F(botInfo.Name, botsOfSameType.IndexOf(client) + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PlayerName = client.Name;
|
PlayerName = client.Name;
|
||||||
@@ -139,7 +140,7 @@ namespace OpenRA
|
|||||||
IsBot = BotType != null;
|
IsBot = BotType != null;
|
||||||
if (IsBot && Game.IsHost)
|
if (IsBot && Game.IsHost)
|
||||||
{
|
{
|
||||||
var logic = PlayerActor.TraitsImplementing<IBot>().FirstOrDefault(b => b.Info.Name == BotType);
|
var logic = PlayerActor.TraitsImplementing<IBot>().FirstOrDefault(b => b.Info.Type == BotType);
|
||||||
if (logic == null)
|
if (logic == null)
|
||||||
Log.Write("debug", "Invalid bot type: {0}", BotType);
|
Log.Write("debug", "Invalid bot type: {0}", BotType);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -337,7 +337,12 @@ namespace OpenRA.Traits
|
|||||||
public interface IWorldLoaded { void WorldLoaded(World w, WorldRenderer wr); }
|
public interface IWorldLoaded { void WorldLoaded(World w, WorldRenderer wr); }
|
||||||
public interface ICreatePlayers { void CreatePlayers(World w); }
|
public interface ICreatePlayers { void CreatePlayers(World w); }
|
||||||
|
|
||||||
public interface IBotInfo : ITraitInfoInterface { string Name { get; } }
|
public interface IBotInfo : ITraitInfoInterface
|
||||||
|
{
|
||||||
|
string Type { get; }
|
||||||
|
string Name { get; }
|
||||||
|
}
|
||||||
|
|
||||||
public interface IBot
|
public interface IBot
|
||||||
{
|
{
|
||||||
void Activate(Player p);
|
void Activate(Player p);
|
||||||
|
|||||||
@@ -15,9 +15,15 @@ namespace OpenRA.Mods.Common.AI
|
|||||||
{
|
{
|
||||||
public sealed class DummyAIInfo : ITraitInfo, IBotInfo
|
public sealed class DummyAIInfo : ITraitInfo, IBotInfo
|
||||||
{
|
{
|
||||||
[Desc("Ingame name this bot uses.")]
|
[Desc("Human-readable name this bot uses.")]
|
||||||
public readonly string Name = "Unnamed Bot";
|
public readonly string Name = "Unnamed Bot";
|
||||||
|
|
||||||
|
[FieldLoader.Require]
|
||||||
|
[Desc("Internal id for this bot.")]
|
||||||
|
public readonly string Type = null;
|
||||||
|
|
||||||
|
string IBotInfo.Type { get { return Type; } }
|
||||||
|
|
||||||
string IBotInfo.Name { get { return Name; } }
|
string IBotInfo.Name { get { return Name; } }
|
||||||
|
|
||||||
public object Create(ActorInitializer init) { return new DummyAI(this); }
|
public object Create(ActorInitializer init) { return new DummyAI(this); }
|
||||||
|
|||||||
@@ -58,7 +58,11 @@ namespace OpenRA.Mods.Common.AI
|
|||||||
public readonly HashSet<string> Silo = new HashSet<string>();
|
public readonly HashSet<string> Silo = new HashSet<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Desc("Ingame name this bot uses.")]
|
[FieldLoader.Require]
|
||||||
|
[Desc("Internal id for this bot.")]
|
||||||
|
public readonly string Type = null;
|
||||||
|
|
||||||
|
[Desc("Human-readable name this bot uses.")]
|
||||||
public readonly string Name = "Unnamed Bot";
|
public readonly string Name = "Unnamed Bot";
|
||||||
|
|
||||||
[Desc("Minimum number of units AI must have before attacking.")]
|
[Desc("Minimum number of units AI must have before attacking.")]
|
||||||
@@ -162,8 +166,6 @@ namespace OpenRA.Mods.Common.AI
|
|||||||
[Desc("Should the AI repair its buildings if damaged?")]
|
[Desc("Should the AI repair its buildings if damaged?")]
|
||||||
public readonly bool ShouldRepairBuildings = true;
|
public readonly bool ShouldRepairBuildings = true;
|
||||||
|
|
||||||
string IBotInfo.Name { get { return Name; } }
|
|
||||||
|
|
||||||
[Desc("What units to the AI should build.", "What % of the total army must be this type of unit.")]
|
[Desc("What units to the AI should build.", "What % of the total army must be this type of unit.")]
|
||||||
public readonly Dictionary<string, float> UnitsToBuild = null;
|
public readonly Dictionary<string, float> UnitsToBuild = null;
|
||||||
|
|
||||||
@@ -233,6 +235,10 @@ namespace OpenRA.Mods.Common.AI
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string IBotInfo.Type { get { return Type; } }
|
||||||
|
|
||||||
|
string IBotInfo.Name { get { return Name; } }
|
||||||
|
|
||||||
public object Create(ActorInitializer init) { return new HackyAI(this, init); }
|
public object Create(ActorInitializer init) { return new HackyAI(this, init); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -280,8 +280,6 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var botType = parts.Skip(2).JoinWith(" ");
|
|
||||||
|
|
||||||
// Invalid slot
|
// Invalid slot
|
||||||
if (bot != null && bot.Bot == null)
|
if (bot != null && bot.Bot == null)
|
||||||
{
|
{
|
||||||
@@ -289,6 +287,16 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var botType = parts[2];
|
||||||
|
var botInfo = server.Map.Rules.Actors["player"].TraitInfos<IBotInfo>()
|
||||||
|
.FirstOrDefault(b => b.Type == botType);
|
||||||
|
|
||||||
|
if (botInfo == null)
|
||||||
|
{
|
||||||
|
server.SendOrderTo(conn, "Message", "Invalid bot type.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
slot.Closed = false;
|
slot.Closed = false;
|
||||||
if (bot == null)
|
if (bot == null)
|
||||||
{
|
{
|
||||||
@@ -296,7 +304,7 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
bot = new Session.Client()
|
bot = new Session.Client()
|
||||||
{
|
{
|
||||||
Index = server.ChooseFreePlayerIndex(),
|
Index = server.ChooseFreePlayerIndex(),
|
||||||
Name = botType,
|
Name = botInfo.Name,
|
||||||
Bot = botType,
|
Bot = botType,
|
||||||
Slot = parts[0],
|
Slot = parts[0],
|
||||||
Faction = "Random",
|
Faction = "Random",
|
||||||
@@ -319,7 +327,7 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Change the type of the existing bot
|
// Change the type of the existing bot
|
||||||
bot.Name = botType;
|
bot.Name = botInfo.Name;
|
||||||
bot.Bot = botType;
|
bot.Bot = botType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,7 +374,7 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
// - Players who now lack a slot are made observers
|
// - Players who now lack a slot are made observers
|
||||||
// - Bots who now lack a slot are dropped
|
// - Bots who now lack a slot are dropped
|
||||||
// - Bots who are not defined in the map rules are dropped
|
// - Bots who are not defined in the map rules are dropped
|
||||||
var botNames = server.Map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name);
|
var botTypes = server.Map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Type);
|
||||||
var slots = server.LobbyInfo.Slots.Keys.ToArray();
|
var slots = server.LobbyInfo.Slots.Keys.ToArray();
|
||||||
var i = 0;
|
var i = 0;
|
||||||
foreach (var os in oldSlots)
|
foreach (var os in oldSlots)
|
||||||
@@ -380,7 +388,7 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
if (c.Slot != null)
|
if (c.Slot != null)
|
||||||
{
|
{
|
||||||
// Remove Bot from slot if slot forbids bots
|
// Remove Bot from slot if slot forbids bots
|
||||||
if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botNames.Contains(c.Bot)))
|
if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botTypes.Contains(c.Bot)))
|
||||||
server.LobbyInfo.Clients.Remove(c);
|
server.LobbyInfo.Clients.Remove(c);
|
||||||
S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]);
|
S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -808,6 +808,19 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bots must now specify an internal type as well as their display name
|
||||||
|
if (engineVersion < 20170707)
|
||||||
|
{
|
||||||
|
if (node.Key.StartsWith("HackyAI", StringComparison.Ordinal) || node.Key.StartsWith("DummyAI", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var nameNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "Name");
|
||||||
|
|
||||||
|
// Just duplicate the name to avoid incompatibility with maps
|
||||||
|
if (nameNode != null)
|
||||||
|
node.Value.Nodes.Add(new MiniYamlNode("Type", nameNode.Value.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
|
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
slotsButton.OnMouseDown = _ =>
|
slotsButton.OnMouseDown = _ =>
|
||||||
{
|
{
|
||||||
var botNames = map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name);
|
var botTypes = map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Type);
|
||||||
var options = new Dictionary<string, IEnumerable<DropDownOption>>();
|
var options = new Dictionary<string, IEnumerable<DropDownOption>>();
|
||||||
|
|
||||||
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
||||||
@@ -215,7 +215,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
foreach (var slot in orderManager.LobbyInfo.Slots)
|
foreach (var slot in orderManager.LobbyInfo.Slots)
|
||||||
{
|
{
|
||||||
var bot = botNames.Random(Game.CosmeticRandom);
|
var bot = botTypes.Random(Game.CosmeticRandom);
|
||||||
var c = orderManager.LobbyInfo.ClientInSlot(slot.Key);
|
var c = orderManager.LobbyInfo.ClientInSlot(slot.Key);
|
||||||
if (slot.Value.AllowBots == true && (c == null || c.Bot != null))
|
if (slot.Value.AllowBots == true && (c == null || c.Bot != null))
|
||||||
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot.Key, botController.Index, bot)));
|
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot.Key, botController.Index, bot)));
|
||||||
@@ -621,7 +621,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
if (addBotOnMapLoad)
|
if (addBotOnMapLoad)
|
||||||
{
|
{
|
||||||
var slot = orderManager.LobbyInfo.FirstEmptyBotSlot();
|
var slot = orderManager.LobbyInfo.FirstEmptyBotSlot();
|
||||||
var bot = currentMap.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name).FirstOrDefault();
|
var bot = currentMap.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Type).FirstOrDefault();
|
||||||
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
||||||
if (slot != null && bot != null)
|
if (slot != null && bot != null)
|
||||||
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot, botController.Index, bot)));
|
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot, botController.Index, bot)));
|
||||||
|
|||||||
@@ -50,13 +50,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
var bots = new List<SlotDropDownOption>();
|
var bots = new List<SlotDropDownOption>();
|
||||||
if (slot.AllowBots)
|
if (slot.AllowBots)
|
||||||
{
|
{
|
||||||
foreach (var b in map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name))
|
foreach (var b in map.Rules.Actors["player"].TraitInfos<IBotInfo>())
|
||||||
{
|
{
|
||||||
var bot = b;
|
|
||||||
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
||||||
bots.Add(new SlotDropDownOption(bot,
|
bots.Add(new SlotDropDownOption(b.Name,
|
||||||
"slot_bot {0} {1} {2}".F(slot.PlayerReference, botController.Index, bot),
|
"slot_bot {0} {1} {2}".F(slot.PlayerReference, botController.Index, b.Type),
|
||||||
() => client != null && client.Bot == bot));
|
() => client != null && client.Bot == b.Type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
Player:
|
Player:
|
||||||
HackyAI@Cabal:
|
HackyAI@Cabal:
|
||||||
Name: Cabal
|
Name: Cabal
|
||||||
|
Type: Cabal
|
||||||
MinimumExcessPower: 60
|
MinimumExcessPower: 60
|
||||||
BuildingCommonNames:
|
BuildingCommonNames:
|
||||||
ConstructionYard: fact
|
ConstructionYard: fact
|
||||||
@@ -122,6 +123,7 @@ Player:
|
|||||||
CheckRadius: 7c0
|
CheckRadius: 7c0
|
||||||
HackyAI@Watson:
|
HackyAI@Watson:
|
||||||
Name: Watson
|
Name: Watson
|
||||||
|
Type: Watson
|
||||||
MinimumExcessPower: 60
|
MinimumExcessPower: 60
|
||||||
BuildingCommonNames:
|
BuildingCommonNames:
|
||||||
ConstructionYard: fact
|
ConstructionYard: fact
|
||||||
@@ -243,6 +245,7 @@ Player:
|
|||||||
CheckRadius: 7c0
|
CheckRadius: 7c0
|
||||||
HackyAI@HAL9001:
|
HackyAI@HAL9001:
|
||||||
Name: HAL 9001
|
Name: HAL 9001
|
||||||
|
Type: HAL 9001
|
||||||
MinimumExcessPower: 60
|
MinimumExcessPower: 60
|
||||||
BuildingCommonNames:
|
BuildingCommonNames:
|
||||||
ConstructionYard: fact
|
ConstructionYard: fact
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
Player:
|
Player:
|
||||||
HackyAI@Omnius:
|
HackyAI@Omnius:
|
||||||
Name: Omnius
|
Name: Omnius
|
||||||
|
Type: Omnius
|
||||||
MinimumExcessPower: 60
|
MinimumExcessPower: 60
|
||||||
BuildingQueues: Building, Upgrade
|
BuildingQueues: Building, Upgrade
|
||||||
UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft
|
UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft
|
||||||
@@ -119,6 +120,7 @@ Player:
|
|||||||
Against: Ally
|
Against: Ally
|
||||||
HackyAI@Vidius:
|
HackyAI@Vidius:
|
||||||
Name: Vidious
|
Name: Vidious
|
||||||
|
Type: Vidious
|
||||||
MinimumExcessPower: 60
|
MinimumExcessPower: 60
|
||||||
BuildingQueues: Building, Upgrade
|
BuildingQueues: Building, Upgrade
|
||||||
UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft
|
UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft
|
||||||
@@ -239,6 +241,7 @@ Player:
|
|||||||
Against: Ally
|
Against: Ally
|
||||||
HackyAI@Gladius:
|
HackyAI@Gladius:
|
||||||
Name: Gladius
|
Name: Gladius
|
||||||
|
Type: Gladius
|
||||||
MinimumExcessPower: 60
|
MinimumExcessPower: 60
|
||||||
BuildingQueues: Building, Upgrade
|
BuildingQueues: Building, Upgrade
|
||||||
UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft
|
UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ Player:
|
|||||||
-HackyAI@TurtleAI:
|
-HackyAI@TurtleAI:
|
||||||
DummyAI@LonestarAI:
|
DummyAI@LonestarAI:
|
||||||
Name: Lonestar AI
|
Name: Lonestar AI
|
||||||
|
Type: Lonestar AI
|
||||||
|
|
||||||
^Infantry:
|
^Infantry:
|
||||||
Inherits@IC: ^IronCurtainable
|
Inherits@IC: ^IronCurtainable
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
Player:
|
Player:
|
||||||
HackyAI@RushAI:
|
HackyAI@RushAI:
|
||||||
Name: Rush AI
|
Name: Rush AI
|
||||||
|
Type: Rush AI
|
||||||
MinimumExcessPower: 40
|
MinimumExcessPower: 40
|
||||||
BuildingCommonNames:
|
BuildingCommonNames:
|
||||||
ConstructionYard: fact
|
ConstructionYard: fact
|
||||||
@@ -114,6 +115,7 @@ Player:
|
|||||||
CheckRadius: 7c0
|
CheckRadius: 7c0
|
||||||
HackyAI@NormalAI:
|
HackyAI@NormalAI:
|
||||||
Name: Normal AI
|
Name: Normal AI
|
||||||
|
Type: Normal AI
|
||||||
MinimumExcessPower: 60
|
MinimumExcessPower: 60
|
||||||
BuildingCommonNames:
|
BuildingCommonNames:
|
||||||
ConstructionYard: fact
|
ConstructionYard: fact
|
||||||
@@ -245,6 +247,7 @@ Player:
|
|||||||
CheckRadius: 7c0
|
CheckRadius: 7c0
|
||||||
HackyAI@TurtleAI:
|
HackyAI@TurtleAI:
|
||||||
Name: Turtle AI
|
Name: Turtle AI
|
||||||
|
Type: Turtle AI
|
||||||
MinimumExcessPower: 100
|
MinimumExcessPower: 100
|
||||||
BuildingCommonNames:
|
BuildingCommonNames:
|
||||||
ConstructionYard: fact
|
ConstructionYard: fact
|
||||||
@@ -376,6 +379,7 @@ Player:
|
|||||||
CheckRadius: 7c0
|
CheckRadius: 7c0
|
||||||
HackyAI@NavalAI:
|
HackyAI@NavalAI:
|
||||||
Name: Naval AI
|
Name: Naval AI
|
||||||
|
Type: Naval AI
|
||||||
BuildingCommonNames:
|
BuildingCommonNames:
|
||||||
ConstructionYard: fact
|
ConstructionYard: fact
|
||||||
Refinery: proc
|
Refinery: proc
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
Player:
|
Player:
|
||||||
HackyAI@TestAI:
|
HackyAI@TestAI:
|
||||||
Name: Test AI
|
Name: Test AI
|
||||||
|
Type: Test AI
|
||||||
MinimumExcessPower: 60
|
MinimumExcessPower: 60
|
||||||
BuildingCommonNames:
|
BuildingCommonNames:
|
||||||
ConstructionYard: gacnst
|
ConstructionYard: gacnst
|
||||||
|
|||||||
Reference in New Issue
Block a user