forked from 0ad/0ad
Adds ownership checks to UI selections.
Adds ownership and diplomacy checks to Commands.js (fixes #880). Adds control all units setting to Player component (network synced). Adds helpers for diplomacy checks - use these instead of directly accessing diplomacy array. Fixes tests according to these changes. This was SVN commit r9726.
This commit is contained in:
parent
24f981cb2c
commit
4d188452f8
@ -118,8 +118,13 @@ function getActionInfo(action, target)
|
||||
return {"possible": false};
|
||||
|
||||
// If the selection isn't friendly units, no action
|
||||
var player = Engine.GetPlayerID();
|
||||
if (entState.player != player && !g_DevSettings.controlAll)
|
||||
var playerID = Engine.GetPlayerID();
|
||||
var allOwnedByPlayer = selection.every(function(ent) {
|
||||
var entState = GetEntityState(ent);
|
||||
return entState && entState.player == playerID;
|
||||
});
|
||||
|
||||
if (!g_DevSettings.controlAll && !allOwnedByPlayer)
|
||||
return {"possible": false};
|
||||
|
||||
// Work out whether the selection can have rally points
|
||||
@ -128,7 +133,6 @@ function getActionInfo(action, target)
|
||||
return entState && entState.rallyPoint;
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (!target)
|
||||
{
|
||||
@ -163,12 +167,12 @@ function getActionInfo(action, target)
|
||||
var entState = GetEntityState(entityID);
|
||||
if (!entState)
|
||||
continue;
|
||||
// Get entity owner diplomacy array
|
||||
var diplomacy = simState.players[entState.player].diplomacy;
|
||||
|
||||
var playerOwned = ((targetState.player == entState.player)? true : false);
|
||||
var enemyOwned = ((targetState.player != entState.player && targetState.player && diplomacy[targetState.player - 1] < 0)? true : false);
|
||||
var gaiaOwned = ((targetState.player == 0)? true : false);
|
||||
|
||||
var playerState = simState.players[entState.player];
|
||||
var playerOwned = (targetState.player == entState.player);
|
||||
var allyOwned = playerState.isAlly[targetState.player];
|
||||
var enemyOwned = playerState.isEnemy[targetState.player];
|
||||
var gaiaOwned = (targetState.player == 0);
|
||||
|
||||
// Find the resource type we're carrying, if any
|
||||
var carriedType = undefined;
|
||||
@ -206,11 +210,11 @@ function getActionInfo(action, target)
|
||||
return {"possible": true};
|
||||
break;
|
||||
case "repair":
|
||||
if (entState.buildEntities && targetState.needsRepair && playerOwned)
|
||||
if (entState.buildEntities && targetState.needsRepair && allyOwned)
|
||||
return {"possible": true};
|
||||
break;
|
||||
case "attack":
|
||||
if (entState.attack && targetState.hitpoints && (enemyOwned || gaiaOwned))
|
||||
if (entState.attack && targetState.hitpoints && enemyOwned)
|
||||
return {"possible": true};
|
||||
}
|
||||
}
|
||||
@ -240,8 +244,13 @@ function determineAction(x, y, fromMinimap)
|
||||
return undefined;
|
||||
|
||||
// If the selection isn't friendly units, no action
|
||||
var player = Engine.GetPlayerID();
|
||||
if (entState.player != player && !g_DevSettings.controlAll)
|
||||
var playerID = Engine.GetPlayerID();
|
||||
var allOwnedByPlayer = selection.every(function(ent) {
|
||||
var entState = GetEntityState(ent);
|
||||
return entState && entState.player == playerID;
|
||||
});
|
||||
|
||||
if (!g_DevSettings.controlAll && !allOwnedByPlayer)
|
||||
return undefined;
|
||||
|
||||
// Work out whether the selection can have rally points
|
||||
@ -421,6 +430,7 @@ function handleInputBeforeGui(ev, hoveredObject)
|
||||
bandbox.size = [x0, y0, x1, y1].join(" ");
|
||||
bandbox.hidden = false;
|
||||
|
||||
// TODO: Should we handle "control all units" here as well?
|
||||
var ents = Engine.PickFriendlyEntitiesInRect(x0, y0, x1, y1, Engine.GetPlayerID());
|
||||
g_Selection.setHighlightList(ents);
|
||||
|
||||
@ -440,6 +450,7 @@ function handleInputBeforeGui(ev, hoveredObject)
|
||||
bandbox.hidden = true;
|
||||
|
||||
// Get list of entities limited to preferred entities
|
||||
// TODO: Should we handle "control all units" here as well?
|
||||
var ents = Engine.PickFriendlyEntitiesInRect(x0, y0, x1, y1, Engine.GetPlayerID());
|
||||
var preferredEntities = getPreferredEntities(ents)
|
||||
|
||||
@ -487,7 +498,7 @@ function handleInputBeforeGui(ev, hoveredObject)
|
||||
{
|
||||
case "mousemotion":
|
||||
// If the mouse moved far enough from the original click location,
|
||||
// then switch to drag-orientatio mode
|
||||
// then switch to drag-orientation mode
|
||||
var dragDeltaX = ev.x - dragStart[0];
|
||||
var dragDeltaY = ev.y - dragStart[1];
|
||||
var maxDragDelta = 16;
|
||||
@ -761,6 +772,7 @@ function handleInputAfterGui(ev)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should we handle "control all units" here as well?
|
||||
ents = Engine.PickSimilarFriendlyEntities(templateToMatch, showOffscreen, matchRank);
|
||||
}
|
||||
else
|
||||
@ -1059,8 +1071,8 @@ function performCommand(entity, commandName)
|
||||
var template = GetTemplateData(entState.template);
|
||||
var unitName = getEntityName(template);
|
||||
|
||||
var player = Engine.GetPlayerID();
|
||||
if (entState.player == player || g_DevSettings.controlAll)
|
||||
var playerID = Engine.GetPlayerID();
|
||||
if (entState.player == playerID || g_DevSettings.controlAll)
|
||||
{
|
||||
switch (commandName)
|
||||
{
|
||||
|
@ -261,10 +261,14 @@ EntitySelection.prototype.addList = function(ents)
|
||||
var selectionSize = this.toList().length;
|
||||
var i = 1;
|
||||
var added = [];
|
||||
var playerID = Engine.GetPlayerID();
|
||||
var allowEnemySelections = g_DevSettings.controlAll || (ents.length == 1 && selectionSize == 0);
|
||||
|
||||
for each (var ent in ents)
|
||||
{
|
||||
if (!this.selected[ent] && (selectionSize + i) <= MAX_SELECTION_SIZE)
|
||||
// Only add entities we own to our selection
|
||||
var entState = GetEntityState(ent);
|
||||
if (!this.selected[ent] && (selectionSize + i) <= MAX_SELECTION_SIZE && (allowEnemySelections || (entState && entState.player == playerID)))
|
||||
{
|
||||
added.push(ent);
|
||||
this.selected[ent] = ent;
|
||||
|
@ -160,10 +160,6 @@ function onTick()
|
||||
handleNetMessage(message);
|
||||
}
|
||||
|
||||
g_DevSettings.controlAll = getGUIObjectByName("devControlAll").checked;
|
||||
// TODO: at some point this controlAll needs to disable the simulation code's
|
||||
// player checks (once it has some player checks)
|
||||
|
||||
updateCursor();
|
||||
|
||||
// If the selection changed, we need to regenerate the sim display
|
||||
|
@ -105,7 +105,12 @@
|
||||
</action>
|
||||
|
||||
<object size="0 0 100%-18 16" type="text" style="devCommandsText">Control all units</object>
|
||||
<object size="100%-16 0 100% 16" type="checkbox" name="devControlAll" style="wheatCrossBox"/>
|
||||
<object size="100%-16 0 100% 16" type="checkbox" name="devControlAll" style="wheatCrossBox">
|
||||
<action on="Press">
|
||||
g_DevSettings.controlAll = this.checked;
|
||||
Engine.PostNetworkCommand( {"type": "control-all", "flag": this.checked} );
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<object size="0 16 100%-18 32" type="text" style="devCommandsText">Display selection state</object>
|
||||
<object size="100%-16 16 100% 32" type="checkbox" name="devDisplayState" style="wheatCrossBox"/>
|
||||
|
@ -94,7 +94,6 @@ function getPlayerData(playerAssignments)
|
||||
"civ": civ,
|
||||
"color": color,
|
||||
"team": playerState.team,
|
||||
"diplomacy": playerState.diplomacy,
|
||||
"state": playerState.state,
|
||||
"guid": undefined, // network guid for players controlled by hosts
|
||||
"disconnected": false, // flag for host-controlled players who have left the game
|
||||
|
@ -63,16 +63,13 @@ BuildingAI.prototype.SetupRangeQuery = function(owner)
|
||||
cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
|
||||
var players = [];
|
||||
|
||||
var player = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(owner), IID_Player);
|
||||
|
||||
// Get our diplomacy array
|
||||
var diplomacy = player.GetDiplomacy();
|
||||
var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(owner), IID_Player);
|
||||
var numPlayers = cmpPlayerManager.GetNumPlayers();
|
||||
|
||||
for (var i = 1; i < numPlayers; ++i)
|
||||
{ // Exclude gaia, allies, and self
|
||||
// TODO: How to handle neutral players - Special query to attack military only?
|
||||
if ((i != owner) && (diplomacy[i - 1] < 0))
|
||||
if (cmpPlayer.IsEnemy(i))
|
||||
players.push(i);
|
||||
}
|
||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
|
@ -71,56 +71,48 @@ EndGameManager.prototype.UpdatePlayerStates = function()
|
||||
|
||||
// Ignore gaia
|
||||
var numPlayers = cmpPlayerManager.GetNumPlayers() - 1;
|
||||
var diplomacy = new Array(numPlayers);
|
||||
var cmpPlayers = new Array(numPlayers);
|
||||
|
||||
// If a player is currently active but has no suitable units left,
|
||||
// mark that player as defeated (else get diplomacy for victory check)
|
||||
// mark that player as defeated
|
||||
for (var i = 0; i < numPlayers; i++)
|
||||
{
|
||||
var playerEntityId = cmpPlayerManager.GetPlayerByID(i+1);
|
||||
var cmpPlayer = Engine.QueryInterface(playerEntityId, IID_Player);
|
||||
if (cmpPlayer.GetState() == "active")
|
||||
cmpPlayers[i] = Engine.QueryInterface(playerEntityId, IID_Player);
|
||||
if (cmpPlayers[i].GetState() == "active")
|
||||
{
|
||||
if (cmpPlayer.GetConquestCriticalEntitiesCount() == 0)
|
||||
{
|
||||
if (cmpPlayers[i].GetConquestCriticalEntitiesCount() == 0)
|
||||
{ // Defeated
|
||||
Engine.PostMessage(playerEntityId, MT_PlayerDefeated, null);
|
||||
}
|
||||
else
|
||||
{ // Get active diplomacy array
|
||||
diplomacy[i] = cmpPlayer.GetDiplomacy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check diplomacy to see if all active players are allied - if so, they all won
|
||||
var onlyAlliesLeft = true;
|
||||
var allyIDs = [];
|
||||
|
||||
var allies = [];
|
||||
for (var i = 0; i < numPlayers && onlyAlliesLeft; i++)
|
||||
{
|
||||
if (diplomacy[i])
|
||||
if (cmpPlayers[i].GetState() == "active")
|
||||
{ //Active player
|
||||
for (var j = 0; j < numPlayers && j != i && onlyAlliesLeft; j++)
|
||||
for (var j = 0; j < numPlayers && onlyAlliesLeft; j++)
|
||||
{
|
||||
if (diplomacy[j] && (diplomacy[i][j] <= 0 || diplomacy[j][i] <= 0))
|
||||
if (cmpPlayers[j].GetState() == "active" && (cmpPlayers[i].IsEnemy(j+1) || cmpPlayers[j].IsEnemy(i+1)))
|
||||
{ // Only need to find an active non-allied player
|
||||
onlyAlliesLeft = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (onlyAlliesLeft)
|
||||
allyIDs.push(i+1);
|
||||
allies.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// If only allies left and allied victory set (or only one player left)
|
||||
if (onlyAlliesLeft && (this.alliedVictory || allyIDs.length == 1))
|
||||
if (onlyAlliesLeft && (this.alliedVictory || allies.length == 1))
|
||||
{
|
||||
for (var p in allyIDs)
|
||||
for each (var p in allies)
|
||||
{
|
||||
var playerEntityId = cmpPlayerManager.GetPlayerByID(allyIDs[p]);
|
||||
var cmpPlayer = Engine.QueryInterface(playerEntityId, IID_Player);
|
||||
cmpPlayer.SetState("won");
|
||||
cmpPlayers[p].SetState("won");
|
||||
}
|
||||
|
||||
// Reveal the map to all players
|
||||
|
@ -45,6 +45,15 @@ GuiInterface.prototype.GetSimulationState = function(player)
|
||||
var playerEnt = cmpPlayerMan.GetPlayerByID(i);
|
||||
var cmpPlayer = Engine.QueryInterface(playerEnt, IID_Player);
|
||||
var cmpPlayerStatisticsTracker = Engine.QueryInterface(playerEnt, IID_StatisticsTracker);
|
||||
|
||||
// store player ally/enemy data as arrays
|
||||
var allies = [];
|
||||
var enemies = [];
|
||||
for (var j = 0; j <= n; ++j)
|
||||
{
|
||||
allies[j] = cmpPlayer.IsAlly(j);
|
||||
enemies[j] = cmpPlayer.IsEnemy(j);
|
||||
}
|
||||
var playerData = {
|
||||
"name": cmpPlayer.GetName(),
|
||||
"civ": cmpPlayer.GetCiv(),
|
||||
@ -55,8 +64,9 @@ GuiInterface.prototype.GetSimulationState = function(player)
|
||||
"trainingQueueBlocked": cmpPlayer.IsTrainingQueueBlocked(),
|
||||
"state": cmpPlayer.GetState(),
|
||||
"team": cmpPlayer.GetTeam(),
|
||||
"diplomacy": cmpPlayer.GetDiplomacy(),
|
||||
"phase": cmpPlayer.GetPhase()
|
||||
"phase": cmpPlayer.GetPhase(),
|
||||
"isAlly": allies,
|
||||
"isEnemy": enemies
|
||||
};
|
||||
ret.players.push(playerData);
|
||||
}
|
||||
@ -340,7 +350,7 @@ GuiInterface.prototype.SetSelectionHighlight = function(player, cmd)
|
||||
var colour = playerColours[owner];
|
||||
if (!colour)
|
||||
{
|
||||
colour = [1, 1, 1];
|
||||
colour = {"r":1, "g":1, "b":1};
|
||||
var cmpPlayer = Engine.QueryInterface(cmpPlayerMan.GetPlayerByID(owner), IID_Player);
|
||||
if (cmpPlayer)
|
||||
colour = cmpPlayer.GetColour();
|
||||
|
@ -26,6 +26,7 @@ Player.prototype.Init = function()
|
||||
this.conquestCriticalEntitiesCount = 0; // number of owned units with ConquestCritical class
|
||||
this.phase = "village";
|
||||
this.startCam = undefined;
|
||||
this.controlAllUnits = false;
|
||||
};
|
||||
|
||||
Player.prototype.SetPlayerID = function(id)
|
||||
@ -251,6 +252,40 @@ Player.prototype.HasStartingCamera = function()
|
||||
return (this.startCam !== undefined);
|
||||
}
|
||||
|
||||
Player.prototype.SetControlAllUnits = function(c)
|
||||
{
|
||||
this.controlAllUnits = c;
|
||||
}
|
||||
|
||||
Player.prototype.CanControlAllUnits = function()
|
||||
{
|
||||
return this.controlAllUnits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given player is our ally
|
||||
*/
|
||||
Player.prototype.IsAlly = function(id)
|
||||
{
|
||||
return (id >= 0 && (id == this.playerID || this.diplomacy[id] > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given player is our enemy
|
||||
*/
|
||||
Player.prototype.IsEnemy = function(id)
|
||||
{
|
||||
return (id >= 0 && id != this.playerID && this.diplomacy[id] < 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given player is neutral
|
||||
*/
|
||||
Player.prototype.IsNeutral = function(id)
|
||||
{
|
||||
return (id >= 0 && id != this.playerID && this.diplomacy[id] == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of population effects of all entities that
|
||||
* become owned or unowned by this player
|
||||
|
@ -460,7 +460,7 @@ var UnitFsmSpec = {
|
||||
// anything more important (and we might be stuck in the WALKING
|
||||
// state forever and need to get out of foundations in that case)
|
||||
"Order.LeaveFoundation": function(msg) {
|
||||
if (!IsOwnedByAlly(this.entity, msg.data.target))
|
||||
if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target))
|
||||
{
|
||||
this.FinishOrder();
|
||||
return;
|
||||
@ -569,7 +569,7 @@ var UnitFsmSpec = {
|
||||
// Override the LeaveFoundation order since we're not doing
|
||||
// anything more important
|
||||
"Order.LeaveFoundation": function(msg) {
|
||||
if (!IsOwnedByAlly(this.entity, msg.data.target))
|
||||
if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target))
|
||||
{
|
||||
this.FinishOrder();
|
||||
return;
|
||||
@ -1097,7 +1097,7 @@ var UnitFsmSpec = {
|
||||
// Override the LeaveFoundation order since we don't want to be
|
||||
// accidentally blocking our own building
|
||||
"Order.LeaveFoundation": function(msg) {
|
||||
if (!IsOwnedByAlly(this.entity, msg.data.target))
|
||||
if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target))
|
||||
{
|
||||
this.FinishOrder();
|
||||
return;
|
||||
@ -1423,17 +1423,13 @@ UnitAI.prototype.SetupRangeQuery = function()
|
||||
if (owner != -1)
|
||||
{
|
||||
// If unit not just killed, get enemy players via diplomacy
|
||||
var player = Engine.QueryInterface(playerMan.GetPlayerByID(owner), IID_Player);
|
||||
|
||||
// Get our diplomacy array
|
||||
var diplomacy = player.GetDiplomacy();
|
||||
var cmpPlayer = Engine.QueryInterface(playerMan.GetPlayerByID(owner), IID_Player);
|
||||
var numPlayers = playerMan.GetNumPlayers();
|
||||
|
||||
for (var i = 1; i < numPlayers; ++i)
|
||||
{
|
||||
// Exclude gaia, allies, and self
|
||||
// TODO: How to handle neutral players - Special query to attack military only?
|
||||
if (i != owner && diplomacy[i - 1] < 0)
|
||||
if (cmpPlayer.IsEnemy(i))
|
||||
players.push(i);
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +48,11 @@ AddMock(100, IID_Player, {
|
||||
IsTrainingQueueBlocked: function() { return false; },
|
||||
GetState: function() { return "active"; },
|
||||
GetTeam: function() { return -1; },
|
||||
GetDiplomacy: function() { return []; },
|
||||
GetDiplomacy: function() { return [-1, 1]; },
|
||||
GetPhase: function() { return ""; },
|
||||
GetConquestCriticalEntitiesCount: function() { return 1; },
|
||||
IsAlly: function() { return false; },
|
||||
IsEnemy: function() { return true; },
|
||||
});
|
||||
|
||||
AddMock(100, IID_StatisticsTracker, {
|
||||
@ -87,9 +89,11 @@ AddMock(101, IID_Player, {
|
||||
IsTrainingQueueBlocked: function() { return false; },
|
||||
GetState: function() { return "active"; },
|
||||
GetTeam: function() { return -1; },
|
||||
GetDiplomacy: function() { return [1]; },
|
||||
GetDiplomacy: function() { return [-1, 1]; },
|
||||
GetPhase: function() { return "village"; },
|
||||
GetConquestCriticalEntitiesCount: function() { return 1; },
|
||||
IsAlly: function() { return true; },
|
||||
IsEnemy: function() { return false; },
|
||||
});
|
||||
|
||||
AddMock(101, IID_StatisticsTracker, {
|
||||
@ -128,8 +132,9 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
||||
trainingQueueBlocked: false,
|
||||
state: "active",
|
||||
team: -1,
|
||||
diplomacy: [],
|
||||
phase: "",
|
||||
isAlly: [false, false, false],
|
||||
isEnemy: [true, true, true],
|
||||
},
|
||||
{
|
||||
name: "Player 2",
|
||||
@ -141,8 +146,9 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
||||
trainingQueueBlocked: false,
|
||||
state: "active",
|
||||
team: -1,
|
||||
diplomacy: [1],
|
||||
phase: "village",
|
||||
isAlly: [true, true, true],
|
||||
isEnemy: [false, false, false],
|
||||
}
|
||||
],
|
||||
circularMap: false,
|
||||
@ -161,8 +167,9 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
||||
trainingQueueBlocked: false,
|
||||
state: "active",
|
||||
team: -1,
|
||||
diplomacy: [],
|
||||
phase: "",
|
||||
isAlly: [false, false, false],
|
||||
isEnemy: [true, true, true],
|
||||
statistics: {
|
||||
unitsTrained: 10,
|
||||
unitsLost: 9,
|
||||
@ -190,8 +197,9 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
||||
trainingQueueBlocked: false,
|
||||
state: "active",
|
||||
team: -1,
|
||||
diplomacy: [1],
|
||||
phase: "village",
|
||||
isAlly: [true, true, true],
|
||||
isEnemy: [false, false, false],
|
||||
statistics: {
|
||||
unitsTrained: 10,
|
||||
unitsLost: 9,
|
||||
|
@ -45,7 +45,8 @@ function TestFormationExiting(mode)
|
||||
});
|
||||
|
||||
AddMock(playerEntity, IID_Player, {
|
||||
GetDiplomacy: function() { return []; },
|
||||
IsAlly: function() { return []; },
|
||||
IsEnemy: function() { return []; },
|
||||
});
|
||||
|
||||
|
||||
|
@ -1,10 +1,18 @@
|
||||
function ProcessCommand(player, cmd)
|
||||
{
|
||||
// print("command: " + player + " " + uneval(cmd) + "\n");
|
||||
|
||||
// TODO: all of this stuff needs to do checks for valid arguments
|
||||
// (e.g. make sure players own the units they're trying to use)
|
||||
// Do some basic checks here that commanding player is valid
|
||||
var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
if (!cmpPlayerMan || player < 0)
|
||||
return;
|
||||
var playerEnt = cmpPlayerMan.GetPlayerByID(player);
|
||||
if (playerEnt == INVALID_ENTITY)
|
||||
return;
|
||||
var cmpPlayer = Engine.QueryInterface(playerEnt, IID_Player);
|
||||
if (!cmpPlayer)
|
||||
return;
|
||||
var controlAllUnits = cmpPlayer.CanControlAllUnits();
|
||||
|
||||
// Now handle various commands
|
||||
switch (cmd.type)
|
||||
{
|
||||
case "debug-print":
|
||||
@ -16,6 +24,10 @@ function ProcessCommand(player, cmd)
|
||||
cmpGuiInterface.PushNotification({"type": "chat", "player": player, "message": cmd.message});
|
||||
break;
|
||||
|
||||
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
|
||||
@ -24,46 +36,69 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
case "walk":
|
||||
var cmpUnitAI = GetFormationUnitAI(cmd.entities);
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
var cmpUnitAI = GetFormationUnitAI(entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.Walk(cmd.x, cmd.z, cmd.queued);
|
||||
break;
|
||||
|
||||
case "attack":
|
||||
var cmpUnitAI = GetFormationUnitAI(cmd.entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.Attack(cmd.target, cmd.queued);
|
||||
// Check if target is owned by player's enemy
|
||||
if (IsOwnedByEnemyOfPlayer(player, cmd.target))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
var cmpUnitAI = GetFormationUnitAI(entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.Attack(cmd.target, cmd.queued);
|
||||
}
|
||||
break;
|
||||
|
||||
case "repair":
|
||||
// This covers both repairing damaged buildings, and constructing unfinished foundations
|
||||
var cmpUnitAI = GetFormationUnitAI(cmd.entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.Repair(cmd.target, cmd.autocontinue, cmd.queued);
|
||||
// Check if target building is owned by player or an ally
|
||||
if (IsOwnedByAllyOfPlayer(player, cmd.target))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
var cmpUnitAI = GetFormationUnitAI(entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.Repair(cmd.target, cmd.autocontinue, cmd.queued);
|
||||
}
|
||||
break;
|
||||
|
||||
case "gather":
|
||||
var cmpUnitAI = GetFormationUnitAI(cmd.entities);
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
var cmpUnitAI = GetFormationUnitAI(entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.Gather(cmd.target, cmd.queued);
|
||||
break;
|
||||
|
||||
case "returnresource":
|
||||
var cmpUnitAI = GetFormationUnitAI(cmd.entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.ReturnResource(cmd.target, cmd.queued);
|
||||
// Check dropsite is owned by player
|
||||
if (IsOwnedByPlayer(cmd.target, player))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
var cmpUnitAI = GetFormationUnitAI(entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.ReturnResource(cmd.target, cmd.queued);
|
||||
}
|
||||
break;
|
||||
|
||||
case "train":
|
||||
var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
|
||||
if (queue)
|
||||
queue.AddBatch(cmd.template, +cmd.count, cmd.metadata);
|
||||
if (CanControlUnit(cmd.entity, player, controlAllUnits))
|
||||
{
|
||||
var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
|
||||
if (queue)
|
||||
queue.AddBatch(cmd.template, +cmd.count, cmd.metadata);
|
||||
}
|
||||
break;
|
||||
|
||||
case "stop-train":
|
||||
var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
|
||||
if (queue)
|
||||
queue.RemoveBatch(cmd.id);
|
||||
if (CanControlUnit(cmd.entity, player, controlAllUnits))
|
||||
{
|
||||
var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
|
||||
if (queue)
|
||||
queue.RemoveBatch(cmd.id);
|
||||
}
|
||||
break;
|
||||
|
||||
case "construct":
|
||||
@ -88,11 +123,11 @@ function ProcessCommand(player, cmd)
|
||||
* . If it's destroyed, an appropriate fraction of the resource cost is refunded.
|
||||
* . If it's completed, it gets replaced with the real building.
|
||||
*/
|
||||
|
||||
// Find the player
|
||||
var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
var playerEnt = cmpPlayerMan.GetPlayerByID(player);
|
||||
var cmpPlayer = Engine.QueryInterface(playerEnt, IID_Player);
|
||||
|
||||
// Check that we can control these units
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
if (!entities.length)
|
||||
break;
|
||||
|
||||
// Tentatively create the foundation (we might find later that it's a invalid build command)
|
||||
var ent = Engine.AddEntity("foundation|" + cmd.template);
|
||||
@ -162,7 +197,7 @@ function ProcessCommand(player, cmd)
|
||||
{
|
||||
ProcessCommand(player, {
|
||||
"type": "repair",
|
||||
"entities": cmd.entities,
|
||||
"entities": entities,
|
||||
"target": ent,
|
||||
"autocontinue": cmd.autocontinue,
|
||||
"queued": cmd.queued
|
||||
@ -172,13 +207,9 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
case "delete-entities":
|
||||
for each (var ent in cmd.entities)
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
for each (var ent in entities)
|
||||
{
|
||||
// Verify the player owns the unit
|
||||
var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
if (!cmpOwnership || cmpOwnership.GetOwner() != player)
|
||||
continue;
|
||||
|
||||
var cmpHealth = Engine.QueryInterface(ent, IID_Health);
|
||||
if (cmpHealth)
|
||||
cmpHealth.Kill();
|
||||
@ -188,7 +219,8 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
case "set-rallypoint":
|
||||
for each (var ent in cmd.entities)
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
for each (var ent in entities)
|
||||
{
|
||||
var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
@ -197,7 +229,8 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
case "unset-rallypoint":
|
||||
for each (var ent in cmd.entities)
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
for each (var ent in entities)
|
||||
{
|
||||
var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
@ -206,42 +239,40 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
case "defeat-player":
|
||||
// Get player entity by playerId
|
||||
var cmpPlayerMananager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
var playerEnt = cmpPlayerManager.GetPlayerByID(cmd.playerId);
|
||||
// Send "OnPlayerDefeated" message to player
|
||||
Engine.PostMessage(playerEnt, MT_PlayerDefeated, null);
|
||||
break;
|
||||
|
||||
case "garrison":
|
||||
var targetCmpOwnership = Engine.QueryInterface(cmd.target, IID_Ownership);
|
||||
if (!targetCmpOwnership || targetCmpOwnership.GetOwner() != player)
|
||||
break;
|
||||
var cmpUnitAI = GetFormationUnitAI(cmd.entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.Garrison(cmd.target);
|
||||
if (CanControlUnit(cmd.target, player, controlAllUnits))
|
||||
{
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
var cmpUnitAI = GetFormationUnitAI(entities);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.Garrison(cmd.target);
|
||||
}
|
||||
break;
|
||||
|
||||
case "unload":
|
||||
var cmpOwnership = Engine.QueryInterface(cmd.garrisonHolder, IID_Ownership);
|
||||
if (!cmpOwnership || cmpOwnership.GetOwner() != player)
|
||||
break;
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(cmd.garrisonHolder, IID_GarrisonHolder);
|
||||
if (cmpGarrisonHolder)
|
||||
cmpGarrisonHolder.Unload(cmd.entity);
|
||||
if (CanControlUnit(cmd.garrisonHolder, player, controlAllUnits))
|
||||
{
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(cmd.garrisonHolder, IID_GarrisonHolder);
|
||||
if (cmpGarrisonHolder)
|
||||
cmpGarrisonHolder.Unload(cmd.entity);
|
||||
}
|
||||
break;
|
||||
|
||||
case "unload-all":
|
||||
var cmpOwnership = Engine.QueryInterface(cmd.garrisonHolder, IID_Ownership);
|
||||
if (!cmpOwnership || cmpOwnership.GetOwner() != player)
|
||||
break;
|
||||
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(cmd.garrisonHolder, IID_GarrisonHolder);
|
||||
cmpGarrisonHolder.UnloadAll();
|
||||
if (CanControlUnit(cmd.garrisonHolder, player, controlAllUnits))
|
||||
{
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(cmd.garrisonHolder, IID_GarrisonHolder);
|
||||
cmpGarrisonHolder.UnloadAll();
|
||||
}
|
||||
break;
|
||||
|
||||
case "formation":
|
||||
var cmpUnitAI = GetFormationUnitAI(cmd.entities);
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
var cmpUnitAI = GetFormationUnitAI(entities);
|
||||
if (!cmpUnitAI)
|
||||
break;
|
||||
var cmpFormation = Engine.QueryInterface(cmpUnitAI.entity, IID_Formation);
|
||||
@ -264,7 +295,8 @@ function ProcessCommand(player, cmd)
|
||||
break;
|
||||
|
||||
case "stance":
|
||||
for each (var ent in cmd.entities)
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
for each (var ent in entities)
|
||||
{
|
||||
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
|
||||
if (cmpUnitAI)
|
||||
@ -507,5 +539,32 @@ function CanMoveEntsIntoFormation(ents, formationName)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if entity is owned by player
|
||||
*/
|
||||
function IsOwnedByPlayer(entity, player)
|
||||
{
|
||||
var cmpOwnership = Engine.QueryInterface(entity, IID_Ownership);
|
||||
return (cmpOwnership && cmpOwnership.GetOwner() == player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if player can control this entity
|
||||
* returns: true if the entity is valid and owned by the player if
|
||||
* or control all units is activated for the player, else false
|
||||
*/
|
||||
function CanControlUnit(entity, player, controlAll)
|
||||
{
|
||||
return (IsOwnedByPlayer(entity, player) || controlAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter entities which the player can control
|
||||
*/
|
||||
function FilterEntityList(entities, player, controlAll)
|
||||
{
|
||||
return entities.filter(function(ent) { return CanControlUnit(ent, player, controlAll);} );
|
||||
}
|
||||
|
||||
Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation);
|
||||
Engine.RegisterGlobal("ProcessCommand", ProcessCommand);
|
||||
|
@ -40,24 +40,28 @@ function LoadPlayerSettings(settings)
|
||||
var diplomacy = [];
|
||||
|
||||
// Build team + diplomacy data
|
||||
for (var i = 0; i < (numPlayers - 1); ++i)
|
||||
for (var i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
diplomacy[i] = cmpPlayerMan.Diplomacy.ENEMY;
|
||||
|
||||
var pData = settings.PlayerData ? settings.PlayerData[i] : {};
|
||||
var pDefs = playerDefaults ? playerDefaults[i+1] : {};
|
||||
var team = getSetting(pData, pDefs, "Team");
|
||||
|
||||
// If team defined, add player to the team
|
||||
if (team !== undefined && team != -1)
|
||||
// Skip gaia
|
||||
if (i > 0)
|
||||
{
|
||||
if (!teams[team])
|
||||
var pData = settings.PlayerData ? settings.PlayerData[i-1] : {};
|
||||
var pDefs = playerDefaults ? playerDefaults[i] : {};
|
||||
var team = getSetting(pData, pDefs, "Team");
|
||||
|
||||
// If team defined, add player to the team
|
||||
if (team !== undefined && team != -1)
|
||||
{
|
||||
teams[team] = [i];
|
||||
}
|
||||
else
|
||||
{
|
||||
teams[team].push(i);
|
||||
if (!teams[team])
|
||||
{
|
||||
teams[team] = [i];
|
||||
}
|
||||
else
|
||||
{
|
||||
teams[team].push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,12 +82,12 @@ function LoadPlayerSettings(settings)
|
||||
|
||||
var pDefs = playerDefaults ? playerDefaults[i] : {};
|
||||
|
||||
// Use real player data if available
|
||||
// Skip gaia
|
||||
if (i > 0)
|
||||
{
|
||||
var pData = settings.PlayerData ? settings.PlayerData[i-1] : {};
|
||||
|
||||
// Copy player data if not gaia
|
||||
// Copy player data
|
||||
player.SetName(getSetting(pData, pDefs, "Name"));
|
||||
player.SetCiv(getSetting(pData, pDefs, "Civ"));
|
||||
|
||||
@ -201,7 +205,7 @@ function QueryPlayerIDInterface(id, iid)
|
||||
* Returns true if the entity 'target' is owned by an ally of
|
||||
* the owner of 'entity'.
|
||||
*/
|
||||
function IsOwnedByAlly(entity, target)
|
||||
function IsOwnedByAllyOfEntity(entity, target)
|
||||
{
|
||||
// Figure out which player controls us
|
||||
var owner = 0;
|
||||
@ -215,17 +219,56 @@ function IsOwnedByAlly(entity, target)
|
||||
if (cmpOwnershipTarget)
|
||||
targetOwner = cmpOwnershipTarget.GetOwner();
|
||||
|
||||
// Players are always implicitly their own ally
|
||||
if (owner == targetOwner)
|
||||
return true;
|
||||
|
||||
// Get our diplomacy array
|
||||
var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
var player = Engine.QueryInterface(playerMan.GetPlayerByID(owner), IID_Player);
|
||||
var diplomacy = player.GetDiplomacy();
|
||||
var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
var cmpPlayer = Engine.QueryInterface(cmpPlayerMan.GetPlayerByID(owner), IID_Player);
|
||||
|
||||
// Check for allied diplomacy status
|
||||
if (diplomacy[targetOwner - 1] > 0)
|
||||
if (cmpPlayer.IsAlly(targetOwner))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entity 'target' is owned by an ally of player
|
||||
*/
|
||||
function IsOwnedByAllyOfPlayer(player, target)
|
||||
{
|
||||
// Figure out which player controls the foundation being built
|
||||
var targetOwner = 0;
|
||||
var cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership);
|
||||
if (cmpOwnershipTarget)
|
||||
targetOwner = cmpOwnershipTarget.GetOwner();
|
||||
|
||||
// Get our diplomacy array
|
||||
var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
var cmpPlayer = Engine.QueryInterface(cmpPlayerMan.GetPlayerByID(player), IID_Player);
|
||||
|
||||
// Check for allied diplomacy status
|
||||
if (cmpPlayer.IsAlly(targetOwner))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entity 'target' is owned by an enemy of player
|
||||
*/
|
||||
function IsOwnedByEnemyOfPlayer(player, target)
|
||||
{
|
||||
// Figure out which player controls the foundation being built
|
||||
var targetOwner = 0;
|
||||
var cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership);
|
||||
if (cmpOwnershipTarget)
|
||||
targetOwner = cmpOwnershipTarget.GetOwner();
|
||||
|
||||
// Get our diplomacy array
|
||||
var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
var cmpPlayer = Engine.QueryInterface(cmpPlayerMan.GetPlayerByID(player), IID_Player);
|
||||
|
||||
// Check for allied diplomacy status
|
||||
if (cmpPlayer.IsEnemy(targetOwner))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -234,4 +277,6 @@ function IsOwnedByAlly(entity, target)
|
||||
Engine.RegisterGlobal("LoadPlayerSettings", LoadPlayerSettings);
|
||||
Engine.RegisterGlobal("QueryOwnerInterface", QueryOwnerInterface);
|
||||
Engine.RegisterGlobal("QueryPlayerIDInterface", QueryPlayerIDInterface);
|
||||
Engine.RegisterGlobal("IsOwnedByAlly", IsOwnedByAlly);
|
||||
Engine.RegisterGlobal("IsOwnedByAllyOfEntity", IsOwnedByAllyOfEntity);
|
||||
Engine.RegisterGlobal("IsOwnedByAllyOfPlayer", IsOwnedByAllyOfPlayer);
|
||||
Engine.RegisterGlobal("IsOwnedByEnemyOfPlayer", IsOwnedByEnemyOfPlayer);
|
||||
|
Loading…
Reference in New Issue
Block a user