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:
historic_bruno 2011-07-02 00:06:39 +00:00
parent 24f981cb2c
commit 4d188452f8
14 changed files with 311 additions and 152 deletions

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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"/>

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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);
}
}

View File

@ -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,

View File

@ -45,7 +45,8 @@ function TestFormationExiting(mode)
});
AddMock(playerEntity, IID_Player, {
GetDiplomacy: function() { return []; },
IsAlly: function() { return []; },
IsEnemy: function() { return []; },
});

View File

@ -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);

View File

@ -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);