diff --git a/binaries/data/mods/public/gui/session/diplomacy/playercontrols/StanceButton.js b/binaries/data/mods/public/gui/session/diplomacy/playercontrols/StanceButton.js
index dc03f81cbd..4c7c6e2e28 100644
--- a/binaries/data/mods/public/gui/session/diplomacy/playercontrols/StanceButton.js
+++ b/binaries/data/mods/public/gui/session/diplomacy/playercontrols/StanceButton.js
@@ -11,7 +11,7 @@ DiplomacyDialogPlayerControl.prototype.StanceButtonManager = class
update(playerInactive)
{
- let hidden = playerInactive || GetSimState().ceasefireActive || g_Players[g_ViewedPlayer].teamsLocked;
+ let hidden = playerInactive || GetSimState().ceasefireActive || g_Players[g_ViewedPlayer].teamLocked;
for (let button of this.buttons)
button.update(hidden);
diff --git a/binaries/data/mods/public/gui/session/lobby/LobbyRatingReport/Players.js b/binaries/data/mods/public/gui/session/lobby/LobbyRatingReport/Players.js
index 2650816951..a60771736a 100644
--- a/binaries/data/mods/public/gui/session/lobby/LobbyRatingReport/Players.js
+++ b/binaries/data/mods/public/gui/session/lobby/LobbyRatingReport/Players.js
@@ -9,7 +9,7 @@ LobbyRatingReport.prototype.Players = class
"playerStates": playerStates.map(playerState => playerState.state).join(",") + ",",
"civs": playerStates.map(playerState => playerState.civ).join(",") + ",",
"teams": playerStates.map(playerState => playerState.team).join(",") + ",",
- "teamsLocked": String(playerStates.every(playerState => playerState.teamsLocked))
+ "teamsLocked": String(playerStates.every(playerState => playerState.teamLocked))
});
}
};
diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js
index f565ad0838..023cbfccb9 100644
--- a/binaries/data/mods/public/gui/session/session.js
+++ b/binaries/data/mods/public/gui/session/session.js
@@ -391,7 +391,7 @@ function updatePlayerData()
"a": playerState.color.a * 255
},
"team": playerState.team,
- "teamsLocked": playerState.teamsLocked,
+ "teamLocked": playerState.teamLocked,
"cheatsEnabled": playerState.cheatsEnabled,
"state": playerState.state,
"isAlly": playerState.isAlly,
diff --git a/binaries/data/mods/public/maps/scripts/CaptureTheRelic.js b/binaries/data/mods/public/maps/scripts/CaptureTheRelic.js
index 55e5947d0f..b36163d868 100644
--- a/binaries/data/mods/public/maps/scripts/CaptureTheRelic.js
+++ b/binaries/data/mods/public/maps/scripts/CaptureTheRelic.js
@@ -67,7 +67,7 @@ Trigger.prototype.CheckCaptureTheRelicCountdown = function()
}
let winningPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager).GetAlliedVictory() ?
- activePlayers.filter(playerID => relicOwners.every(owner => QueryPlayerIDInterface(playerID).IsMutualAlly(owner))) :
+ activePlayers.filter(playerID => relicOwners.every(owner => QueryPlayerIDInterface(playerID, IID_Diplomacy).IsMutualAlly(owner))) :
[relicOwners[0]];
// All relicOwners should be mutually allied
diff --git a/binaries/data/mods/public/maps/scripts/WonderVictory.js b/binaries/data/mods/public/maps/scripts/WonderVictory.js
index b2c6d8fc13..4ec3a710bb 100644
--- a/binaries/data/mods/public/maps/scripts/WonderVictory.js
+++ b/binaries/data/mods/public/maps/scripts/WonderVictory.js
@@ -36,7 +36,7 @@ Trigger.prototype.WonderVictoryDiplomacyChanged = function(data)
let owner = this.wonderVictoryMessages[ent].playerID;
let otherPlayer = owner == data.player ? data.otherPlayer : data.player;
- let newAllies = new Set(QueryPlayerIDInterface(owner).GetPlayersByDiplomacy("IsExclusiveMutualAlly"));
+ let newAllies = new Set(QueryPlayerIDInterface(owner, IID_Diplomacy).GetPlayersByDiplomacy("IsExclusiveMutualAlly"));
if (newAllies.has(otherPlayer) && !this.wonderVictoryMessages[ent].allies.has(otherPlayer) ||
!newAllies.has(otherPlayer) && this.wonderVictoryMessages[ent].allies.has(otherPlayer))
{
@@ -53,7 +53,7 @@ Trigger.prototype.WonderVictoryStartTimer = function(ent, player)
{
let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager);
let allies = cmpEndGameManager.GetAlliedVictory() ?
- QueryPlayerIDInterface(player).GetPlayersByDiplomacy("IsExclusiveMutualAlly") : [];
+ QueryPlayerIDInterface(player, IID_Diplomacy).GetPlayersByDiplomacy("IsExclusiveMutualAlly") : [];
let others = [-1];
for (let playerID = 1; playerID < TriggerHelper.GetNumberOfPlayers(); ++playerID)
diff --git a/binaries/data/mods/public/simulation/components/AlertRaiser.js b/binaries/data/mods/public/simulation/components/AlertRaiser.js
index b1a394a1bd..ced18da39c 100644
--- a/binaries/data/mods/public/simulation/components/AlertRaiser.js
+++ b/binaries/data/mods/public/simulation/components/AlertRaiser.js
@@ -37,8 +37,8 @@ AlertRaiser.prototype.RaiseAlert = function()
return;
let owner = cmpOwnership.GetOwner();
- let cmpPlayer = QueryOwnerInterface(this.entity);
- let mutualAllies = cmpPlayer ? cmpPlayer.GetMutualAllies() : [owner];
+ const cmpDiplomacy = QueryPlayerIDInterface(owner, IID_Diplomacy);
+ const mutualAllies = cmpDiplomacy ? cmpDiplomacy.GetMutualAllies() : [owner];
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
// Store the number of available garrison spots so that units don't try to garrison in buildings that will be full
@@ -98,8 +98,8 @@ AlertRaiser.prototype.EndOfAlert = function()
return;
let owner = cmpOwnership.GetOwner();
- let cmpPlayer = QueryOwnerInterface(this.entity);
- let mutualAllies = cmpPlayer ? cmpPlayer.GetMutualAllies() : [owner];
+ const cmpDiplomacy = QueryPlayerIDInterface(owner, IID_Diplomacy);
+ const mutualAllies = cmpDiplomacy ? cmpDiplomacy.GetMutualAllies() : [owner];
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
// Units that are not garrisoned should go back to work
diff --git a/binaries/data/mods/public/simulation/components/Attack.js b/binaries/data/mods/public/simulation/components/Attack.js
index 9876abca2a..2ac58ac315 100644
--- a/binaries/data/mods/public/simulation/components/Attack.js
+++ b/binaries/data/mods/public/simulation/components/Attack.js
@@ -270,6 +270,7 @@ Attack.prototype.CanAttack = function(target, wantedTypes)
const entityOwner = cmpEntityPlayer.GetPlayerID();
const targetOwner = cmpTargetPlayer.GetPlayerID();
const cmpCapturable = QueryMiragedInterface(target, IID_Capturable);
+ const cmpDiplomacy = QueryPlayerIDInterface(entityOwner, IID_Diplomacy);
// Check if the relative height difference is larger than the attack range
// If the relative height is bigger, it means they will never be able to
@@ -278,7 +279,7 @@ Attack.prototype.CanAttack = function(target, wantedTypes)
for (const type of types)
{
- if (type != "Capture" && (!cmpEntityPlayer.IsEnemy(targetOwner) || !cmpHealth || !cmpHealth.GetHitpoints()))
+ if (type != "Capture" && (!cmpDiplomacy?.IsEnemy(targetOwner) || !cmpHealth || !cmpHealth.GetHitpoints()))
continue;
if (type == "Capture" && (!cmpCapturable || !cmpCapturable.CanCapture(entityOwner)))
diff --git a/binaries/data/mods/public/simulation/components/Auras.js b/binaries/data/mods/public/simulation/components/Auras.js
index 58d9c1a9ad..a21fb59a4f 100644
--- a/binaries/data/mods/public/simulation/components/Auras.js
+++ b/binaries/data/mods/public/simulation/components/Auras.js
@@ -123,6 +123,10 @@ Auras.prototype.CalculateAffectedPlayers = function(name)
if (!cmpPlayer || cmpPlayer.IsDefeated())
return;
+ const playerID = cmpPlayer.GetPlayerID();
+ const cmpDiplomacy = Engine.QueryInterface(this.entity, IID_Diplomacy) ??
+ QueryPlayerIDInterface(playerID, IID_Diplomacy);
+
let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
for (let i of cmpPlayerManager.GetAllPlayers())
{
@@ -130,7 +134,7 @@ Auras.prototype.CalculateAffectedPlayers = function(name)
if (!cmpAffectedPlayer || cmpAffectedPlayer.IsDefeated())
continue;
- if (affectedPlayers.some(p => p == "Player" ? cmpPlayer.GetPlayerID() == i : cmpPlayer["Is" + p](i)))
+ if (affectedPlayers.some(p => p == "Player" ? playerID == i : cmpDiplomacy["Is" + p](i)))
this.affectedPlayers[name].push(i);
}
};
diff --git a/binaries/data/mods/public/simulation/components/BuildRestrictions.js b/binaries/data/mods/public/simulation/components/BuildRestrictions.js
index 4fcac7993c..792d592975 100644
--- a/binaries/data/mods/public/simulation/components/BuildRestrictions.js
+++ b/binaries/data/mods/public/simulation/components/BuildRestrictions.js
@@ -175,11 +175,16 @@ BuildRestrictions.prototype.CheckPlacement = function()
if (!cmpTerritoryManager || !cmpPosition || !cmpPosition.IsInWorld())
return result; // Fail
+ const playerID = cmpPlayer.GetPlayerID();
+ const cmpDiplomacy = QueryPlayerIDInterface(playerID, IID_Diplomacy);
+ if (!cmpDiplomacy)
+ return result;
+
var pos = cmpPosition.GetPosition2D();
var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y);
var isConnected = !cmpTerritoryManager.IsTerritoryBlinking(pos.x, pos.y);
- var isOwn = tileOwner == cmpPlayer.GetPlayerID();
- var isMutualAlly = cmpPlayer.IsExclusiveMutualAlly(tileOwner);
+ var isOwn = tileOwner == playerID;
+ var isMutualAlly = cmpDiplomacy.IsExclusiveMutualAlly(tileOwner);
var isNeutral = tileOwner == 0;
var invalidTerritory = "";
diff --git a/binaries/data/mods/public/simulation/components/BuildingAI.js b/binaries/data/mods/public/simulation/components/BuildingAI.js
index 3a840520e0..634fc9df9b 100644
--- a/binaries/data/mods/public/simulation/components/BuildingAI.js
+++ b/binaries/data/mods/public/simulation/components/BuildingAI.js
@@ -111,11 +111,11 @@ BuildingAI.prototype.SetupRangeQuery = function()
this.enemyUnitsQuery = undefined;
}
- var cmpPlayer = QueryOwnerInterface(this.entity);
- if (!cmpPlayer)
+ const cmpDiplomacy = QueryOwnerInterface(this.entity, IID_Diplomacy);
+ if (!cmpDiplomacy)
return;
- var enemies = cmpPlayer.GetEnemies();
+ const enemies = cmpDiplomacy.GetEnemies();
// Remove gaia.
if (enemies.length && enemies[0] == 0)
enemies.shift();
@@ -148,8 +148,7 @@ BuildingAI.prototype.SetupGaiaRangeQuery = function()
this.gaiaUnitsQuery = undefined;
}
- var cmpPlayer = QueryOwnerInterface(this.entity);
- if (!cmpPlayer || !cmpPlayer.IsEnemy(0))
+ if (!QueryOwnerInterface(this.entity, IID_Diplomacy)?.IsEnemy(0))
return;
const range = cmpAttack.GetRange(attackType);
diff --git a/binaries/data/mods/public/simulation/components/Capturable.js b/binaries/data/mods/public/simulation/components/Capturable.js
index 8a431afd4c..c1dd55f505 100644
--- a/binaries/data/mods/public/simulation/components/Capturable.js
+++ b/binaries/data/mods/public/simulation/components/Capturable.js
@@ -83,8 +83,8 @@ Capturable.prototype.Reduce = function(amount, playerID)
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER)
return 0;
- let cmpPlayerSource = QueryPlayerIDInterface(playerID);
- if (!cmpPlayerSource)
+ const cmpDiplomacySource = QueryPlayerIDInterface(playerID, IID_Diplomacy);
+ if (!cmpDiplomacySource)
return 0;
// Before changing the value, activate Fogging if necessary to hide changes.
@@ -92,7 +92,7 @@ Capturable.prototype.Reduce = function(amount, playerID)
if (cmpFogging)
cmpFogging.Activate();
- let numberOfEnemies = this.capturePoints.filter((v, i) => v > 0 && cmpPlayerSource.IsEnemy(i)).length;
+ let numberOfEnemies = this.capturePoints.filter((v, i) => v > 0 && cmpDiplomacySource.IsEnemy(i)).length;
if (numberOfEnemies == 0)
return 0;
@@ -105,7 +105,7 @@ Capturable.prototype.Reduce = function(amount, playerID)
numberOfEnemies = 0;
for (let i in this.capturePoints)
{
- if (!this.capturePoints[i] || !cmpPlayerSource.IsEnemy(i))
+ if (!this.capturePoints[i] || !cmpDiplomacySource.IsEnemy(i))
continue;
if (this.capturePoints[i] > distributedAmount)
{
@@ -138,14 +138,14 @@ Capturable.prototype.Reduce = function(amount, playerID)
*/
Capturable.prototype.CanCapture = function(playerID)
{
- let cmpPlayerSource = QueryPlayerIDInterface(playerID);
+ const cmpDiplomacySource = QueryPlayerIDInterface(playerID, IID_Diplomacy);
- if (!cmpPlayerSource)
- warn(playerID + " has no player component defined on its id.");
+ if (!cmpDiplomacySource)
+ warn(playerID + " has no diplomacy component defined on its id.");
let capturePoints = this.GetCapturePoints();
let sourceEnemyCapturePoints = 0;
for (let i in this.GetCapturePoints())
- if (cmpPlayerSource.IsEnemy(i))
+ if (cmpDiplomacySource.IsEnemy(i))
sourceEnemyCapturePoints += capturePoints[i];
return sourceEnemyCapturePoints > 0;
};
diff --git a/binaries/data/mods/public/simulation/components/CeasefireManager.js b/binaries/data/mods/public/simulation/components/CeasefireManager.js
index e64e2c955c..17a9a6b9b1 100644
--- a/binaries/data/mods/public/simulation/components/CeasefireManager.js
+++ b/binaries/data/mods/public/simulation/components/CeasefireManager.js
@@ -71,13 +71,13 @@ CeasefireManager.prototype.StartCeasefire = function(ceasefireTime)
// Save diplomacy
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
for (let i = 1; i < numPlayers; ++i)
- this.diplomacyBeforeCeasefire.push(QueryPlayerIDInterface(i).GetDiplomacy());
+ this.diplomacyBeforeCeasefire.push(QueryPlayerIDInterface(i, IID_Diplomacy).GetDiplomacy());
// Set every enemy (except gaia) to neutral
for (let i = 1; i < numPlayers; ++i)
for (let j = 1; j < numPlayers; ++j)
if (this.diplomacyBeforeCeasefire[i-1][j] < 0)
- QueryPlayerIDInterface(i).SetNeutral(j);
+ QueryPlayerIDInterface(i, IID_Diplomacy).SetNeutral(j);
}
this.ceasefireIsActive = true;
@@ -116,7 +116,7 @@ CeasefireManager.prototype.StopCeasefire = function()
// Reset diplomacies to original settings
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
for (let i = 1; i < numPlayers; ++i)
- QueryPlayerIDInterface(i).SetDiplomacy(this.diplomacyBeforeCeasefire[i-1]);
+ QueryPlayerIDInterface(i, IID_Diplomacy).SetDiplomacy(this.diplomacyBeforeCeasefire[i-1]);
this.ceasefireIsActive = false;
this.ceasefireTime = 0;
diff --git a/binaries/data/mods/public/simulation/components/Diplomacy.js b/binaries/data/mods/public/simulation/components/Diplomacy.js
new file mode 100644
index 0000000000..f91e58daf0
--- /dev/null
+++ b/binaries/data/mods/public/simulation/components/Diplomacy.js
@@ -0,0 +1,347 @@
+function Diplomacy() {}
+
+Diplomacy.prototype.Schema =
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+
+Diplomacy.prototype.SerializableAttributes = [
+ "team",
+ "teamLocked",
+ "diplomacy",
+ "sharedDropsites",
+];
+
+Diplomacy.prototype.Serialize = function()
+{
+ const state = {};
+ for (const key in this.SerializableAttributes)
+ if (this.hasOwnProperty(key))
+ state[key] = this[key];
+
+ return state;
+};
+
+Diplomacy.prototype.Deserialize = function(state)
+{
+ for (const prop in state)
+ this[prop] = state[prop];
+};
+
+Diplomacy.prototype.Init = function()
+{
+ // Team number of the player, players on the same team will always have ally diplomatic status. Also this is useful for team emblems, scoring, etc.
+ this.team = -1;
+
+ // Array of diplomatic stances for this player with respect to other players (including gaia and self).
+ this.diplomacy = [];
+};
+
+/**
+ * @param {Object} color - r, g, b values of the diplomacy colour.
+ */
+Diplomacy.prototype.SetDiplomacyColor = function(color)
+{
+ this.diplomacyColor = { "r": color.r / 255, "g": color.g / 255, "b": color.b / 255, "a": 1 };
+};
+
+/**
+ * @return {Object} -
+ */
+Diplomacy.prototype.GetColor = function()
+{
+ return this.diplomacyColor;
+};
+
+/**
+ * @return {number} -
+ */
+Diplomacy.prototype.GetTeam = function()
+{
+ return this.team;
+};
+
+/**
+ * @param {number} team - The new team number, -1 for no team.
+ */
+Diplomacy.prototype.ChangeTeam = function(team)
+{
+ if (this.teamLocked || this.team === team)
+ return;
+
+ const playerID = Engine.QueryInterface(this.entity, IID_Player)?.GetPlayerID();
+ if (!playerID)
+ return;
+
+ // ToDo: Fix this.
+ if (this.team !== -1)
+ warn("A change in teams is requested while the player already had a team, previous alliances are maintained.");
+
+ this.team = team;
+
+ if (this.team !== -1)
+ {
+ const numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
+ for (let i = 0; i < numPlayers; ++i)
+ {
+ const cmpDiplomacy = QueryPlayerIDInterface(i, IID_Diplomacy);
+ if (this.team !== cmpDiplomacy.GetTeam())
+ continue;
+
+ this.Ally(i);
+ cmpDiplomacy.Ally(playerID);
+ }
+ }
+
+ Engine.BroadcastMessage(MT_DiplomacyChanged, {
+ "player": playerID,
+ "otherPlayer": null
+ });
+};
+
+Diplomacy.prototype.LockTeam = function()
+{
+ this.teamLocked = true;
+};
+
+Diplomacy.prototype.UnLockTeam = function()
+{
+ delete this.teamLocked;
+};
+
+/**
+ * @return {boolean} -
+ */
+Diplomacy.prototype.IsTeamLocked = function()
+{
+ return !!this.teamLocked;
+};
+
+/**
+ * @return {number[]} - Current diplomatic stances.
+ */
+Diplomacy.prototype.GetDiplomacy = function()
+{
+ return this.diplomacy.slice();
+};
+
+/**
+ * @param {number[]} dipl - The diplomacy array to set.
+ */
+Diplomacy.prototype.SetDiplomacy = function(dipl)
+{
+ const playerID = Engine.QueryInterface(this.entity, IID_Player)?.GetPlayerID();
+ if (!playerID)
+ return
+
+ this.diplomacy = dipl.slice();
+
+ Engine.BroadcastMessage(MT_DiplomacyChanged, {
+ "player": playerID,
+ "otherPlayer": null
+ });
+};
+
+/**
+ * Helper function for allying etc.
+ * @param {number} idx - The player number.
+ * @param {number} value - The diplomacy value.
+ */
+Diplomacy.prototype.SetDiplomacyIndex = function(idx, value)
+{
+ if (!QueryPlayerIDInterface(idx)?.IsActive())
+ return;
+
+ const cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
+ if (!cmpPlayer?.IsActive())
+ return;
+
+ this.diplomacy[idx] = value;
+
+ const playerID = cmpPlayer.GetPlayerID();
+ Engine.BroadcastMessage(MT_DiplomacyChanged, {
+ "player": playerID,
+ "otherPlayer": idx,
+ "value": value
+ });
+};
+
+/**
+ * Helper function for getting allies etc.
+ * @param {string} func - Name of the function to test.
+ * @return {number[]} - Player IDs matching the function.
+ */
+Diplomacy.prototype.GetPlayersByDiplomacy = function(func)
+{
+ const players = [];
+ for (let i = 0; i < this.diplomacy.length; ++i)
+ if (this[func](i))
+ players.push(i);
+ return players;
+};
+
+/**
+ * @param {number} - id
+ */
+Diplomacy.prototype.Ally = function(id)
+{
+ this.SetDiplomacyIndex(id, 1);
+};
+
+/**
+ * Check if given player is our ally.
+ * @param {number} id -
+ * @return {boolean} -
+ */
+Diplomacy.prototype.IsAlly = function(id)
+{
+ return this.diplomacy[id] > 0;
+};
+
+/**
+ * @return {number[]} -
+ */
+Diplomacy.prototype.GetAllies = function()
+{
+ return this.GetPlayersByDiplomacy("IsAlly");
+};
+
+/**
+ * Check if given player is our ally excluding ourself.
+ * @param {number} id -
+ * @return {boolean} -
+ */
+Diplomacy.prototype.IsExclusiveAlly = function(id)
+{
+ return Engine.QueryInterface(this.entity, IID_Player)?.GetPlayerID() !== id && this.IsAlly(id);
+};
+
+/**
+ * Check if given player is our ally, and we are its ally.
+ * @param {number} id -
+ * @return {boolean} -
+ */
+Diplomacy.prototype.IsMutualAlly = function(id)
+{
+ const playerID = Engine.QueryInterface(this.entity, IID_Player)?.GetPlayerID();
+ return this.IsAlly(id) && playerID && QueryPlayerIDInterface(id, IID_Diplomacy)?.IsAlly(playerID);
+};
+
+/**
+ * @return {number[]} -
+ */
+Diplomacy.prototype.GetMutualAllies = function()
+{
+ return this.GetPlayersByDiplomacy("IsMutualAlly");
+};
+
+/**
+ * Check if given player is our ally, and we are its ally, excluding ourself.
+ * @param {number} id -
+ * @return {boolean} -
+ */
+Diplomacy.prototype.IsExclusiveMutualAlly = function(id)
+{
+ const playerID = Engine.QueryInterface(this.entity, IID_Player)?.GetPlayerID();
+ return playerID && playerID !== id && this.IsMutualAlly(id);
+};
+
+/**
+ * @param {number} id -
+ */
+Diplomacy.prototype.SetEnemy = function(id)
+{
+ this.SetDiplomacyIndex(id, -1);
+};
+
+/**
+ * Check if given player is our enemy.
+ * @param {number} id -
+ * @return {boolean} -
+ */
+Diplomacy.prototype.IsEnemy = function(id)
+{
+ return this.diplomacy[id] < 0;
+};
+
+/**
+ * @return {number[]} -
+ */
+Diplomacy.prototype.GetEnemies = function()
+{
+ return this.GetPlayersByDiplomacy("IsEnemy");
+};
+
+/**
+ * @param {number} id -
+ */
+Diplomacy.prototype.SetNeutral = function(id)
+{
+ this.SetDiplomacyIndex(id, 0);
+};
+
+/**
+ * Check if given player is neutral.
+ * @param {number} id -
+ * @return {boolean} -
+ */
+Diplomacy.prototype.IsNeutral = function(id)
+{
+ return this.diplomacy[id] === 0;
+};
+
+/**
+ * @return {boolean} -
+ */
+Diplomacy.prototype.HasSharedDropsites = function()
+{
+ return this.sharedDropsites;
+};
+
+/**
+ * @return {boolean} -
+ */
+Diplomacy.prototype.HasSharedLos = function()
+{
+ const cmpTechnologyManager = Engine.QueryInterface(this.entity, IID_TechnologyManager);
+ return cmpTechnologyManager && cmpTechnologyManager.IsTechnologyResearched(this.template.SharedLosTech);
+};
+
+Diplomacy.prototype.UpdateSharedLos = function()
+{
+ const playerID = Engine.QueryInterface(this.entity, IID_Player).GetPlayerID();
+ if (!playerID)
+ return;
+
+ Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager)?.
+ SetSharedLos(playerID, this.HasSharedLos() ? this.GetMutualAllies() : [playerID]);
+};
+
+Diplomacy.prototype.OnResearchFinished = function(msg)
+{
+ if (msg.tech === this.template.SharedLosTech)
+ this.UpdateSharedLos();
+ else if (msg.tech === this.template.SharedDropsitesTech)
+ this.sharedDropsites = true;
+};
+
+Diplomacy.prototype.OnDiplomacyChanged = function(msg)
+{
+ this.UpdateSharedLos();
+
+ if (msg.otherPlayer === null)
+ return;
+
+ const cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
+ if (!cmpPlayer || cmpPlayer.GetPlayerID() != msg.otherPlayer)
+ return;
+
+ // Mutual worsening of relations.
+ if (this.diplomacy[msg.player] > msg.value)
+ this.SetDiplomacyIndex(msg.player, msg.value);
+};
+
+Engine.RegisterComponentType(IID_Diplomacy, "Diplomacy", Diplomacy);
diff --git a/binaries/data/mods/public/simulation/components/EndGameManager.js b/binaries/data/mods/public/simulation/components/EndGameManager.js
index 383cfee6f9..f2e59cd87b 100644
--- a/binaries/data/mods/public/simulation/components/EndGameManager.js
+++ b/binaries/data/mods/public/simulation/components/EndGameManager.js
@@ -66,7 +66,7 @@ EndGameManager.prototype.MarkPlayerAndAlliesAsWon = function(playerID, victorySt
let winningPlayers = [playerID];
if (this.alliedVictory)
- winningPlayers = cmpPlayer.GetMutualAllies(playerID).filter(
+ winningPlayers = QueryPlayerIDInterface(playerID, IID_Diplomacy).GetMutualAllies(playerID).filter(
player => QueryPlayerIDInterface(player).IsActive());
this.MarkPlayersAsWon(winningPlayers, victoryString, defeatString);
@@ -148,7 +148,7 @@ EndGameManager.prototype.AlliedVictoryCheck = function()
if (!cmpPlayer.IsActive())
continue;
- if (allies.length && !cmpPlayer.IsMutualAlly(allies[0]))
+ if (allies.length && !QueryPlayerIDInterface(playerID, IID_Diplomacy).IsMutualAlly(allies[0]))
return;
allies.push(playerID);
diff --git a/binaries/data/mods/public/simulation/components/Gate.js b/binaries/data/mods/public/simulation/components/Gate.js
index 194bcaa2c0..d2d962df5e 100644
--- a/binaries/data/mods/public/simulation/components/Gate.js
+++ b/binaries/data/mods/public/simulation/components/Gate.js
@@ -72,7 +72,7 @@ Gate.prototype.SetupRangeQuery = function(owner)
cmpRangeManager.DestroyActiveQuery(this.unitsQuery);
// Only allied units can make the gate open.
- var players = QueryPlayerIDInterface(owner).GetAllies();
+ const players = QueryPlayerIDInterface(owner, IID_Diplomacy).GetAllies();
var range = this.GetPassRange();
if (range > 0)
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
index 99644763ce..0d5349a661 100644
--- a/binaries/data/mods/public/simulation/components/GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -3,6 +3,8 @@ function GuiInterface() {}
GuiInterface.prototype.Schema =
"";
+GuiInterface.prototype.WHITE = { "r": 1, "g": 1, "b": 1 };
+
GuiInterface.prototype.Serialize = function()
{
// This component isn't network-synchronized for the biggest part,
@@ -66,6 +68,7 @@ GuiInterface.prototype.GetSimulationState = function()
const cmpPlayer = Engine.QueryInterface(playerEnt, IID_Player);
const cmpPlayerEntityLimits = Engine.QueryInterface(playerEnt, IID_EntityLimits);
const cmpIdentity = Engine.QueryInterface(playerEnt, IID_Identity);
+ const cmpDiplomacy = Engine.QueryInterface(playerEnt, IID_Diplomacy);
// Work out which phase we are in.
let phase = "";
@@ -87,10 +90,10 @@ GuiInterface.prototype.GetSimulationState = function()
for (let j = 0; j < numPlayers; ++j)
{
- allies[j] = cmpPlayer.IsAlly(j);
- mutualAllies[j] = cmpPlayer.IsMutualAlly(j);
- neutrals[j] = cmpPlayer.IsNeutral(j);
- enemies[j] = cmpPlayer.IsEnemy(j);
+ allies[j] = cmpDiplomacy.IsAlly(j);
+ mutualAllies[j] = cmpDiplomacy.IsMutualAlly(j);
+ neutrals[j] = cmpDiplomacy.IsNeutral(j);
+ enemies[j] = cmpDiplomacy.IsEnemy(j);
}
ret.players.push({
@@ -107,13 +110,13 @@ GuiInterface.prototype.GetSimulationState = function()
"resourceGatherers": cmpPlayer.GetResourceGatherers(),
"trainingBlocked": cmpPlayer.IsTrainingBlocked(),
"state": cmpPlayer.GetState(),
- "team": cmpPlayer.GetTeam(),
- "teamsLocked": cmpPlayer.GetLockTeams(),
+ "team": cmpDiplomacy.GetTeam(),
+ "teamLocked": cmpDiplomacy.IsTeamLocked(),
"cheatsEnabled": cmpPlayer.GetCheatsEnabled(),
"disabledTemplates": cmpPlayer.GetDisabledTemplates(),
"disabledTechnologies": cmpPlayer.GetDisabledTechnologies(),
- "hasSharedDropsites": cmpPlayer.HasSharedDropsites(),
- "hasSharedLos": cmpPlayer.HasSharedLos(),
+ "hasSharedDropsites": cmpDiplomacy.HasSharedDropsites(),
+ "hasSharedLos": cmpDiplomacy.HasSharedLos(),
"spyCostMultiplier": cmpPlayer.GetSpyCostMultiplier(),
"phase": phase,
"isAlly": allies,
@@ -910,13 +913,13 @@ GuiInterface.prototype.UpdateDisplayedPlayerColors = function(player, data)
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
for (let i = 1; i < numPlayers; ++i)
{
- let cmpPlayer = QueryPlayerIDInterface(i, IID_Player);
- if (!cmpPlayer)
+ const cmpDiplomacy = QueryPlayerIDInterface(i, IID_Diplomacy);
+ if (!cmpDiplomacy)
continue;
- cmpPlayer.SetDisplayDiplomacyColor(data.displayDiplomacyColors);
+ QueryPlayerIDInterface(i, IID_Player).SetDisplayDiplomacyColor(data.displayDiplomacyColors);
if (data.displayDiplomacyColors)
- cmpPlayer.SetDiplomacyColor(data.displayedPlayerColors[i]);
+ cmpDiplomacy.SetDiplomacyColor(data.displayedPlayerColors[i]);
updateEntityColor(data.showAllStatusBars && (i == player || player == -1) ?
[IID_Minimap, IID_RangeOverlayRenderer, IID_RallyPointRenderer, IID_StatusBars] :
@@ -947,10 +950,7 @@ GuiInterface.prototype.SetSelectionHighlight = function(player, cmd)
let color = playerColors[owner];
if (!color)
{
- color = { "r": 1, "g": 1, "b": 1 };
- let cmpPlayer = QueryPlayerIDInterface(owner);
- if (cmpPlayer)
- color = cmpPlayer.GetDisplayedColor();
+ color = QueryPlayerIDInterface(owner, IID_Player)?.GetDisplayedColor() || this.WHITE;
playerColors[owner] = color;
}
diff --git a/binaries/data/mods/public/simulation/components/Player.js b/binaries/data/mods/public/simulation/components/Player.js
index 42cea727d9..242e34e373 100644
--- a/binaries/data/mods/public/simulation/components/Player.js
+++ b/binaries/data/mods/public/simulation/components/Player.js
@@ -17,12 +17,6 @@ Player.prototype.Schema =
"" +
"" +
"" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
"" +
"" +
"";
@@ -32,9 +26,6 @@ Player.prototype.STATE_ACTIVE = "active";
Player.prototype.STATE_DEFEATED = "defeated";
Player.prototype.STATE_WON = "won";
-/**
- * Don't serialize diplomacyColor or displayDiplomacyColor since they're modified by the GUI.
- */
Player.prototype.Serialize = function()
{
let state = {};
@@ -42,8 +33,8 @@ Player.prototype.Serialize = function()
if (this.hasOwnProperty(key))
state[key] = this[key];
- state.diplomacyColor = undefined;
- state.displayDiplomacyColor = false;
+ // Modified by GUI, so don't serialise.
+ delete state.displayDiplomacyColor;
return state;
};
@@ -62,8 +53,6 @@ Player.prototype.Init = function()
{
this.playerID = undefined;
this.color = undefined;
- this.diplomacyColor = undefined;
- this.displayDiplomacyColor = false;
this.popUsed = 0; // Population of units owned or trained by this player.
this.popBonuses = 0; // Sum of population bonuses of player's entities.
this.maxPop = 300; // Maximum population.
@@ -71,11 +60,7 @@ Player.prototype.Init = function()
this.resourceCount = {};
this.resourceGatherers = {};
this.tradingGoods = []; // Goods for next trade-route and its probabilities * 100.
- this.team = -1; // Team number of the player, players on the same team will always have ally diplomatic status. Also this is useful for team emblems, scoring, etc.
- this.teamsLocked = false;
this.state = this.STATE_ACTIVE;
- this.diplomacy = []; // Array of diplomatic stances for this player with respect to other players (including gaia and self).
- this.sharedDropsites = false;
this.formations = this.template.Formations._string.split(" ");
this.startCam = undefined;
this.controlAllUnits = false;
@@ -134,11 +119,6 @@ Player.prototype.SetColor = function(r, g, b)
});
};
-Player.prototype.SetDiplomacyColor = function(color)
-{
- this.diplomacyColor = { "r": color.r / 255, "g": color.g / 255, "b": color.b / 255, "a": 1 };
-};
-
Player.prototype.SetDisplayDiplomacyColor = function(displayDiplomacyColor)
{
this.displayDiplomacyColor = displayDiplomacyColor;
@@ -151,7 +131,7 @@ Player.prototype.GetColor = function()
Player.prototype.GetDisplayedColor = function()
{
- return this.displayDiplomacyColor ? this.diplomacyColor : this.color;
+ return this.displayDiplomacyColor ? Engine.QueryInterface(this.entity, IID_Diplomacy).GetColor() : this.color;
};
// Try reserving num population slots. Returns 0 on success or number of missing slots otherwise.
@@ -543,101 +523,6 @@ Player.prototype.SetState = function(newState, message)
Engine.PostMessage(this.entity, won ? MT_PlayerWon : MT_PlayerDefeated, { "playerId": this.playerID });
};
-Player.prototype.GetTeam = function()
-{
- return this.team;
-};
-
-Player.prototype.SetTeam = function(team)
-{
- if (this.teamsLocked)
- return;
-
- this.team = team;
-
- // Set all team members as allies.
- if (this.team != -1)
- {
- let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
- for (let i = 0; i < numPlayers; ++i)
- {
- let cmpPlayer = QueryPlayerIDInterface(i);
- if (this.team != cmpPlayer.GetTeam())
- continue;
-
- this.SetAlly(i);
- cmpPlayer.SetAlly(this.playerID);
- }
- }
-
- Engine.BroadcastMessage(MT_DiplomacyChanged, {
- "player": this.playerID,
- "otherPlayer": null
- });
-};
-
-Player.prototype.SetLockTeams = function(value)
-{
- this.teamsLocked = value;
-};
-
-Player.prototype.GetLockTeams = function()
-{
- return this.teamsLocked;
-};
-
-Player.prototype.GetDiplomacy = function()
-{
- return this.diplomacy.slice();
-};
-
-Player.prototype.SetDiplomacy = function(dipl)
-{
- this.diplomacy = dipl.slice();
-
- Engine.BroadcastMessage(MT_DiplomacyChanged, {
- "player": this.playerID,
- "otherPlayer": null
- });
-};
-
-Player.prototype.SetDiplomacyIndex = function(idx, value)
-{
- let cmpPlayer = QueryPlayerIDInterface(idx);
- if (!cmpPlayer)
- return;
-
- if (!this.IsActive() || !cmpPlayer.IsActive())
- return;
-
- this.diplomacy[idx] = value;
-
- Engine.BroadcastMessage(MT_DiplomacyChanged, {
- "player": this.playerID,
- "otherPlayer": cmpPlayer.GetPlayerID()
- });
-
- // Mutual worsening of relations.
- if (cmpPlayer.diplomacy[this.playerID] > value)
- cmpPlayer.SetDiplomacyIndex(this.playerID, value);
-};
-
-Player.prototype.UpdateSharedLos = function()
-{
- let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
- let cmpTechnologyManager = Engine.QueryInterface(this.entity, IID_TechnologyManager);
- if (!cmpRangeManager || !cmpTechnologyManager)
- return;
-
- if (!cmpTechnologyManager.IsTechnologyResearched(this.template.SharedLosTech))
- {
- cmpRangeManager.SetSharedLos(this.playerID, [this.playerID]);
- return;
- }
-
- cmpRangeManager.SetSharedLos(this.playerID, this.GetMutualAllies());
-};
-
Player.prototype.GetFormations = function()
{
return this.formations;
@@ -668,16 +553,6 @@ Player.prototype.HasStartingCamera = function()
return this.startCam !== undefined;
};
-Player.prototype.HasSharedLos = function()
-{
- let cmpTechnologyManager = Engine.QueryInterface(this.entity, IID_TechnologyManager);
- return cmpTechnologyManager && cmpTechnologyManager.IsTechnologyResearched(this.template.SharedLosTech);
-};
-Player.prototype.HasSharedDropsites = function()
-{
- return this.sharedDropsites;
-};
-
Player.prototype.SetControlAllUnits = function(c)
{
this.controlAllUnits = c;
@@ -698,94 +573,6 @@ Player.prototype.IsAI = function()
return this.isAI;
};
-Player.prototype.GetPlayersByDiplomacy = function(func)
-{
- let players = [];
- for (let i = 0; i < this.diplomacy.length; ++i)
- if (this[func](i))
- players.push(i);
- return players;
-};
-
-Player.prototype.SetAlly = function(id)
-{
- this.SetDiplomacyIndex(id, 1);
-};
-
-/**
- * Check if given player is our ally.
- */
-Player.prototype.IsAlly = function(id)
-{
- return this.diplomacy[id] > 0;
-};
-
-Player.prototype.GetAllies = function()
-{
- return this.GetPlayersByDiplomacy("IsAlly");
-};
-
-/**
- * Check if given player is our ally excluding ourself
- */
-Player.prototype.IsExclusiveAlly = function(id)
-{
- return this.playerID != id && this.IsAlly(id);
-};
-
-/**
- * Check if given player is our ally, and we are its ally
- */
-Player.prototype.IsMutualAlly = function(id)
-{
- let cmpPlayer = QueryPlayerIDInterface(id);
- return this.IsAlly(id) && cmpPlayer && cmpPlayer.IsAlly(this.playerID);
-};
-
-Player.prototype.GetMutualAllies = function()
-{
- return this.GetPlayersByDiplomacy("IsMutualAlly");
-};
-
-/**
- * Check if given player is our ally, and we are its ally, excluding ourself
- */
-Player.prototype.IsExclusiveMutualAlly = function(id)
-{
- return this.playerID != id && this.IsMutualAlly(id);
-};
-
-Player.prototype.SetEnemy = function(id)
-{
- this.SetDiplomacyIndex(id, -1);
-};
-
-/**
- * Check if given player is our enemy
- */
-Player.prototype.IsEnemy = function(id)
-{
- return this.diplomacy[id] < 0;
-};
-
-Player.prototype.GetEnemies = function()
-{
- return this.GetPlayersByDiplomacy("IsEnemy");
-};
-
-Player.prototype.SetNeutral = function(id)
-{
- this.SetDiplomacyIndex(id, 0);
-};
-
-/**
- * Check if given player is neutral
- */
-Player.prototype.IsNeutral = function(id)
-{
- return this.diplomacy[id] == 0;
-};
-
/**
* Do some map dependant initializations
*/
@@ -841,19 +628,6 @@ Player.prototype.OnGlobalOwnershipChanged = function(msg)
}
};
-Player.prototype.OnResearchFinished = function(msg)
-{
- if (msg.tech == this.template.SharedLosTech)
- this.UpdateSharedLos();
- else if (msg.tech == this.template.SharedDropsitesTech)
- this.sharedDropsites = true;
-};
-
-Player.prototype.OnDiplomacyChanged = function()
-{
- this.UpdateSharedLos();
-};
-
Player.prototype.OnValueModification = function(msg)
{
if (msg.component != "Player")
@@ -983,7 +757,7 @@ Player.prototype.OnGlobalPlayerDefeated = function(msg)
if (!cmpSound)
return;
- const soundGroup = cmpSound.GetSoundGroup(this.playerID === msg.playerId ? "defeated" : this.IsAlly(msg.playerId) ? "defeated_ally" : this.HasWon() ? "won" : "defeated_enemy");
+ const soundGroup = cmpSound.GetSoundGroup(this.playerID === msg.playerId ? "defeated" : Engine.QueryInterface(this.entity, IID_Diplomacy).IsAlly(msg.playerId) ? "defeated_ally" : this.HasWon() ? "won" : "defeated_enemy");
if (soundGroup)
Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager).PlaySoundGroupForPlayer(soundGroup, this.playerID);
};
diff --git a/binaries/data/mods/public/simulation/components/PlayerManager.js b/binaries/data/mods/public/simulation/components/PlayerManager.js
index 40d933dd20..adb1a21941 100644
--- a/binaries/data/mods/public/simulation/components/PlayerManager.js
+++ b/binaries/data/mods/public/simulation/components/PlayerManager.js
@@ -17,18 +17,17 @@ PlayerManager.prototype.AddPlayer = function(templateName)
{
const ent = Engine.AddEntity(templateName);
const id = this.playerEntities.length;
- const cmpPlayer = Engine.QueryInterface(ent, IID_Player);
- cmpPlayer.SetPlayerID(id);
+ Engine.QueryInterface(ent, IID_Player).SetPlayerID(id);
this.playerEntities.push(ent);
const newDiplo = [];
for (let i = 0; i < id; i++)
{
- Engine.QueryInterface(this.GetPlayerByID(i), IID_Player).diplomacy[id] = -1;
+ Engine.QueryInterface(this.GetPlayerByID(i), IID_Diplomacy).diplomacy[id] = -1;
newDiplo[i] = -1;
}
newDiplo[id] = 1;
- cmpPlayer.SetDiplomacy(newDiplo);
+ Engine.QueryInterface(ent, IID_Diplomacy).SetDiplomacy(newDiplo);
Engine.BroadcastMessage(MT_PlayerEntityChanged, {
"player": id,
@@ -61,7 +60,7 @@ PlayerManager.prototype.ReplacePlayerTemplate = function(id, newTemplateName)
this.playerEntities[id] = ent;
newCmpPlayer.SetColor(oldCmpPlayer.GetColor());
- newCmpPlayer.SetDiplomacy(oldCmpPlayer.GetDiplomacy());
+ Engine.QueryInterface(ent, IID_Diplomacy).SetDiplomacy(Engine.QueryInterface(oldent, IID_Diplomacy).GetDiplomacy());
Engine.BroadcastMessage(MT_PlayerEntityChanged, {
"player": id,
diff --git a/binaries/data/mods/public/simulation/components/ResourceGatherer.js b/binaries/data/mods/public/simulation/components/ResourceGatherer.js
index 7b292509d3..48d93e1056 100644
--- a/binaries/data/mods/public/simulation/components/ResourceGatherer.js
+++ b/binaries/data/mods/public/simulation/components/ResourceGatherer.js
@@ -373,12 +373,17 @@ ResourceGatherer.prototype.CanReturnResource = function(target, checkCarriedReso
return false;
}
- let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
- if (cmpOwnership && IsOwnedByPlayer(cmpOwnership.GetOwner(), target))
+ const cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+ if (!cmpOwnership)
+ return false;
+
+ const playerID = cmpOwnership.GetOwner();
+ if (IsOwnedByPlayer(playerID, target))
return true;
- let cmpPlayer = QueryOwnerInterface(this.entity);
- return cmpPlayer && cmpPlayer.HasSharedDropsites() && cmpResourceDropsite.IsShared() &&
- cmpOwnership && IsOwnedByMutualAllyOfPlayer(cmpOwnership.GetOwner(), target);
+
+ return QueryPlayerIDInterface(playerID, IID_Diplomacy)?.HasSharedDropsites() &&
+ cmpResourceDropsite.IsShared() &&
+ IsOwnedByMutualAllyOfPlayer(playerID, target);
};
/**
diff --git a/binaries/data/mods/public/simulation/components/StatisticsTracker.js b/binaries/data/mods/public/simulation/components/StatisticsTracker.js
index 05ad960e13..c04a36818e 100644
--- a/binaries/data/mods/public/simulation/components/StatisticsTracker.js
+++ b/binaries/data/mods/public/simulation/components/StatisticsTracker.js
@@ -416,25 +416,27 @@ StatisticsTracker.prototype.GetPercentMapExplored = function()
*/
StatisticsTracker.prototype.GetTeamPercentMapExplored = function()
{
- let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
- if (!cmpPlayer)
+ const cmpDiplomacy = Engine.QueryInterface(this.entity, IID_Diplomacy);
+ if (!cmpDiplomacy)
return 0;
- let team = cmpPlayer.GetTeam();
- let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ const team = cmpDiplomacy.GetTeam();
+ const cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
// If teams are not locked, this statistic won't be displayed, so don't bother computing
- if (team == -1 || !cmpPlayer.GetLockTeams())
- return cmpRangeManager.GetPercentMapExplored(cmpPlayer.GetPlayerID());
-
- let teamPlayers = [];
- let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
- for (let i = 1; i < numPlayers; ++i)
+ if (team == -1 || !cmpDiplomacy.IsTeamLocked())
{
- let cmpOtherPlayer = QueryPlayerIDInterface(i);
- if (cmpOtherPlayer && cmpOtherPlayer.GetTeam() == team)
- teamPlayers.push(i);
+ const cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
+ if (!cmpPlayer)
+ return 0;
+ return cmpRangeManager.GetPercentMapExplored(cmpPlayer.GetPlayerID());
}
+ const teamPlayers = [];
+ const numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
+ for (let i = 1; i < numPlayers; ++i)
+ if (QueryPlayerIDInterface(i, IID_Diplomacy)?.GetTeam() === team)
+ teamPlayers.push(i);
+
return cmpRangeManager.GetUnionPercentMapExplored(teamPlayers);
};
@@ -449,23 +451,25 @@ StatisticsTracker.prototype.GetPercentMapControlled = function()
StatisticsTracker.prototype.GetTeamPercentMapControlled = function()
{
- let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
- if (!cmpPlayer)
+ const cmpDiplomacy = Engine.QueryInterface(this.entity, IID_Diplomacy);
+ if (!cmpDiplomacy)
return 0;
- let team = cmpPlayer.GetTeam();
- let cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
- if (team == -1 || !cmpPlayer.GetLockTeams())
+ const team = cmpDiplomacy.GetTeam();
+ const cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
+ if (team === -1 || !cmpDiplomacy.IsTeamLocked())
+ {
+ let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
+ if (!cmpPlayer)
+ return 0;
return cmpTerritoryManager.GetTerritoryPercentage(cmpPlayer.GetPlayerID());
+ }
let teamPercent = 0;
- let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
+ const numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
for (let i = 1; i < numPlayers; ++i)
- {
- let cmpOtherPlayer = QueryPlayerIDInterface(i);
- if (cmpOtherPlayer && cmpOtherPlayer.GetTeam() == team)
+ if (QueryPlayerIDInterface(i, IID_Diplomacy)?.GetTeam() === team)
teamPercent += cmpTerritoryManager.GetTerritoryPercentage(i);
- }
return teamPercent;
};
diff --git a/binaries/data/mods/public/simulation/components/TerritoryDecay.js b/binaries/data/mods/public/simulation/components/TerritoryDecay.js
index a0b231dead..f8ff328e48 100644
--- a/binaries/data/mods/public/simulation/components/TerritoryDecay.js
+++ b/binaries/data/mods/public/simulation/components/TerritoryDecay.js
@@ -35,6 +35,11 @@ TerritoryDecay.prototype.IsConnected = function()
if (!cmpPlayer)
return true;// something without ownership can't decay
+ const playerID = cmpPlayer.GetPlayerID();
+ const cmpDiplomacy = QueryPlayerIDInterface(playerID, IID_Diplomacy);
+ if (!cmpDiplomacy)
+ return true;
+
const decayTerritory = ApplyValueModificationsToEntity("TerritoryDecay/Territory", this.template.Territory, this.entity);
var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
@@ -43,11 +48,11 @@ TerritoryDecay.prototype.IsConnected = function()
if (tileOwner == 0)
{
this.connectedNeighbours[0] = 1;
- return cmpPlayer.GetPlayerID() == 0 || decayTerritory.indexOf("neutral") === -1;
+ return playerID == 0 || decayTerritory.indexOf("neutral") === -1;
}
var tileConnected = cmpTerritoryManager.IsConnected(pos.x, pos.y);
- if (tileConnected && !cmpPlayer.IsMutualAlly(tileOwner))
+ if (tileConnected && !cmpDiplomacy.IsMutualAlly(tileOwner))
{
this.connectedNeighbours[tileOwner] = 1;
return decayTerritory.indexOf("enemy") === -1;
@@ -58,7 +63,7 @@ TerritoryDecay.prototype.IsConnected = function()
// Special-case: if the tile is unconnected, non-own territory, decay towards gaia.
// TODO: this is not great, see #4749
- if (cmpPlayer.GetPlayerID() != tileOwner)
+ if (playerID != tileOwner)
{
this.connectedNeighbours[0] = 1;
return false;
@@ -68,7 +73,7 @@ TerritoryDecay.prototype.IsConnected = function()
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
for (var i = 1; i < numPlayers; ++i)
- if (this.connectedNeighbours[i] > 0 && cmpPlayer.IsMutualAlly(i))
+ if (this.connectedNeighbours[i] > 0 && cmpDiplomacy.IsMutualAlly(i))
{
// don't decay if connected to a connected ally; disable blinking
cmpTerritoryManager.SetTerritoryBlinking(pos.x, pos.y, false);
diff --git a/binaries/data/mods/public/simulation/components/Trader.js b/binaries/data/mods/public/simulation/components/Trader.js
index e81b2828b6..1c86697692 100644
--- a/binaries/data/mods/public/simulation/components/Trader.js
+++ b/binaries/data/mods/public/simulation/components/Trader.js
@@ -181,10 +181,10 @@ Trader.prototype.CanTrade = function(target)
!(cmpTraderIdentity.HasClass("Ship") && cmpTargetMarket.HasType("naval")))
return false;
- let cmpTraderPlayer = QueryOwnerInterface(this.entity, IID_Player);
+ let cmpTraderDiplomacy = QueryOwnerInterface(this.entity, IID_Diplomacy);
let cmpTargetPlayer = QueryOwnerInterface(target, IID_Player);
- return cmpTraderPlayer && cmpTargetPlayer && !cmpTraderPlayer.IsEnemy(cmpTargetPlayer.GetPlayerID());
+ return cmpTraderPlayer && cmpTargetPlayer && !cmpTraderDiplomacy.IsEnemy(cmpTargetPlayer.GetPlayerID());
};
Trader.prototype.AddResources = function(ent, gain)
diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js
index 0db693469d..d87dbfdc53 100644
--- a/binaries/data/mods/public/simulation/components/UnitAI.js
+++ b/binaries/data/mods/public/simulation/components/UnitAI.js
@@ -3764,12 +3764,11 @@ UnitAI.prototype.SetupLOSRangeQuery = function(enable = true)
this.losRangeQuery = undefined;
}
- let cmpPlayer = QueryOwnerInterface(this.entity);
- // If we are being destructed (owner == -1), creating a range query is pointless.
- if (!cmpPlayer)
+ const cmpDiplomacy = QueryOwnerInterface(this.entity, IID_Diplomacy);
+ if (!cmpDiplomacy)
return;
- let players = cmpPlayer.GetEnemies();
+ const players = cmpDiplomacy.GetEnemies();
if (!players.length)
return;
@@ -3798,13 +3797,12 @@ UnitAI.prototype.SetupHealRangeQuery = function(enable = true)
this.losHealRangeQuery = undefined;
}
- let cmpPlayer = QueryOwnerInterface(this.entity);
- // If we are being destructed (owner == -1), creating a range query is pointless.
- if (!cmpPlayer)
+ const cmpDiplomacy = QueryOwnerInterface(this.entity, IID_Diplomacy);
+ if (!cmpDiplomacy)
return;
- let players = cmpPlayer.GetAllies();
- let range = this.GetQueryRange(IID_Heal);
+ const players = cmpDiplomacy.GetAllies();
+ const range = this.GetQueryRange(IID_Heal);
// Do not compensate for entity sizes: LOS doesn't, and UnitAI relies on that.
this.losHealRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity,
@@ -3830,13 +3828,12 @@ UnitAI.prototype.SetupAttackRangeQuery = function(enable = true)
this.losAttackRangeQuery = undefined;
}
- let cmpPlayer = QueryOwnerInterface(this.entity);
- // If we are being destructed (owner == -1), creating a range query is pointless.
- if (!cmpPlayer)
+ const cmpDiplomacy = QueryOwnerInterface(this.entity, IID_Diplomacy);
+ if (!cmpDiplomacy)
return;
// TODO: How to handle neutral players - Special query to attack military only?
- let players = cmpPlayer.GetEnemies();
+ const players = cmpDiplomacy.GetEnemies();
if (!players.length)
return;
@@ -4470,8 +4467,8 @@ UnitAI.prototype.FindNearestDropsite = function(genericType)
let maxDifference = 40;
let owner = cmpOwnership.GetOwner();
- let cmpPlayer = QueryOwnerInterface(this.entity);
- let players = cmpPlayer && cmpPlayer.HasSharedDropsites() ? cmpPlayer.GetMutualAllies() : [owner];
+ let cmpDiplomacy = QueryOwnerInterface(this.entity, IID_Diplomacy);
+ let players = cmpDiplomacy && cmpDiplomacy.HasSharedDropsites() ? cmpDiplomacy.GetMutualAllies() : [owner];
let nearestDropsites = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).ExecuteQuery(this.entity, 0, -1, players, IID_ResourceDropsite, false);
let isShip = Engine.QueryInterface(this.entity, IID_Identity).HasClass("Ship");
diff --git a/binaries/data/mods/public/simulation/components/interfaces/Diplomacy.js b/binaries/data/mods/public/simulation/components/interfaces/Diplomacy.js
new file mode 100644
index 0000000000..21ca54de86
--- /dev/null
+++ b/binaries/data/mods/public/simulation/components/interfaces/Diplomacy.js
@@ -0,0 +1,7 @@
+Engine.RegisterInterface("Diplomacy");
+
+/**
+ * Message of the form { "player": number, "otherPlayer": number }
+ * sent from Diplomacy component when diplomacy changed for one player or between two players.
+ */
+Engine.RegisterMessageType("DiplomacyChanged");
diff --git a/binaries/data/mods/public/simulation/components/interfaces/Player.js b/binaries/data/mods/public/simulation/components/interfaces/Player.js
index 574949ab77..2ca8ae9086 100644
--- a/binaries/data/mods/public/simulation/components/interfaces/Player.js
+++ b/binaries/data/mods/public/simulation/components/interfaces/Player.js
@@ -1,9 +1,3 @@
-/**
- * Message of the form { "player": number, "otherPlayer": number }
- * sent from Player component when diplomacy changed for one player or between two players.
- */
-Engine.RegisterMessageType("DiplomacyChanged");
-
/**
* Message of the form {}
* sent from Player component.
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Attack.js b/binaries/data/mods/public/simulation/components/tests/test_Attack.js
index dcfd66a351..7c1111d4e3 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Attack.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Attack.js
@@ -26,6 +26,7 @@ Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/Auras.js");
Engine.LoadComponentScript("interfaces/Capturable.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("interfaces/Formation.js");
Engine.LoadComponentScript("interfaces/Health.js");
@@ -45,6 +46,9 @@ function attackComponentTest(defenderClass, isEnemy, test_function)
AddMock(playerEnt1, IID_Player, {
"GetPlayerID": () => 1,
+ });
+
+ AddMock(playerEnt1, IID_Diplomacy, {
"IsEnemy": () => isEnemy
});
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Auras.js b/binaries/data/mods/public/simulation/components/tests/test_Auras.js
index 9321e02100..f341ddb508 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Auras.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Auras.js
@@ -1,6 +1,7 @@
Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/Auras.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/RangeOverlayManager.js");
Engine.LoadComponentScript("interfaces/TechnologyManager.js");
Engine.LoadComponentScript("interfaces/ModifiersManager.js");
@@ -52,19 +53,25 @@ function testAuras(name, test_function)
});
AddMock(playerEnt[1], IID_Player, {
- "IsAlly": id => id == playerID[1] || id == playerID[2],
- "IsEnemy": id => id != playerID[1] || id != playerID[2],
"GetPlayerID": () => playerID[1],
"IsDefeated": () => playerDefeated[1]
});
- AddMock(playerEnt[2], IID_Player, {
+ AddMock(playerEnt[1], IID_Diplomacy, {
"IsAlly": id => id == playerID[1] || id == playerID[2],
"IsEnemy": id => id != playerID[1] || id != playerID[2],
+ });
+
+ AddMock(playerEnt[2], IID_Player, {
"GetPlayerID": () => playerID[2],
"IsDefeated": () => playerDefeated[2]
});
+ AddMock(playerEnt[2], IID_Diplomacy, {
+ "IsAlly": id => id == playerID[1] || id == playerID[2],
+ "IsEnemy": id => id != playerID[1] || id != playerID[2],
+ });
+
AddMock(targetEnt, IID_Identity, {
"GetClassesList": () => ["CorrectClass", "OtherClass"]
});
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Builder.js b/binaries/data/mods/public/simulation/components/tests/test_Builder.js
index f9033c5c13..b6d77f0f54 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Builder.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Builder.js
@@ -1,6 +1,7 @@
Engine.LoadHelperScript("Player.js");
Engine.LoadComponentScript("interfaces/Builder.js");
Engine.LoadComponentScript("interfaces/Cost.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/Foundation.js");
Engine.LoadComponentScript("interfaces/Health.js");
Engine.LoadComponentScript("interfaces/Repairable.js");
@@ -110,7 +111,7 @@ function testBuildingFoundation()
"Entities": { "_string": "" }
});
- AddMock(playerEntityID, IID_Player, {
+ AddMock(playerEntityID, IID_Diplomacy, {
"IsAlly": (p) => p == playerId
});
@@ -140,7 +141,7 @@ testBuildingFoundation();
function testRepairing()
{
- AddMock(playerEntityID, IID_Player, {
+ AddMock(playerEntityID, IID_Diplomacy, {
"IsAlly": (p) => p == playerId
});
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Capturable.js b/binaries/data/mods/public/simulation/components/tests/test_Capturable.js
index 2912879141..105f800e59 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Capturable.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Capturable.js
@@ -2,6 +2,7 @@ Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/Auras.js");
Engine.LoadComponentScript("interfaces/Capturable.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
Engine.LoadComponentScript("interfaces/ModifiersManager.js");
@@ -48,19 +49,19 @@ function testCapturable(testData, test_function)
"Activate": () => {}
});
- AddMock(10, IID_Player, {
+ AddMock(10, IID_Diplomacy, {
"IsEnemy": id => id != 0
});
- AddMock(11, IID_Player, {
+ AddMock(11, IID_Diplomacy, {
"IsEnemy": id => id != 1 && id != 2
});
- AddMock(12, IID_Player, {
+ AddMock(12, IID_Diplomacy, {
"IsEnemy": id => id != 1 && id != 2
});
- AddMock(13, IID_Player, {
+ AddMock(13, IID_Diplomacy, {
"IsEnemy": id => id != 3
});
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Damage.js b/binaries/data/mods/public/simulation/components/tests/test_Damage.js
index 815c0977ff..ebaa28043e 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Damage.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Damage.js
@@ -16,6 +16,7 @@ Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("Position.js");
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/DelayedDamage.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/Health.js");
Engine.LoadComponentScript("interfaces/Loot.js");
Engine.LoadComponentScript("interfaces/Promotion.js");
@@ -77,7 +78,7 @@ function Test_Generic()
"direction": new Vector3D(1, 0, 0)
};
- AddMock(atkPlayerEntity, IID_Player, {
+ AddMock(atkPlayerEntity, IID_Diplomacy, {
"GetEnemies": () => [targetOwner]
});
@@ -161,7 +162,7 @@ function Test_Generic()
TestDamage();
atkPlayerEntity = 1;
- AddMock(atkPlayerEntity, IID_Player, {
+ AddMock(atkPlayerEntity, IID_Diplomacy, {
"GetEnemies": () => [2, 3]
});
TS_ASSERT_UNEVAL_EQUALS(AttackHelper.GetPlayersToDamage(atkPlayerEntity, true), [0, 1, 2, 3, 4]);
@@ -199,7 +200,7 @@ function TestLinearSplashDamage()
let hitEnts = new Set();
- AddMock(attackerOwner, IID_Player, {
+ AddMock(attackerOwner, IID_Diplomacy, {
"GetEnemies": () => [2]
});
@@ -295,7 +296,7 @@ function TestCircularSplashDamage()
return 1 - r * r / (radius * radius);
};
- AddMock(attackerOwner, IID_Player, {
+ AddMock(attackerOwner, IID_Diplomacy, {
"GetEnemies": () => [2]
});
@@ -474,7 +475,7 @@ function Test_MissileHit()
"IsInWorld": () => true,
});
- AddMock(10, IID_Player, {
+ AddMock(10, IID_Diplomacy, {
"GetEnemies": () => [2]
});
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Diplomacy.js b/binaries/data/mods/public/simulation/components/tests/test_Diplomacy.js
new file mode 100644
index 0000000000..d331083350
--- /dev/null
+++ b/binaries/data/mods/public/simulation/components/tests/test_Diplomacy.js
@@ -0,0 +1,79 @@
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
+Engine.LoadComponentScript("interfaces/PlayerManager.js");
+Engine.LoadComponentScript("Diplomacy.js");
+Engine.LoadHelperScript("Player.js");
+
+const players = [10, 11];
+
+ConstructComponent(players[0], "Diplomacy", null)
+const cmpDiplomacy = ConstructComponent(players[1], "Diplomacy", {})
+TS_ASSERT_EQUALS(cmpDiplomacy.GetTeam(), -1);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetAllies(), []);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetEnemies(), []);
+
+AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
+ "GetNumPlayers": () => players.length,
+ "GetPlayerByID": (i) => players[i]
+});
+
+for (const player in players)
+ AddMock(players[player], IID_Player, {
+ "GetPlayerID": () => player,
+ "IsActive": () => true,
+ });
+
+cmpDiplomacy.ChangeTeam(1);
+TS_ASSERT_EQUALS(cmpDiplomacy.GetTeam(), 1);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetAllies(), [1]);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetEnemies(), []);
+
+cmpDiplomacy.LockTeam();
+cmpDiplomacy.ChangeTeam(2);
+TS_ASSERT_EQUALS(cmpDiplomacy.GetTeam(), 1);
+
+cmpDiplomacy.UnLockTeam();
+cmpDiplomacy.SetEnemy(0);
+
+TS_ASSERT(!cmpDiplomacy.IsAlly(0));
+TS_ASSERT(!cmpDiplomacy.IsNeutral(0));
+TS_ASSERT(cmpDiplomacy.IsEnemy(0));
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetAllies(), [1]);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetEnemies(), [0]);
+
+cmpDiplomacy.Ally(0);
+
+TS_ASSERT(cmpDiplomacy.IsAlly(0));
+TS_ASSERT(!cmpDiplomacy.IsNeutral(0));
+TS_ASSERT(!cmpDiplomacy.IsEnemy(0));
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetAllies(), [0, 1]);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetEnemies(), []);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetMutualAllies(), [1]);
+
+cmpDiplomacy.SetNeutral(0);
+
+TS_ASSERT(!cmpDiplomacy.IsAlly(0));
+TS_ASSERT(cmpDiplomacy.IsNeutral(0));
+TS_ASSERT(!cmpDiplomacy.IsEnemy(0));
+
+// Mutual worsening of relations.
+cmpDiplomacy.OnDiplomacyChanged({
+ "player": 0,
+ "otherPlayer": 1,
+ "value": -1
+});
+TS_ASSERT(cmpDiplomacy.IsEnemy(0));
+
+
+cmpDiplomacy.SetDiplomacy([-1, 1, 0, 1, -1]);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetAllies(), [1, 3]);
+TS_ASSERT_UNEVAL_EQUALS(cmpDiplomacy.GetEnemies(), [0, 4]);
+
+// Check diplomacy is not editable outside of the component.
+var diplo = cmpDiplomacy.GetDiplomacy();
+diplo[0] = 1;
+TS_ASSERT(cmpDiplomacy.IsEnemy(0));
+
+diplo = [1, 1, 0];
+cmpDiplomacy.SetDiplomacy(diplo);
+diplo[1] = -1;
+TS_ASSERT(cmpDiplomacy.IsAlly(1));
diff --git a/binaries/data/mods/public/simulation/components/tests/test_GarrisonHolder.js b/binaries/data/mods/public/simulation/components/tests/test_GarrisonHolder.js
index b2128b1b91..a5062a6305 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_GarrisonHolder.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_GarrisonHolder.js
@@ -1,5 +1,6 @@
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadHelperScript("Player.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/Garrisonable.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/Health.js");
@@ -31,16 +32,14 @@ AddMock(garrisonHolderId, IID_Ownership, {
"GetOwner": () => player
});
-AddMock(player, IID_Player, {
+AddMock(player, IID_Diplomacy, {
"IsAlly": id => id != enemyPlayer,
"IsMutualAlly": id => id != enemyPlayer,
- "GetPlayerID": () => player
});
-AddMock(friendlyPlayer, IID_Player, {
+AddMock(friendlyPlayer, IID_Diplomacy, {
"IsAlly": id => true,
"IsMutualAlly": id => true,
- "GetPlayerID": () => friendlyPlayer
});
AddMock(SYSTEM_ENTITY, IID_Timer, {
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Garrisoning.js b/binaries/data/mods/public/simulation/components/tests/test_Garrisoning.js
index a7efea5c69..c4346b3964 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Garrisoning.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Garrisoning.js
@@ -1,6 +1,7 @@
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("Position.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/Garrisonable.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/Health.js");
@@ -50,16 +51,14 @@ AddMock(holder, IID_Ownership, {
"GetOwner": () => player
});
-AddMock(player, IID_Player, {
+AddMock(player, IID_Diplomacy, {
"IsAlly": id => id != enemyPlayer,
"IsMutualAlly": id => id != enemyPlayer,
- "GetPlayerID": () => player
});
-AddMock(friendlyPlayer, IID_Player, {
+AddMock(friendlyPlayer, IID_Diplomacy, {
"IsAlly": id => true,
"IsMutualAlly": id => true,
- "GetPlayerID": () => friendlyPlayer
});
AddMock(SYSTEM_ENTITY, IID_Timer, {
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Gate.js b/binaries/data/mods/public/simulation/components/tests/test_Gate.js
index 8f6496487a..a3d3064fc4 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Gate.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Gate.js
@@ -1,3 +1,4 @@
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/Gate.js");
Engine.LoadComponentScript("interfaces/UnitAI.js");
Engine.LoadComponentScript("Gate.js");
diff --git a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
index 6c9f38de20..5ebb028fe1 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
@@ -7,6 +7,7 @@ Engine.LoadComponentScript("interfaces/Builder.js");
Engine.LoadComponentScript("interfaces/Capturable.js");
Engine.LoadComponentScript("interfaces/CeasefireManager.js");
Engine.LoadComponentScript("interfaces/DeathDamage.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/EndGameManager.js");
Engine.LoadComponentScript("interfaces/EntityLimits.js");
Engine.LoadComponentScript("interfaces/Formation.js");
@@ -111,20 +112,23 @@ AddMock(100, IID_Player, {
"GetPanelEntities": function() { return []; },
"IsTrainingBlocked": function() { return false; },
"GetState": function() { return "active"; },
- "GetTeam": function() { return -1; },
- "GetLockTeams": function() { return false; },
"GetCheatsEnabled": function() { return false; },
- "GetDiplomacy": function() { return [-1, 1]; },
- "IsAlly": function() { return false; },
- "IsMutualAlly": function() { return false; },
- "IsNeutral": function() { return false; },
- "IsEnemy": function() { return true; },
"GetDisabledTemplates": function() { return {}; },
"GetDisabledTechnologies": function() { return {}; },
"CanBarter": function() { return false; },
- "GetSpyCostMultiplier": function() { return 1; },
- "HasSharedDropsites": function() { return false; },
- "HasSharedLos": function() { return false; }
+ "GetSpyCostMultiplier": function() { return 1; }
+});
+
+AddMock(100, IID_Diplomacy, {
+ "GetTeam": () => -1,
+ "IsTeamLocked": () => false,
+ "GetDiplomacy": () => [-1, 1],
+ "IsAlly": () => false,
+ "IsMutualAlly": () => false,
+ "IsNeutral": () => false,
+ "IsEnemy": () => true,
+ "HasSharedDropsites": () => false,
+ "HasSharedLos": () => false,
});
AddMock(100, IID_Identity, {
@@ -204,20 +208,23 @@ AddMock(101, IID_Player, {
"GetPanelEntities": function() { return []; },
"IsTrainingBlocked": function() { return false; },
"GetState": function() { return "active"; },
- "GetTeam": function() { return -1; },
- "GetLockTeams": function() {return false; },
"GetCheatsEnabled": function() { return false; },
- "GetDiplomacy": function() { return [-1, 1]; },
- "IsAlly": function() { return true; },
- "IsMutualAlly": function() {return false; },
- "IsNeutral": function() { return false; },
- "IsEnemy": function() { return false; },
"GetDisabledTemplates": function() { return {}; },
"GetDisabledTechnologies": function() { return {}; },
"CanBarter": function() { return false; },
"GetSpyCostMultiplier": function() { return 1; },
- "HasSharedDropsites": function() { return false; },
- "HasSharedLos": function() { return false; }
+});
+
+AddMock(101, IID_Diplomacy, {
+ "GetTeam": () => -1,
+ "IsTeamLocked": () => false,
+ "GetDiplomacy": () => [-1, 1],
+ "IsAlly": () => true,
+ "IsMutualAlly": () => false,
+ "IsNeutral": () => false,
+ "IsEnemy": () => false,
+ "HasSharedDropsites": () => false,
+ "HasSharedLos": () => false,
});
AddMock(101, IID_Identity, {
@@ -305,7 +312,7 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
"trainingBlocked": false,
"state": "active",
"team": -1,
- "teamsLocked": false,
+ "teamLocked": false,
"cheatsEnabled": false,
"disabledTemplates": {},
"disabledTechnologies": {},
@@ -356,7 +363,7 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
"trainingBlocked": false,
"state": "active",
"team": -1,
- "teamsLocked": false,
+ "teamLocked": false,
"cheatsEnabled": false,
"disabledTemplates": {},
"disabledTechnologies": {},
@@ -417,7 +424,7 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
"trainingBlocked": false,
"state": "active",
"team": -1,
- "teamsLocked": false,
+ "teamLocked": false,
"cheatsEnabled": false,
"disabledTemplates": {},
"disabledTechnologies": {},
@@ -491,7 +498,7 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
"trainingBlocked": false,
"state": "active",
"team": -1,
- "teamsLocked": false,
+ "teamLocked": false,
"cheatsEnabled": false,
"disabledTemplates": {},
"disabledTechnologies": {},
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Heal.js b/binaries/data/mods/public/simulation/components/tests/test_Heal.js
index 9f856a91cb..e0cace5b2e 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Heal.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Heal.js
@@ -1,5 +1,6 @@
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadHelperScript("Player.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/Formation.js");
Engine.LoadComponentScript("interfaces/Heal.js");
Engine.LoadComponentScript("interfaces/Health.js");
@@ -39,11 +40,11 @@ AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
"GetPlayerByID": () => player
});
-AddMock(player, IID_Player, {
+AddMock(player, IID_Diplomacy, {
"IsAlly": (p) => p == player
});
-AddMock(otherPlayer, IID_Player, {
+AddMock(otherPlayer, IID_Diplomacy, {
"IsAlly": (p) => p == player
});
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Player.js b/binaries/data/mods/public/simulation/components/tests/test_Player.js
index cdb81a09fe..c0908ca289 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Player.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Player.js
@@ -47,19 +47,6 @@ TS_ASSERT_EQUALS(cmpPlayer.GetPlayerID(), playerID);
TS_ASSERT_EQUALS(cmpPlayer.GetPopulationCount(), 0);
TS_ASSERT_EQUALS(cmpPlayer.GetPopulationLimit(), 0);
-cmpPlayer.SetDiplomacy([-1, 1, 0, 1, -1]);
-TS_ASSERT_UNEVAL_EQUALS(cmpPlayer.GetAllies(), [1, 3]);
-TS_ASSERT_UNEVAL_EQUALS(cmpPlayer.GetEnemies(), [0, 4]);
-
-var diplo = cmpPlayer.GetDiplomacy();
-diplo[0] = 1;
-TS_ASSERT(cmpPlayer.IsEnemy(0));
-
-diplo = [1, 1, 0];
-cmpPlayer.SetDiplomacy(diplo);
-diplo[1] = -1;
-TS_ASSERT(cmpPlayer.IsAlly(1));
-
TS_ASSERT_EQUALS(cmpPlayer.GetSpyCostMultiplier(), 1);
TS_ASSERT_UNEVAL_EQUALS(cmpPlayer.GetBarterMultiplier(), {
"buy": {
diff --git a/binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js b/binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js
index b200c93032..9b1668ff98 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js
@@ -1,4 +1,5 @@
Engine.LoadHelperScript("Player.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/TurretHolder.js");
Engine.LoadComponentScript("interfaces/Turretable.js");
Engine.LoadComponentScript("interfaces/UnitAI.js");
@@ -38,16 +39,14 @@ for (let entity of entitiesToTest)
});
}
-AddMock(player, IID_Player, {
+AddMock(player, IID_Diplomacy, {
"IsAlly": id => id != enemyPlayer,
"IsMutualAlly": id => id != enemyPlayer,
- "GetPlayerID": () => player
});
-AddMock(alliedPlayer, IID_Player, {
+AddMock(alliedPlayer, IID_Diplomacy, {
"IsAlly": id => true,
"IsMutualAlly": id => true,
- "GetPlayerID": () => alliedPlayer
});
let cmpTurretHolder = ConstructComponent(turretHolderID, "TurretHolder", {
diff --git a/binaries/data/mods/public/simulation/components/tests/test_Turrets.js b/binaries/data/mods/public/simulation/components/tests/test_Turrets.js
index f4b5d28371..c123884560 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_Turrets.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_Turrets.js
@@ -1,6 +1,7 @@
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("Position.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/Health.js");
Engine.LoadComponentScript("interfaces/Turretable.js");
Engine.LoadComponentScript("interfaces/TurretHolder.js");
@@ -47,16 +48,14 @@ AddMock(holder, IID_Ownership, {
"GetOwner": () => player
});
-AddMock(player, IID_Player, {
+AddMock(player, IID_Diplomacy, {
"IsAlly": id => id != enemyPlayer,
"IsMutualAlly": id => id != enemyPlayer,
- "GetPlayerID": () => player
});
-AddMock(friendlyPlayer, IID_Player, {
+AddMock(friendlyPlayer, IID_Diplomacy, {
"IsAlly": id => true,
"IsMutualAlly": id => true,
- "GetPlayerID": () => friendlyPlayer
});
AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
diff --git a/binaries/data/mods/public/simulation/components/tests/test_UnitAI.js b/binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
index 8f733149df..503f819a54 100644
--- a/binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
+++ b/binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
@@ -5,6 +5,7 @@ Engine.LoadComponentScript("interfaces/Auras.js");
Engine.LoadComponentScript("interfaces/Builder.js");
Engine.LoadComponentScript("interfaces/BuildingAI.js");
Engine.LoadComponentScript("interfaces/Capturable.js");
+Engine.LoadComponentScript("interfaces/Diplomacy.js");
Engine.LoadComponentScript("interfaces/Garrisonable.js");
Engine.LoadComponentScript("interfaces/Resistance.js");
Engine.LoadComponentScript("interfaces/Formation.js");
@@ -144,7 +145,7 @@ function TestFormationExiting(mode)
"GetNumPlayers": function() { return 2; },
});
- AddMock(playerEntity, IID_Player, {
+ AddMock(playerEntity, IID_Diplomacy, {
"IsAlly": function() { return false; },
"IsEnemy": function() { return true; },
"GetEnemies": function() { return [2]; },
@@ -327,7 +328,7 @@ function TestMoveIntoFormationWhileAttacking()
"IsInTargetRange": (ent, target, min, max) => true
});
- AddMock(playerEntity, IID_Player, {
+ AddMock(playerEntity, IID_Diplomacy, {
"IsAlly": function() { return false; },
"IsEnemy": function() { return true; },
"GetEnemies": function() { return [2]; },
diff --git a/binaries/data/mods/public/simulation/helpers/Attack.js b/binaries/data/mods/public/simulation/helpers/Attack.js
index ddf4c584d6..ef958392ca 100644
--- a/binaries/data/mods/public/simulation/helpers/Attack.js
+++ b/binaries/data/mods/public/simulation/helpers/Attack.js
@@ -218,7 +218,7 @@ AttackHelper.prototype.GetTotalAttackEffects = function(target, effectData, effe
AttackHelper.prototype.GetPlayersToDamage = function(attackerOwner, friendlyFire)
{
if (!friendlyFire)
- return QueryPlayerIDInterface(attackerOwner).GetEnemies();
+ return QueryPlayerIDInterface(attackerOwner, IID_Diplomacy).GetEnemies();
return Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers();
};
diff --git a/binaries/data/mods/public/simulation/helpers/Commands.js b/binaries/data/mods/public/simulation/helpers/Commands.js
index 0ec5384157..f714efa40a 100644
--- a/binaries/data/mods/public/simulation/helpers/Commands.js
+++ b/binaries/data/mods/public/simulation/helpers/Commands.js
@@ -88,28 +88,29 @@ var g_Commands = {
"diplomacy": function(player, cmd, data)
{
- let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager);
- if (data.cmpPlayer.GetLockTeams() ||
- cmpCeasefireManager && cmpCeasefireManager.IsCeasefireActive())
+ if (Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive())
+ return;
+
+ const cmpDiplomacy = QueryPlayerIDInterface(player, IID_Diplomacy);
+ if (!cmpDiplomacy || cmpDiplomacy.IsTeamLocked())
return;
switch(cmd.to)
{
case "ally":
- data.cmpPlayer.SetAlly(cmd.player);
+ cmpDiplomacy.Ally(cmd.player);
break;
case "neutral":
- data.cmpPlayer.SetNeutral(cmd.player);
+ cmpDiplomacy.SetNeutral(cmd.player);
break;
case "enemy":
- data.cmpPlayer.SetEnemy(cmd.player);
+ cmpDiplomacy.SetEnemy(cmd.player);
break;
default:
warn("Invalid command: Could not set "+player+" diplomacy status of player "+cmd.player+" to "+cmd.to);
}
- var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
- cmpGuiInterface.PushNotification({
+ Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).PushNotification({
"type": "diplomacy",
"players": [player],
"targetPlayer": cmd.player,
diff --git a/binaries/data/mods/public/simulation/helpers/Player.js b/binaries/data/mods/public/simulation/helpers/Player.js
index 3823e15dd2..cc4b05515c 100644
--- a/binaries/data/mods/public/simulation/helpers/Player.js
+++ b/binaries/data/mods/public/simulation/helpers/Player.js
@@ -107,9 +107,9 @@ function LoadPlayerSettings(settings, newPlayers)
// If diplomacy explicitly defined, use that; otherwise use teams.
const diplomacy = getPlayerSetting(i, "Diplomacy");
if (diplomacy !== undefined)
- cmpPlayer.SetDiplomacy(diplomacy);
+ QueryPlayerIDInterface(i, IID_Diplomacy).SetDiplomacy(diplomacy);
else
- cmpPlayer.SetTeam(getPlayerSetting(i, "Team") ?? -1);
+ QueryPlayerIDInterface(i, IID_Diplomacy).ChangeTeam(getPlayerSetting(i, "Team") ?? -1);
const formations = getPlayerSetting(i, "Formations");
if (formations)
@@ -120,11 +120,11 @@ function LoadPlayerSettings(settings, newPlayers)
cmpPlayer.SetStartingCamera(startCam.Position, startCam.Rotation);
}
- // NOTE: We need to do the team locking here, as otherwise
- // SetTeam can't ally the players.
+ // NOTE: We need to do the team locking here, as
+ // otherwise we can't ally the players above.
if (settings.LockTeams)
for (let i = 0; i < numPlayers; ++i)
- QueryPlayerIDInterface(i).SetLockTeams(true);
+ QueryPlayerIDInterface(i, IID_Diplomacy).LockTeam();
}
function GetPlayerTemplateName(civ)
@@ -232,21 +232,8 @@ function IsOwnedByMutualAllyOfEntity(entity, target)
function IsOwnedByEntityHelper(entity, target, check)
{
- // Figure out which player controls us
- let owner = 0;
- let cmpOwnership = Engine.QueryInterface(entity, IID_Ownership);
- if (cmpOwnership)
- owner = cmpOwnership.GetOwner();
-
- // Figure out which player controls the target entity
- let targetOwner = 0;
- let cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership);
- if (cmpOwnershipTarget)
- targetOwner = cmpOwnershipTarget.GetOwner();
-
- let cmpPlayer = QueryPlayerIDInterface(owner);
-
- return cmpPlayer && cmpPlayer[check](targetOwner);
+ const owner = Engine.QueryInterface(entity, IID_Ownership)?.GetOwner() || 0;
+ return IsOwnedByHelper(owner, target, check);
}
/**
@@ -288,14 +275,9 @@ function IsOwnedByEnemyOfPlayer(player, target)
function IsOwnedByHelper(player, target, check)
{
- let targetOwner = 0;
- let cmpOwnershipTarget = Engine.QueryInterface(target, IID_Ownership);
- if (cmpOwnershipTarget)
- targetOwner = cmpOwnershipTarget.GetOwner();
-
- let cmpPlayer = QueryPlayerIDInterface(player);
-
- return cmpPlayer && cmpPlayer[check](targetOwner);
+ const targetOwner = Engine.QueryInterface(target, IID_Ownership)?.GetOwner() || 0;
+ const cmpDiplomacy = QueryPlayerIDInterface(player, IID_Diplomacy);
+ return cmpDiplomacy && cmpDiplomacy[check](targetOwner);
}
Engine.RegisterGlobal("LoadPlayerSettings", LoadPlayerSettings);
diff --git a/binaries/data/mods/public/simulation/templates/special/players/gaia.xml b/binaries/data/mods/public/simulation/templates/special/players/gaia.xml
index 80bb127fc5..faabe5b493 100644
--- a/binaries/data/mods/public/simulation/templates/special/players/gaia.xml
+++ b/binaries/data/mods/public/simulation/templates/special/players/gaia.xml
@@ -1,5 +1,9 @@
+
+
+
+
gaia
Gaia
@@ -7,8 +11,6 @@
true
-
-
1.0
diff --git a/binaries/data/mods/public/simulation/templates/template_player.xml b/binaries/data/mods/public/simulation/templates/template_player.xml
index 6ff64c095d..9c273e469b 100644
--- a/binaries/data/mods/public/simulation/templates/template_player.xml
+++ b/binaries/data/mods/public/simulation/templates/template_player.xml
@@ -13,6 +13,10 @@
0
8
+
+ unlock_shared_los
+ unlock_shared_dropsites
+
50
@@ -70,8 +74,6 @@
1.0
- unlock_shared_los
- unlock_shared_dropsites
1.0
special/formations/null