Re-enables build restrictions for AIs since they have basic compliance now.
Moves target ownership checks from Commands.js to UnitAI. Adds more robust target checking in UnitAI by calling CanFoo functions more frequently. Adds optional debugging mode to Commands.js (useful for AI developers). This was SVN commit r10570.
This commit is contained in:
parent
e9041a392b
commit
5cc856aedc
@ -691,31 +691,31 @@ var UnitFsmSpec = {
|
||||
},
|
||||
|
||||
"Timer": function(msg) {
|
||||
// Check the target is still alive
|
||||
if (this.TargetIsAlive(this.order.data.target))
|
||||
var target = this.order.data.target;
|
||||
// Check the target is still alive and attackable
|
||||
if (this.TargetIsAlive(target) && this.CanAttack(target))
|
||||
{
|
||||
// Check we can still reach the target
|
||||
if (this.CheckTargetRange(this.order.data.target, IID_Attack, this.attackType))
|
||||
if (this.CheckTargetRange(target, IID_Attack, this.attackType))
|
||||
{
|
||||
this.FaceTowardsTarget(this.order.data.target);
|
||||
this.FaceTowardsTarget(target);
|
||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
cmpAttack.PerformAttack(this.attackType, this.order.data.target);
|
||||
cmpAttack.PerformAttack(this.attackType, target);
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't reach it - try to chase after it
|
||||
if (this.ShouldChaseTargetedEntity(this.order.data.target, this.order.data.force))
|
||||
if (this.ShouldChaseTargetedEntity(target, this.order.data.force))
|
||||
{
|
||||
if (this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType))
|
||||
if (this.MoveToTargetRange(target, IID_Attack, this.attackType))
|
||||
{
|
||||
this.SetNextState("COMBAT.CHASING");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Can't reach it, or it doesn't exist any more - give up
|
||||
// Can't reach it, no longer owned by enemy, or it doesn't exist any more - give up
|
||||
if (this.FinishOrder())
|
||||
return;
|
||||
|
||||
@ -837,15 +837,16 @@ var UnitFsmSpec = {
|
||||
},
|
||||
|
||||
"Timer": function(msg) {
|
||||
// Check we can still reach the target
|
||||
if (this.CheckTargetRange(this.order.data.target, IID_ResourceGatherer))
|
||||
var target = this.order.data.target;
|
||||
// Check we can still reach and gather from the target
|
||||
if (this.CheckTargetRange(target, IID_ResourceGatherer) && this.CanGather(target))
|
||||
{
|
||||
// Gather the resources:
|
||||
|
||||
var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);
|
||||
|
||||
// Try to gather treasure
|
||||
if (cmpResourceGatherer.TryInstantGather(this.order.data.target))
|
||||
if (cmpResourceGatherer.TryInstantGather(target))
|
||||
return;
|
||||
|
||||
// If we've already got some resources but they're the wrong type,
|
||||
@ -854,7 +855,7 @@ var UnitFsmSpec = {
|
||||
cmpResourceGatherer.DropResources();
|
||||
|
||||
// Collect from the target
|
||||
var status = cmpResourceGatherer.PerformGather(this.order.data.target);
|
||||
var status = cmpResourceGatherer.PerformGather(target);
|
||||
|
||||
// TODO: if exhausted, we should probably stop immediately
|
||||
// and choose a new target
|
||||
@ -879,7 +880,7 @@ var UnitFsmSpec = {
|
||||
else
|
||||
{
|
||||
// Try to follow the target
|
||||
if (this.MoveToTargetRange(this.order.data.target, IID_ResourceGatherer))
|
||||
if (this.MoveToTargetRange(target, IID_ResourceGatherer))
|
||||
{
|
||||
this.SetNextState("APPROACHING");
|
||||
return;
|
||||
@ -1030,10 +1031,10 @@ var UnitFsmSpec = {
|
||||
|
||||
"Timer": function(msg) {
|
||||
var target = this.order.data.target;
|
||||
// Check we can still reach the target
|
||||
if (!this.CheckTargetRange(target, IID_Builder))
|
||||
// Check we can still reach and repair the target
|
||||
if (!this.CheckTargetRange(target, IID_Builder) || !this.CanRepair(target))
|
||||
{
|
||||
// Can't reach it, or it doesn't exist any more
|
||||
// Can't reach it, no longer owned by ally, or it doesn't exist any more
|
||||
this.FinishOrder();
|
||||
return;
|
||||
}
|
||||
@ -1071,10 +1072,10 @@ var UnitFsmSpec = {
|
||||
}
|
||||
|
||||
// If this building was e.g. a farmstead, we should look for nearby
|
||||
// resources we can gather
|
||||
var cmpResourceDropsite = Engine.QueryInterface(msg.data.newentity, IID_ResourceDropsite);
|
||||
if (cmpResourceDropsite)
|
||||
// resources we can gather, if we are capable of doing so
|
||||
if (this.CanReturnResource(msg.data.newentity))
|
||||
{
|
||||
var cmpResourceDropsite = Engine.QueryInterface(msg.data.newentity, IID_ResourceDropsite);
|
||||
var types = cmpResourceDropsite.GetTypes();
|
||||
var nearby = this.FindNearbyResource(function (ent, type) {
|
||||
return (types.indexOf(type.generic) != -1);
|
||||
@ -1138,13 +1139,16 @@ var UnitFsmSpec = {
|
||||
|
||||
"GARRISONED": {
|
||||
"enter": function() {
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(this.order.data.target, IID_GarrisonHolder);
|
||||
if (cmpGarrisonHolder && cmpGarrisonHolder.Garrison(this.entity))
|
||||
var target = this.order.data.target;
|
||||
// Check that we can still garrison here and that garrisoning succeeds
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
|
||||
if (this.CanGarrison(target) && cmpGarrisonHolder.Garrison(this.entity))
|
||||
{
|
||||
this.isGarrisoned = true;
|
||||
}
|
||||
else
|
||||
{ // Garrisoning failed for some reason, so finish the order
|
||||
{
|
||||
// Garrisoning failed for some reason, so finish the order
|
||||
if (this.FinishOrder())
|
||||
return;
|
||||
}
|
||||
@ -1205,7 +1209,8 @@ var UnitFsmSpec = {
|
||||
this.Attack(msg.data.attacker, false);
|
||||
}
|
||||
else if (this.template.NaturalBehaviour == "domestic")
|
||||
{ // Never flee, stop what we were doing
|
||||
{
|
||||
// Never flee, stop what we were doing
|
||||
this.SetNextState("IDLE");
|
||||
}
|
||||
},
|
||||
@ -2436,17 +2441,30 @@ UnitAI.prototype.CanAttack = function(target)
|
||||
if (!cmpAttack)
|
||||
return false;
|
||||
|
||||
// TODO: verify that this is a valid target
|
||||
// Verify that the target is owned by an enemy of this entity's player
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
if (!cmpOwnership || !IsOwnedByEnemyOfPlayer(cmpOwnership.GetOwner(), target))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
UnitAI.prototype.CanGarrison = function(target)
|
||||
{
|
||||
// Formation controllers should always respond to commands
|
||||
// (then the individual units can make up their own minds)
|
||||
if (this.IsFormationController())
|
||||
return true;
|
||||
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
|
||||
if (!cmpGarrisonHolder)
|
||||
return false;
|
||||
|
||||
// Verify that the target is owned by this entity's player
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
if (!cmpOwnership || !IsOwnedByPlayer(cmpOwnership.GetOwner(), target))
|
||||
return false;
|
||||
|
||||
// Don't let animals garrison for now
|
||||
// (If we want to support that, we'll need to change Order.Garrison so it
|
||||
// doesn't move the animal into an INVIDIDUAL.* state)
|
||||
@ -2472,7 +2490,10 @@ UnitAI.prototype.CanGather = function(target)
|
||||
if (!cmpResourceGatherer.GetTargetGatherRate(target))
|
||||
return false;
|
||||
|
||||
// TODO: should verify it's owned by the correct player, etc
|
||||
// Verify that the target is owned by gaia or this entity's player
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
if (!cmpOwnership || (!IsOwnedByGaia(target) && !IsOwnedByPlayer(cmpOwnership.GetOwner(), target)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -2500,7 +2521,10 @@ UnitAI.prototype.CanReturnResource = function(target)
|
||||
if (!type || !cmpResourceDropsite.AcceptsType(type))
|
||||
return false;
|
||||
|
||||
// TODO: should verify it's owned by the correct player, etc
|
||||
// Verify that the dropsite is owned by this entity's player
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
if (!cmpOwnership || !IsOwnedByPlayer(cmpOwnership.GetOwner(), target))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -2517,7 +2541,10 @@ UnitAI.prototype.CanRepair = function(target)
|
||||
if (!cmpBuilder)
|
||||
return false;
|
||||
|
||||
// TODO: verify that this is a valid target
|
||||
// Verify that the target is owned by an ally of this entity's player
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
if (!cmpOwnership || !IsOwnedByAllyOfPlayer(cmpOwnership.GetOwner(), target))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Setting this to true will display some warnings when commands
|
||||
// are likely to fail, which may be useful for debugging AIs
|
||||
var g_DebugCommands = false;
|
||||
|
||||
function ProcessCommand(player, cmd)
|
||||
{
|
||||
// Do some basic checks here that commanding player is valid
|
||||
@ -12,6 +16,12 @@ function ProcessCommand(player, cmd)
|
||||
return;
|
||||
var controlAllUnits = cmpPlayer.CanControlAllUnits();
|
||||
|
||||
// Note: checks of UnitAI targets are not robust enough here, as ownership
|
||||
// can change after the order is issued, they should be checked by UnitAI
|
||||
// when the specific behavior (e.g. attack, garrison) is performed.
|
||||
// (Also it's not ideal if a command silently fails, it's nicer if UnitAI
|
||||
// moves the entities closer to the target before giving up.)
|
||||
|
||||
// Now handle various commands
|
||||
switch (cmd.type)
|
||||
{
|
||||
@ -27,7 +37,7 @@ function ProcessCommand(player, cmd)
|
||||
case "control-all":
|
||||
cmpPlayer.SetControlAllUnits(cmd.flag);
|
||||
break;
|
||||
|
||||
|
||||
case "reveal-map":
|
||||
// Reveal the map for all players, not just the current player,
|
||||
// primarily to make it obvious to everyone that the player is cheating
|
||||
@ -43,66 +53,89 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
case "attack":
|
||||
// Check if target is owned by player's enemy
|
||||
if (IsOwnedByEnemyOfPlayer(player, cmd.target))
|
||||
if (g_DebugCommands && !IsOwnedByEnemyOfPlayer(player, cmd.target))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
|
||||
cmpUnitAI.Attack(cmd.target, cmd.queued);
|
||||
});
|
||||
// This check is for debugging only!
|
||||
warn("Invalid command: attack target is not owned by enemy of player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
// See UnitAI.CanAttack for target checks
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
|
||||
cmpUnitAI.Attack(cmd.target, cmd.queued);
|
||||
});
|
||||
break;
|
||||
|
||||
case "repair":
|
||||
// This covers both repairing damaged buildings, and constructing unfinished foundations
|
||||
// Check if target building is owned by player or an ally
|
||||
if (IsOwnedByAllyOfPlayer(player, cmd.target))
|
||||
if (g_DebugCommands && !IsOwnedByAllyOfPlayer(player, cmd.target))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
|
||||
cmpUnitAI.Repair(cmd.target, cmd.autocontinue, cmd.queued);
|
||||
});
|
||||
// This check is for debugging only!
|
||||
warn("Invalid command: repair target is not owned by ally of player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
// See UnitAI.CanRepair for target checks
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
|
||||
cmpUnitAI.Repair(cmd.target, cmd.autocontinue, cmd.queued);
|
||||
});
|
||||
break;
|
||||
|
||||
case "gather":
|
||||
// Check if target resource is owned by gaia or player
|
||||
if (IsOwnedByGaia(cmd.target) || IsOwnedByPlayer(player, cmd.target))
|
||||
if (g_DebugCommands && !(IsOwnedByPlayer(player, cmd.target) || IsOwnedByGaia(cmd.target)))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
|
||||
cmpUnitAI.Gather(cmd.target, cmd.queued);
|
||||
});
|
||||
// This check is for debugging only!
|
||||
warn("Invalid command: resource is not owned by gaia or player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
// See UnitAI.CanGather for target checks
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
|
||||
cmpUnitAI.Gather(cmd.target, cmd.queued);
|
||||
});
|
||||
break;
|
||||
|
||||
case "returnresource":
|
||||
// Check dropsite is owned by player
|
||||
if (IsOwnedByPlayer(player, cmd.target))
|
||||
if (g_DebugCommands && IsOwnedByPlayer(player, cmd.target))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
|
||||
cmpUnitAI.ReturnResource(cmd.target, cmd.queued);
|
||||
});
|
||||
// This check is for debugging only!
|
||||
warn("Invalid command: dropsite is not owned by player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
// See UnitAI.CanReturnResource for target checks
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
|
||||
cmpUnitAI.ReturnResource(cmd.target, cmd.queued);
|
||||
});
|
||||
break;
|
||||
|
||||
case "train":
|
||||
// Verify that the building can be controlled by the player
|
||||
if (CanControlUnit(cmd.entity, player, controlAllUnits))
|
||||
{
|
||||
var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
|
||||
if (queue)
|
||||
queue.AddBatch(cmd.template, +cmd.count, cmd.metadata);
|
||||
}
|
||||
else if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: training building cannot be controlled by player "+player+": "+uneval(cmd));
|
||||
}
|
||||
break;
|
||||
|
||||
case "stop-train":
|
||||
// Verify that the building can be controlled by the player
|
||||
if (CanControlUnit(cmd.entity, player, controlAllUnits))
|
||||
{
|
||||
var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
|
||||
if (queue)
|
||||
queue.RemoveBatch(cmd.id);
|
||||
}
|
||||
else if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: training building cannot be controlled by player "+player+": "+uneval(cmd));
|
||||
}
|
||||
break;
|
||||
|
||||
case "construct":
|
||||
@ -138,7 +171,7 @@ function ProcessCommand(player, cmd)
|
||||
if (ent == INVALID_ENTITY)
|
||||
{
|
||||
// Error (e.g. invalid template names)
|
||||
error("Error creating foundation for '" + cmd.template + "'");
|
||||
error("Error creating foundation entity for '" + cmd.template + "'");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -147,52 +180,72 @@ function ProcessCommand(player, cmd)
|
||||
cmpPosition.JumpTo(cmd.x, cmd.z);
|
||||
cmpPosition.SetYRotation(cmd.angle);
|
||||
|
||||
// TODO: Build restrictions disabled for AI since it lacks a mechanism for checking most of them
|
||||
// Check whether it's obstructed by other entities or invalid terrain
|
||||
var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions);
|
||||
if (!cmpBuildRestrictions || !cmpBuildRestrictions.CheckPlacement(player))
|
||||
{
|
||||
if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: build restrictions check failed for player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
cmpGuiInterface.PushNotification({ "player": player, "message": "Building site was obstructed" });
|
||||
|
||||
// Remove the foundation because the construction was aborted
|
||||
Engine.DestroyEntity(ent);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check build limits
|
||||
var cmpBuildLimits = QueryPlayerIDInterface(player, IID_BuildLimits);
|
||||
if (!cmpBuildLimits || !cmpBuildLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory()))
|
||||
{
|
||||
if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: build limits check failed for player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
// TODO: The UI should tell the user they can't build this (but we still need this check)
|
||||
|
||||
// Remove the foundation because the construction was aborted
|
||||
Engine.DestroyEntity(ent);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: AI has no visibility info
|
||||
if (!cmpPlayer.IsAI())
|
||||
{
|
||||
// Check whether it's obstructed by other entities or invalid terrain
|
||||
var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions);
|
||||
if (!cmpBuildRestrictions || !cmpBuildRestrictions.CheckPlacement(player))
|
||||
{
|
||||
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
cmpGuiInterface.PushNotification({ "player": player, "message": "Building site was obstructed" });
|
||||
|
||||
// Remove the foundation because the construction was aborted
|
||||
Engine.DestroyEntity(ent);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check build limits
|
||||
var cmpBuildLimits = QueryPlayerIDInterface(player, IID_BuildLimits);
|
||||
if (!cmpBuildLimits || !cmpBuildLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory()))
|
||||
{
|
||||
// TODO: The UI should tell the user they can't build this (but we still need this check)
|
||||
|
||||
// Remove the foundation because the construction was aborted
|
||||
Engine.DestroyEntity(ent);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check whether it's in a visible region
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
var visible = (cmpRangeManager.GetLosVisibility(ent, player) == "visible");
|
||||
if (!visible)
|
||||
{
|
||||
// TODO: report error to player (the building site was not visible)
|
||||
print("Building site was not visible\n");
|
||||
if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: foundation visibility check failed for player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
cmpGuiInterface.PushNotification({ "player": player, "message": "Building site was not visible" });
|
||||
|
||||
Engine.DestroyEntity(ent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var cmpCost = Engine.QueryInterface(ent, IID_Cost);
|
||||
if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))
|
||||
{
|
||||
if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: building cost check failed for player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
Engine.DestroyEntity(ent);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Make it owned by the current player
|
||||
var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
cmpOwnership.SetOwner(player);
|
||||
@ -214,7 +267,7 @@ function ProcessCommand(player, cmd)
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case "delete-entities":
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
for each (var ent in entities)
|
||||
@ -246,13 +299,14 @@ function ProcessCommand(player, cmd)
|
||||
cmpRallyPoint.Unset();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case "defeat-player":
|
||||
// Send "OnPlayerDefeated" message to player
|
||||
Engine.PostMessage(playerEnt, MT_PlayerDefeated, null);
|
||||
Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": player } );
|
||||
break;
|
||||
|
||||
case "garrison":
|
||||
// Verify that the building can be controlled by the player
|
||||
if (CanControlUnit(cmd.target, player, controlAllUnits))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
@ -260,9 +314,14 @@ function ProcessCommand(player, cmd)
|
||||
cmpUnitAI.Garrison(cmd.target);
|
||||
});
|
||||
}
|
||||
else if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: garrison target cannot be controlled by player "+player+": "+uneval(cmd));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case "unload":
|
||||
// Verify that the building can be controlled by the player
|
||||
if (CanControlUnit(cmd.garrisonHolder, player, controlAllUnits))
|
||||
{
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(cmd.garrisonHolder, IID_GarrisonHolder);
|
||||
@ -274,9 +333,14 @@ function ProcessCommand(player, cmd)
|
||||
cmpGUIInterface.PushNotification(notification);
|
||||
}
|
||||
}
|
||||
else if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: unload target cannot be controlled by player "+player+": "+uneval(cmd));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case "unload-all":
|
||||
// Verify that the building can be controlled by the player
|
||||
if (CanControlUnit(cmd.garrisonHolder, player, controlAllUnits))
|
||||
{
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(cmd.garrisonHolder, IID_GarrisonHolder);
|
||||
@ -288,6 +352,10 @@ function ProcessCommand(player, cmd)
|
||||
cmpGUIInterface.PushNotification(notification);
|
||||
}
|
||||
}
|
||||
else if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: unload-all target cannot be controlled by player "+player+": "+uneval(cmd));
|
||||
}
|
||||
break;
|
||||
|
||||
case "formation":
|
||||
@ -302,6 +370,7 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
case "promote":
|
||||
// No need to do checks here since this is a cheat anyway
|
||||
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
cmpGuiInterface.PushNotification({"type": "chat", "player": player, "message": "(Cheat - promoted units)"});
|
||||
|
||||
@ -324,7 +393,7 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Ignoring unrecognised command type '" + cmd.type + "'");
|
||||
error("Invalid command: unknown command type: "+uneval(cmd));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user