Index: binaries/data/mods/public/gui/session/messages.js
===================================================================
--- binaries/data/mods/public/gui/session/messages.js
+++ binaries/data/mods/public/gui/session/messages.js
@@ -328,6 +328,7 @@
"status": notification.status
});
updatePlayerData();
+ setDiplomacyColors();
},
"ceasefire-ended": function(notification, player)
{
Index: binaries/data/mods/public/gui/session/minimap_panel.xml
===================================================================
--- binaries/data/mods/public/gui/session/minimap_panel.xml
+++ binaries/data/mods/public/gui/session/minimap_panel.xml
@@ -19,6 +19,20 @@
if (g_HasIdleWorker) Engine.GetGUIObjectByName("idleOverlay").sprite = "stretched:session/minimap-idle-highlight.png";
+
+
-
+
+
Index: binaries/data/mods/public/gui/session/session.js
===================================================================
--- binaries/data/mods/public/gui/session/session.js
+++ binaries/data/mods/public/gui/session/session.js
@@ -12,6 +12,14 @@
const g_VictoryDurations = prepareForDropdown(g_Settings && g_Settings.VictoryDurations);
/**
+ * Diplomacy colors (ally/neutral/enemy as a player, teams as an observer).
+ */
+var g_PlayerColors;
+var g_DiplomacyColors;
+var g_DiplomacyColorsToggle = false;
+var g_DiplomacyColorsList = Engine.ReadJSONFile("simulation/data/settings/diplomacy_colors.json");
+
+/**
* Colors to flash when pop limit reached.
*/
var g_DefaultPopulationColor = "white";
@@ -280,6 +288,8 @@
g_PlayerAssignments.local.player = -1;
updatePlayerData();
+ g_PlayerColors = g_Players.map(x => x.color);
+ updatePlayerColors();
g_BarterSell = g_ResourceData.GetCodes()[0];
@@ -291,19 +301,12 @@
initPanelEntities(slot);
// Populate player selection dropdown
- let playerNames = [translate("Observer")];
- let playerIDs = [-1];
- for (let player in g_Players)
- {
- playerIDs.push(player);
- playerNames.push(colorizePlayernameHelper("■", player) + " " + g_Players[player].name);
- }
+ updateViewPlayerNames();
+ let viewPlayerDropdown = Engine.GetGUIObjectByName("viewPlayer");
+ viewPlayerDropdown.list_data = Array.from({ length: g_Players.length + 1 }, (v, i) => i - 1);
// Select "observer" item when rejoining as a defeated player
let viewedPlayer = g_Players[Engine.GetPlayerID()];
- let viewPlayerDropdown = Engine.GetGUIObjectByName("viewPlayer");
- viewPlayerDropdown.list = playerNames;
- viewPlayerDropdown.list_data = playerIDs;
viewPlayerDropdown.selected = viewedPlayer && viewedPlayer.state == "defeated" ? 0 : Engine.GetPlayerID() + 1;
// If in Atlas editor, disable the exit button
@@ -330,6 +333,50 @@
// setTimeout(function() { reportPerformance(60); }, 60000);
}
+function setDiplomacyColors()
+{
+ g_DiplomacyColors = [g_Players[0].color];
+ let teamColors = {};
+ for (let i = 1; i < g_Players.length; ++i)
+ if (g_ViewedPlayer <= 0)
+ {
+ // Observers (and gaia) see team colors
+ let team = g_Players[i].team;
+ g_DiplomacyColors.push(g_PlayerColors[teamColors[team] || i]);
+ if (team != -1 && !teamColors[team])
+ teamColors[team] = i;
+ }
+ else
+ g_DiplomacyColors.push(
+ g_ViewedPlayer == i ? g_DiplomacyColorsList.Self :
+ g_Players[g_ViewedPlayer].isAlly[i] ? g_DiplomacyColorsList.Ally :
+ g_Players[g_ViewedPlayer].isNeutral[i] ? g_DiplomacyColorsList.Neutral :
+ g_DiplomacyColorsList.Enemy
+ );
+
+ if (g_DiplomacyColorsToggle)
+ updatePlayerColors();
+}
+
+function updatePlayerColors()
+{
+ let playerColors = g_DiplomacyColorsToggle ? g_DiplomacyColors : g_PlayerColors;
+ for (let i = 1; i < g_Players.length; ++i)
+ g_Players[i].color = playerColors[i];
+
+ Engine.GuiInterfaceCall("UpdatePlayerColors", playerColors);
+ updateViewPlayerNames();
+}
+
+function updateViewPlayerNames()
+{
+ let playerNames = [translate("Observer")];
+ for (let player in g_Players)
+ playerNames.push(colorizePlayernameHelper("■", player) + " " + g_Players[player].name);
+
+ Engine.GetGUIObjectByName("viewPlayer").list = playerNames;
+}
+
function updatePlayerData()
{
let simState = GetSimState();
@@ -488,6 +535,7 @@
}
Engine.SetViewedPlayer(g_ViewedPlayer);
+ setDiplomacyColors();
updateTopPanel();
updateChatAddressees();
updateHotkeyTooltips();
@@ -797,6 +845,7 @@
else if (idleWorkerButton.sprite != prefix + "minimap-idle-highlight.png")
idleWorkerButton.sprite = prefix + "minimap-idle.png";
}
+
function onSimulationUpdate()
{
// Templates change depending on technologies and auras, so they have to be reloaded every turn.
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js
+++ binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -874,6 +874,18 @@
return buildableEnts;
};
+GuiInterface.prototype.UpdatePlayerColors = function(player, data)
+{
+ for (let i = 0; i < data.length; ++i)
+ {
+ let cmpPlayer = QueryPlayerIDInterface(i, IID_Player);
+ if (!cmpPlayer)
+ continue;
+
+ cmpPlayer.SetDiplomacyColor(data[i].r, data[i].g, data[i].b);
+ }
+};
+
GuiInterface.prototype.SetSelectionHighlight = function(player, cmd)
{
let playerColors = {}; // cache of owner -> color map
@@ -2015,6 +2027,7 @@
"GetFoundationSnapData": 1,
"PlaySound": 1,
"FindIdleUnits": 1,
+ "UpdatePlayerColors": 1,
"HasIdleUnits": 1,
"GetTradingRouteGain": 1,
"GetTradingDetails": 1,
Index: binaries/data/mods/public/simulation/components/Player.js
===================================================================
--- binaries/data/mods/public/simulation/components/Player.js
+++ binaries/data/mods/public/simulation/components/Player.js
@@ -22,6 +22,19 @@
"";
/**
+ * Don't serialise diplomacyColor since it's modified by the GUI
+ */
+Player.prototype.Serialize = function()
+{
+ let data = {};
+ for (let key in this)
+ if (this.hasOwnProperty(key) && key != "diplomacyColor")
+ data[key] = this[key];
+
+ return data;
+};
+
+/**
* Which units will be shown with special icons at the top.
*/
var panelEntityClasses = "Hero Relic";
@@ -32,6 +45,7 @@
this.name = undefined; // define defaults elsewhere (supporting other languages)
this.civ = undefined;
this.color = undefined;
+ this.diplomacyColor = undefined;
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
@@ -131,9 +145,18 @@
});
};
+Player.prototype.SetDiplomacyColor = function(r, g, b)
+{
+ this.diplomacyColor = { "r": r/255, "g": g/255, "b": b/255, "a": 1 };
+
+ Engine.BroadcastMessage(MT_PlayerColorChanged, {
+ "player": this.playerID
+ });
+};
+
Player.prototype.GetColor = function()
{
- return this.color;
+ return this.diplomacyColor || this.color;
};
// Try reserving num population slots. Returns 0 on success or number of missing slots otherwise.
Index: binaries/data/mods/public/simulation/components/StatusBars.js
===================================================================
--- binaries/data/mods/public/simulation/components/StatusBars.js
+++ binaries/data/mods/public/simulation/components/StatusBars.js
@@ -100,6 +100,12 @@
this.RegenerateSprites();
};
+StatusBars.prototype.OnPlayerColorChanged = function(msg)
+{
+ if (this.enabled)
+ this.RegenerateSprites();
+};
+
StatusBars.prototype.RegenerateSprites = function()
{
let cmpOverlayRenderer = Engine.QueryInterface(this.entity, IID_OverlayRenderer);
Index: binaries/data/mods/public/simulation/data/settings/diplomacy_colors.json
===================================================================
--- binaries/data/mods/public/simulation/data/settings/diplomacy_colors.json
+++ binaries/data/mods/public/simulation/data/settings/diplomacy_colors.json
@@ -0,0 +1,6 @@
+{
+ "Self": { "r": 0, "g": 0, "b": 255 },
+ "Ally": { "r": 0, "g": 255, "b": 0 },
+ "Neutral": { "r": 255, "g": 255, "b": 0 },
+ "Enemy": { "r": 255, "g": 0, "b": 0 }
+}
Index: source/simulation2/components/CCmpMinimap.cpp
===================================================================
--- source/simulation2/components/CCmpMinimap.cpp
+++ source/simulation2/components/CCmpMinimap.cpp
@@ -32,6 +32,7 @@
public:
static void ClassInit(CComponentManager& componentManager)
{
+ componentManager.SubscribeToMessageType(MT_PlayerColorChanged);
componentManager.SubscribeToMessageType(MT_PositionChanged);
componentManager.SubscribeToMessageType(MT_OwnershipChanged);
componentManager.SubscribeToMessageType(MT_MinimapPing);
@@ -117,13 +118,6 @@
template
void SerializeCommon(S& serialize)
{
- if (m_UsePlayerColor)
- {
- serialize.NumberU8_Unbounded("r", m_R);
- serialize.NumberU8_Unbounded("g", m_G);
- serialize.NumberU8_Unbounded("b", m_B);
- }
-
serialize.Bool("active", m_Active);
if (m_Active)
@@ -177,18 +171,23 @@
if (msgData.to == INVALID_PLAYER)
break;
- // Find the new player's color
- CmpPtr cmpPlayerManager(GetSystemEntity());
- if (!cmpPlayerManager)
+ UpdatePlayerColor(msgData.to);
+
+ break;
+ }
+ case MT_PlayerColorChanged:
+ {
+ if (!m_UsePlayerColor)
break;
- CmpPtr cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(msgData.to));
- if (!cmpPlayer)
+
+ const CMessagePlayerColorChanged& msgData = static_cast (msg);
+
+ CmpPtr cmpOwnership(GetEntityHandle());
+
+ if (!cmpOwnership || msgData.player != cmpOwnership->GetOwner())
break;
- CColor color = cmpPlayer->GetColor();
- m_R = (u8)(color.r*255.0);
- m_G = (u8)(color.g*255.0);
- m_B = (u8)(color.b*255.0);
- // TODO: probably should avoid using floating-point here
+
+ UpdatePlayerColor(msgData.player);
break;
}
@@ -236,6 +235,22 @@
return m_IsPinging;
}
+
+ void UpdatePlayerColor(player_id_t player)
+ {
+ CmpPtr cmpPlayerManager(GetSystemEntity());
+ if (!cmpPlayerManager)
+ return;
+
+ CmpPtr cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(player));
+ if (!cmpPlayer)
+ return;
+
+ CColor color = cmpPlayer->GetColor();
+ m_R = (u8) (color.r * 255);
+ m_G = (u8) (color.g * 255);
+ m_B = (u8) (color.b * 255);
+ }
};
REGISTER_COMPONENT_TYPE(Minimap)
Index: source/simulation2/components/CCmpTerritoryManager.cpp
===================================================================
--- source/simulation2/components/CCmpTerritoryManager.cpp
+++ source/simulation2/components/CCmpTerritoryManager.cpp
@@ -177,7 +177,10 @@
}
case MT_PlayerColorChanged:
{
- MakeDirty();
+ // Color change is not a trigger event
+ SAFE_DELETE(m_Territories);
+ ++m_DirtyID;
+ m_BoundaryLinesDirty = true;
break;
}
case MT_PositionChanged: