Index: binaries/data/mods/public/gui/gamesetup/gamesetup.js =================================================================== --- binaries/data/mods/public/gui/gamesetup/gamesetup.js +++ binaries/data/mods/public/gui/gamesetup/gamesetup.js @@ -1047,7 +1047,7 @@ }, }, "playerColor": { - "sprite": (playerIdx) => "color:" + rgbToGuiColor(g_GameAttributes.settings.PlayerData[playerIdx].Color) + " 100", + "sprite": (playerIdx) => "color:" + rgbToGuiColor(g_GameAttributes.settings.PlayerData[playerIdx].Color, 100), }, "playerConfig": { "hidden": (playerIdx) => !g_GameAttributes.settings.PlayerData[playerIdx].AI, Index: binaries/data/mods/public/gui/session/menu.js =================================================================== --- binaries/data/mods/public/gui/session/menu.js +++ binaries/data/mods/public/gui/session/menu.js @@ -433,7 +433,7 @@ row.size = size; row.hidden = false; - row.sprite = "color: " + rgbToGuiColor(g_Players[i].color) + " 32"; + row.sprite = "color:" + rgbToGuiColor(g_DisplayedPlayerColors[i], 32); setOutcomeIcon(g_Players[i].state, "diplomacyPlayerOutcome[" + (i - 1) + "]"); 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 @@ -331,17 +331,22 @@ }, "diplomacy": function(notification, player) { + updatePlayerData(); + if (g_DiplomacyColorsToggle) + updateDisplayedPlayerColors(); + addChatMessage({ "type": "diplomacy", "sourcePlayer": player, "targetPlayer": notification.targetPlayer, "status": notification.status }); - updatePlayerData(); }, "ceasefire-ended": function(notification, player) { updatePlayerData(); + if (g_DiplomacyColorsToggle) + updateDisplayedPlayerColors(); }, "tutorial": function(notification, player) { @@ -965,7 +970,7 @@ function colorizePlayernameHelper(username, playerID) { - let playerColor = playerID > -1 ? rgbToGuiColor(g_Players[playerID].color) : "white"; + let playerColor = playerID > -1 ? rgbToGuiColor(g_DisplayedPlayerColors[playerID]) : "white"; return coloredText(username || translate("Unknown Player"), playerColor); } 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 @@ -21,11 +21,25 @@ name="idleWorkerButton" type="button" size="100%-120 100%-120 100%-5 100%-5" - tooltip_style="sessionToolTip" hotkey="selection.idleworker" + tooltip_style="sessionToolTip" + hotkey="selection.idleworker" sprite="stretched:session/minimap-idle.png" sprite_over="stretched:session/minimap-idle-highlight.png" sprite_disabled="stretched:session/minimap-idle-disabled.png" > findIdleUnit(g_WorkerTypes); + + + + Toggle Diplomacy Colors + updateDiplomacyColorsButton() + Index: binaries/data/mods/public/gui/session/selection_details.js =================================================================== --- binaries/data/mods/public/gui/session/selection_details.js +++ binaries/data/mods/public/gui/session/selection_details.js @@ -72,7 +72,7 @@ let civEmblem = g_CivData[playerState.civ].Emblem; let playerName = playerState.name; - let playerColor = playerState.color.r + " " + playerState.color.g + " " + playerState.color.b + " 128"; + let playerColor = rgbToGuiColor(g_DisplayedPlayerColors[entState.player], 128); // Indicate disconnected players by prefixing their name if (g_Players[entState.player].offline) @@ -138,7 +138,7 @@ let size = 100 * Math.max(0, Math.min(1, entState.capturePoints[playerID] / entState.maxCapturePoints)); sizeObj.rright = startSize + size; unitCaptureBar.size = sizeObj; - unitCaptureBar.sprite = "color: " + rgbToGuiColor(g_Players[playerID].color, 128); + unitCaptureBar.sprite = "color:" + rgbToGuiColor(g_DisplayedPlayerColors[playerID], 128); unitCaptureBar.hidden = false; return startSize + size; }; @@ -271,7 +271,7 @@ Engine.GetGUIObjectByName("specific").caption = specificName; Engine.GetGUIObjectByName("player").caption = playerName; - Engine.GetGUIObjectByName("playerColorBackground").sprite = "color: " + playerColor; + Engine.GetGUIObjectByName("playerColorBackground").sprite = "color:" + playerColor; Engine.GetGUIObjectByName("generic").caption = genericName == specificName ? "" : sprintf(translate("(%(genericName)s)"), { "genericName": genericName @@ -382,7 +382,7 @@ let size = 100 * Math.max(0, Math.min(1, capturePoints[pID] / maxCapturePoints)); sizeObj.rbottom = startSize + size; unitCaptureBar.size = sizeObj; - unitCaptureBar.sprite = "color: " + rgbToGuiColor(g_Players[pID].color, 128); + unitCaptureBar.sprite = "color:" + rgbToGuiColor(g_DisplayedPlayerColors[pID], 128); unitCaptureBar.hidden = false; return startSize + size; }; Index: binaries/data/mods/public/gui/session/selection_panels_helpers.js =================================================================== --- binaries/data/mods/public/gui/session/selection_panels_helpers.js +++ binaries/data/mods/public/gui/session/selection_panels_helpers.js @@ -33,7 +33,7 @@ function getPlayerHighlightColor(player) { - return "color:" + rgbToGuiColor(g_Players[player].color) + " 160"; + return "color:" + rgbToGuiColor(g_DisplayedPlayerColors[player], 160); } /** 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,22 @@ var g_GameSpeeds; /** + * Whether to display diplomacy colors (where players see self/ally/neutral/enemy each in different colors and + * observers see each team in a different color) or regular player colors. + */ +var g_DiplomacyColorsToggle = false; + +/** + * The array of displayed player colors (either the diplomacy color or regular color for each player). + */ +var g_DisplayedPlayerColors; + +/** + * The self/ally/neutral/enemy color codes. + */ +var g_DiplomacyColorPalette; + +/** * Colors to flash when pop limit reached. */ var g_DefaultPopulationColor = "white"; @@ -278,6 +294,8 @@ for (let slot in Engine.GetGUIObjectByName("panelEntityPanel").children) initPanelEntities(slot); + g_DiplomacyColorPalette = Engine.ReadJSONFile(g_SettingsDirectory + "diplomacy_colors.json"); + g_DisplayedPlayerColors = g_Players.map(player => player.color); updateViewedPlayerDropdown(); // Select "observer" in the view player dropdown when rejoining as a defeated player @@ -358,6 +376,59 @@ g_Players = playerData; } +function updateDiplomacyColorsButton() +{ + g_DiplomacyColorsToggle = !g_DiplomacyColorsToggle; + let diplomacyColorsButton = Engine.GetGUIObjectByName("diplomacyColorsButton"); + diplomacyColorsButton.sprite = g_DiplomacyColorsToggle ? + "stretched:session/minimap-diplomacy-on.png" : + "stretched:session/minimap-diplomacy-off.png"; + diplomacyColorsButton.sprite_over = g_DiplomacyColorsToggle ? + "stretched:session/minimap-diplomacy-on-highlight.png" : + "stretched:session/minimap-diplomacy-off-highlight.png"; + updateDisplayedPlayerColors(); +} + +/** + * Updates the displayed colors of players in the simulation and GUI. + */ +function updateDisplayedPlayerColors() +{ + if (g_DiplomacyColorsToggle) + { + let teamRepresentatives = {}; + 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_DisplayedPlayerColors[i] = g_Players[teamRepresentatives[team] || i].color; + if (team != -1 && !teamRepresentatives[team]) + teamRepresentatives[team] = i; + } + else + // Players see colors depending on diplomacy + g_DisplayedPlayerColors[i] = + g_ViewedPlayer == i ? g_DiplomacyColorPalette.Self : + g_Players[g_ViewedPlayer].isAlly[i] ? g_DiplomacyColorPalette.Ally : + g_Players[g_ViewedPlayer].isNeutral[i] ? g_DiplomacyColorPalette.Neutral : + g_DiplomacyColorPalette.Enemy; + + g_DisplayedPlayerColors[0] = g_Players[0].color; + } + else + g_DisplayedPlayerColors = g_Players.map(player => player.color); + + Engine.GuiInterfaceCall("UpdateDisplayedPlayerColors", { + "displayedPlayerColors": g_DisplayedPlayerColors, + "displayDiplomacyColors": g_DiplomacyColorsToggle, + "showAllStatusBars": g_ShowAllStatusBars, + "selected": g_Selection.toList() + }); + + updateGUIObjects(); +} + /** * Depends on the current player (g_IsObserver). */ @@ -477,6 +548,7 @@ } Engine.SetViewedPlayer(g_ViewedPlayer); + updateDisplayedPlayerColors(); updateTopPanel(); updateChatAddressees(); updateHotkeyTooltips(); @@ -899,6 +971,7 @@ global.music.setState(global.music.states[battleState]); } + updateViewedPlayerDropdown(); updateDiplomacy(); } 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 @@ -769,6 +769,39 @@ return buildableEnts; }; +GuiInterface.prototype.UpdateDisplayedPlayerColors = function(player, data) +{ + let updateEntityColor = (iids, entities) => { + for (let ent of entities) + for (let iid of iids) + { + let cmp = Engine.QueryInterface(ent, iid); + if (cmp) + cmp.UpdateColor(); + } + }; + + let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); + let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); + for (let i = 1; i < numPlayers; ++i) + { + let cmpPlayer = QueryPlayerIDInterface(i, IID_Player); + if (!cmpPlayer) + continue; + + cmpPlayer.SetDisplayDiplomacyColor(data.displayDiplomacyColors); + if (data.displayDiplomacyColors) + cmpPlayer.SetDiplomacyColor(data.displayedPlayerColors[i]); + + updateEntityColor(data.showAllStatusBars && (i == player || player == -1) ? + [IID_Minimap, IID_RangeOverlayRenderer, IID_RallyPointRenderer, IID_StatusBars] : + [IID_Minimap, IID_RangeOverlayRenderer, IID_RallyPointRenderer], + cmpRangeManager.GetEntitiesByPlayer(i)); + } + updateEntityColor([IID_Selectable, IID_StatusBars], data.selected); + Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager).UpdateColors(); +}; + GuiInterface.prototype.SetSelectionHighlight = function(player, cmd) { let playerColors = {}; // cache of owner -> color map @@ -791,7 +824,7 @@ color = { "r":1, "g":1, "b":1 }; let cmpPlayer = QueryPlayerIDInterface(owner); if (cmpPlayer) - color = cmpPlayer.GetColor(); + color = cmpPlayer.GetDisplayedColor(); playerColors[owner] = color; } @@ -1902,6 +1935,7 @@ "GetFormationInfoFromTemplate": 1, "IsStanceSelected": 1, + "UpdateDisplayedPlayerColors": 1, "SetSelectionHighlight": 1, "GetAllBuildableEntities": 1, "SetStatusBars": 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,21 @@ ""; /** + * Don't serialize diplomacyColor or displayDiplomacyColor since they're modified by the GUI. + */ +Player.prototype.Serialize = function() +{ + let state = {}; + for (let key in this) + if (this.hasOwnProperty(key)) + state[key] = this[key]; + + state.diplomacyColor = undefined; + state.displayDiplomacyColor = false; + return state; +}; + +/** * Which units will be shown with special icons at the top. */ var panelEntityClasses = "Hero Relic"; @@ -32,6 +47,8 @@ this.name = undefined; // define defaults elsewhere (supporting other languages) this.civ = 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 @@ -122,7 +139,7 @@ { var colorInitialized = !!this.color; - this.color = { "r": r/255.0, "g": g/255.0, "b": b/255.0, "a": 1.0 }; + this.color = { "r": r / 255, "g": g / 255, "b": b / 255, "a": 1 }; // Used in Atlas if (colorInitialized) @@ -131,11 +148,26 @@ }); }; +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; +}; + Player.prototype.GetColor = function() { return this.color; }; +Player.prototype.GetDisplayedColor = function() +{ + return this.displayDiplomacyColor ? this.diplomacyColor : this.color; +}; + // Try reserving num population slots. Returns 0 on success or number of missing slots otherwise. Player.prototype.TryReservePopulationSlots = function(num) { 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 @@ -33,6 +33,10 @@ { this.enabled = false; this.showRank = false; + + // Whether the status bars used the player colors anywhere (e.g. in the capture bar) + this.usedPlayerColors = false; + this.auraSources = new Map(); }; @@ -103,6 +107,12 @@ this.RegenerateSprites(); }; +StatusBars.prototype.UpdateColor = function() +{ + if (this.usedPlayerColors) + this.RegenerateSprites(); +}; + StatusBars.prototype.RegenerateSprites = function() { let cmpOverlayRenderer = Engine.QueryInterface(this.entity, IID_OverlayRenderer); @@ -199,6 +209,8 @@ let owner = cmpOwnership.GetOwner(); if (owner == INVALID_PLAYER) return 0; + + this.usedPlayerColors = true; let cp = cmpCapturable.GetCapturePoints(); // Size of health bar (in world-space units) @@ -210,7 +222,7 @@ let setCaptureBarPart = function(playerID, startSize) { - let c = QueryPlayerIDInterface(playerID).GetColor(); + let c = QueryPlayerIDInterface(playerID).GetDisplayedColor(); let strColor = (c.r * 255) + " " + (c.g * 255) + " " + (c.b * 255) + " 255"; let size = width * cp[playerID] / cmpCapturable.GetMaxCapturePoints(); Index: binaries/data/mods/public/simulation/data/settings/diplomacy_colors.json =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/data/settings/diplomacy_colors.json @@ -0,0 +1,6 @@ +{ + "Self": { "r": 0, "g": 68, "b": 255 }, + "Ally": { "r": 94, "g": 255, "b": 0 }, + "Neutral": { "r": 255, "g": 220, "b": 0 }, + "Enemy": { "r": 255, "g": 0, "b": 0 } +} Index: source/graphics/TerritoryTexture.cpp =================================================================== --- source/graphics/TerritoryTexture.cpp +++ source/graphics/TerritoryTexture.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -53,7 +53,7 @@ bool CTerritoryTexture::UpdateDirty() { CmpPtr cmpTerritoryManager(m_Simulation, SYSTEM_ENTITY); - return cmpTerritoryManager && cmpTerritoryManager->NeedUpdate(&m_DirtyID); + return cmpTerritoryManager && cmpTerritoryManager->NeedUpdateTexture(&m_DirtyID); } void CTerritoryTexture::BindTexture(int unit) @@ -178,7 +178,7 @@ CColor color(1, 0, 1, 1); CmpPtr cmpPlayer(m_Simulation, cmpPlayerManager->GetPlayerByID(p)); if (cmpPlayer) - color = cmpPlayer->GetColor(); + color = cmpPlayer->GetDisplayedColor(); colors.push_back(color); } Index: source/ps/Game.cpp =================================================================== --- source/ps/Game.cpp +++ source/ps/Game.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -449,7 +449,7 @@ if (!cmpPlayer) m_PlayerColors[i] = BrokenColor; else - m_PlayerColors[i] = cmpPlayer->GetColor(); + m_PlayerColors[i] = cmpPlayer->GetDisplayedColor(); } } Index: source/simulation2/components/CCmpAIManager.cpp =================================================================== --- source/simulation2/components/CCmpAIManager.cpp +++ source/simulation2/components/CCmpAIManager.cpp @@ -1032,11 +1032,11 @@ passabilityMap = &cmpPathfinder->GetPassabilityGrid(); // Get the territory data - // Since getting the territory grid can trigger a recalculation, we check NeedUpdate first + // Since getting the territory grid can trigger a recalculation, we check NeedUpdateAI first Grid dummyGrid2; const Grid* territoryMap = &dummyGrid2; CmpPtr cmpTerritoryManager(GetSystemEntity()); - if (cmpTerritoryManager && cmpTerritoryManager->NeedUpdate(&m_TerritoriesDirtyID, &m_TerritoriesDirtyBlinkingID)) + if (cmpTerritoryManager && cmpTerritoryManager->NeedUpdateAI(&m_TerritoriesDirtyID, &m_TerritoriesDirtyBlinkingID)) territoryMap = &cmpTerritoryManager->GetTerritoryGrid(); LoadPathfinderClasses(state); @@ -1094,9 +1094,9 @@ } // Update the territory data - // Since getting the territory grid can trigger a recalculation, we check NeedUpdate first + // Since getting the territory grid can trigger a recalculation, we check NeedUpdateAI first CmpPtr cmpTerritoryManager(GetSystemEntity()); - if (cmpTerritoryManager && (cmpTerritoryManager->NeedUpdate(&m_TerritoriesDirtyID, &m_TerritoriesDirtyBlinkingID) || m_JustDeserialized)) + if (cmpTerritoryManager && (cmpTerritoryManager->NeedUpdateAI(&m_TerritoriesDirtyID, &m_TerritoriesDirtyBlinkingID) || m_JustDeserialized)) { const Grid& territoryMap = cmpTerritoryManager->GetTerritoryGrid(); m_Worker.UpdateTerritoryMap(territoryMap); Index: source/simulation2/components/CCmpMinimap.cpp =================================================================== --- source/simulation2/components/CCmpMinimap.cpp +++ source/simulation2/components/CCmpMinimap.cpp @@ -232,7 +232,7 @@ if (!cmpPlayer) return; - CColor color = cmpPlayer->GetColor(); + CColor color = cmpPlayer->GetDisplayedColor(); m_R = (u8) (color.r * 255); m_G = (u8) (color.g * 255); m_B = (u8) (color.b * 255); Index: source/simulation2/components/CCmpRallyPointRenderer.cpp =================================================================== --- source/simulation2/components/CCmpRallyPointRenderer.cpp +++ source/simulation2/components/CCmpRallyPointRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -351,6 +351,12 @@ return !m_RallyPoints.empty(); } + void UpdateColor() + { + UpdateLineColor(); + ConstructAllOverlayLines(); + } + private: /** @@ -598,7 +604,7 @@ if (!cmpPlayer) return; - m_LineColor = cmpPlayer->GetColor(); + m_LineColor = cmpPlayer->GetDisplayedColor(); } void CCmpRallyPointRenderer::RecomputeAllRallyPointPaths() Index: source/simulation2/components/CCmpRangeOverlayRenderer.cpp =================================================================== --- source/simulation2/components/CCmpRangeOverlayRenderer.cpp +++ source/simulation2/components/CCmpRangeOverlayRenderer.cpp @@ -154,7 +154,7 @@ if (!cmpPlayer) return; - CColor color = cmpPlayer->GetColor(); + CColor color = cmpPlayer->GetDisplayedColor(); m_Color = color; } Index: source/simulation2/components/CCmpSelectable.cpp =================================================================== --- source/simulation2/components/CCmpSelectable.cpp +++ source/simulation2/components/CCmpSelectable.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -244,7 +244,7 @@ /** * Set the color of the current owner. */ - void UpdatePlayerColor(); + virtual void UpdateColor(); private: SOverlayDescriptor m_OverlayDescriptor; @@ -333,7 +333,7 @@ if (msgData.from == INVALID_PLAYER || msgData.to == INVALID_PLAYER) break; - UpdatePlayerColor(); + UpdateColor(); InvalidateStaticOverlay(); break; } @@ -345,7 +345,7 @@ if (!cmpOwnership || msgData.player != cmpOwnership->GetOwner()) break; - UpdatePlayerColor(); + UpdateColor(); break; } case MT_PositionChanged: @@ -378,7 +378,7 @@ } } -void CCmpSelectable::UpdatePlayerColor() +void CCmpSelectable::UpdateColor() { CmpPtr cmpOwnership(GetEntityHandle()); @@ -393,7 +393,7 @@ { CmpPtr cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(cmpOwnership->GetOwner())); if (cmpPlayer) - color = cmpPlayer->GetColor(); + color = cmpPlayer->GetDisplayedColor(); } // Update the highlight color, while keeping the current alpha target value intact @@ -556,7 +556,7 @@ { if (!m_Cached) { - UpdatePlayerColor(); + UpdateColor(); m_Cached = true; } Index: source/simulation2/components/CCmpTerritoryManager.cpp =================================================================== --- source/simulation2/components/CCmpTerritoryManager.cpp +++ source/simulation2/components/CCmpTerritoryManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -102,6 +102,7 @@ struct SBoundaryLine { bool blinking; + player_id_t owner; CColor color; SOverlayTexturedLine overlay; }; @@ -128,6 +129,7 @@ m_DirtyID = 1; m_DirtyBlinkingID = 1; m_Visible = true; + m_ColorChanged = false; m_AnimTime = 0.0; @@ -258,6 +260,8 @@ size_t m_DirtyID; size_t m_DirtyBlinkingID; + bool m_ColorChanged; + void MakeDirty() { SAFE_DELETE(m_Territories); @@ -266,25 +270,24 @@ m_TriggerEvent = true; } - virtual bool NeedUpdate(size_t* dirtyID) const + virtual bool NeedUpdateTexture(size_t* dirtyID) { - if (*dirtyID != m_DirtyID) - { - *dirtyID = m_DirtyID; - return true; - } - return false; + if (*dirtyID == m_DirtyID && !m_ColorChanged) + return false; + + *dirtyID = m_DirtyID; + m_ColorChanged = false; + return true; } - virtual bool NeedUpdate(size_t* dirtyID, size_t* dirtyBlinkingID) const + virtual bool NeedUpdateAI(size_t* dirtyID, size_t* dirtyBlinkingID) const { - if (*dirtyID != m_DirtyID || *dirtyBlinkingID != m_DirtyBlinkingID) - { - *dirtyID = m_DirtyID; - *dirtyBlinkingID = m_DirtyBlinkingID; - return true; - } - return false; + if (*dirtyID == m_DirtyID && *dirtyBlinkingID == m_DirtyBlinkingID) + return false; + + *dirtyID = m_DirtyID; + *dirtyBlinkingID = m_DirtyBlinkingID; + return true; } void CalculateCostGrid(); @@ -306,6 +309,8 @@ m_Visible = visible; } + void UpdateColors(); + private: bool m_Visible; @@ -623,10 +628,11 @@ CColor color(1, 0, 1, 1); CmpPtr cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(boundaries[i].owner)); if (cmpPlayer) - color = cmpPlayer->GetColor(); + color = cmpPlayer->GetDisplayedColor(); m_BoundaryLines.push_back(SBoundaryLine()); m_BoundaryLines.back().blinking = boundaries[i].blinking; + m_BoundaryLines.back().owner = boundaries[i].owner; m_BoundaryLines.back().color = color; m_BoundaryLines.back().overlay.m_SimContext = &GetSimContext(); m_BoundaryLines.back().overlay.m_TextureBase = textureBase; @@ -805,6 +811,25 @@ return (m_Territories->get(i, j) & TERRITORY_BLINKING_MASK) != 0; } +void CCmpTerritoryManager::UpdateColors() +{ + m_ColorChanged = true; + + CmpPtr cmpPlayerManager(GetSystemEntity()); + if (!cmpPlayerManager) + return; + + for (SBoundaryLine& boundaryLine : m_BoundaryLines) + { + CmpPtr cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(boundaryLine.owner)); + if (!cmpPlayer) + continue; + + boundaryLine.color = cmpPlayer->GetDisplayedColor(); + boundaryLine.overlay.m_Color = boundaryLine.color; + } +} + TerritoryOverlay::TerritoryOverlay(CCmpTerritoryManager& manager) : TerrainTextureOverlay((float)Pathfinding::NAVCELLS_PER_TILE / ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE), m_TerritoryManager(manager) Index: source/simulation2/components/ICmpPlayer.h =================================================================== --- source/simulation2/components/ICmpPlayer.h +++ source/simulation2/components/ICmpPlayer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,7 +32,7 @@ class ICmpPlayer : public IComponent { public: - virtual CColor GetColor() = 0; + virtual CColor GetDisplayedColor() = 0; virtual std::wstring GetCiv() = 0; virtual CFixedVector3D GetStartingCameraPos() = 0; virtual CFixedVector3D GetStartingCameraRot() = 0; Index: source/simulation2/components/ICmpPlayer.cpp =================================================================== --- source/simulation2/components/ICmpPlayer.cpp +++ source/simulation2/components/ICmpPlayer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -33,9 +33,9 @@ public: DEFAULT_SCRIPT_WRAPPER(PlayerScripted) - virtual CColor GetColor() + virtual CColor GetDisplayedColor() { - return m_Script.Call("GetColor"); + return m_Script.Call("GetDisplayedColor"); } virtual std::wstring GetCiv() Index: source/simulation2/components/ICmpRallyPointRenderer.h =================================================================== --- source/simulation2/components/ICmpRallyPointRenderer.h +++ source/simulation2/components/ICmpRallyPointRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -50,6 +50,9 @@ /// Returns true if at least one display rally point is set virtual bool IsSet() const = 0; + /// Updates the line color + virtual void UpdateColor() = 0; + DECLARE_INTERFACE_TYPE(RallyPointRenderer) }; Index: source/simulation2/components/ICmpRallyPointRenderer.cpp =================================================================== --- source/simulation2/components/ICmpRallyPointRenderer.cpp +++ source/simulation2/components/ICmpRallyPointRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,4 +29,5 @@ DEFINE_INTERFACE_METHOD_1("AddPosition", void, ICmpRallyPointRenderer, AddPosition_wrapper, CFixedVector2D) DEFINE_INTERFACE_METHOD_0("Reset", void, ICmpRallyPointRenderer, Reset) DEFINE_INTERFACE_METHOD_CONST_0("IsSet", bool, ICmpRallyPointRenderer, IsSet) +DEFINE_INTERFACE_METHOD_0("UpdateColor", void, ICmpRallyPointRenderer, UpdateColor) END_INTERFACE_WRAPPER(RallyPointRenderer) Index: source/simulation2/components/ICmpRangeOverlayRenderer.h =================================================================== --- source/simulation2/components/ICmpRangeOverlayRenderer.h +++ source/simulation2/components/ICmpRangeOverlayRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -34,6 +34,11 @@ */ virtual void ResetRangeOverlays() = 0; + /** + * Updates the overlay color to match the player color. + */ + virtual void UpdateColor() = 0; + DECLARE_INTERFACE_TYPE(RangeOverlayRenderer) }; Index: source/simulation2/components/ICmpRangeOverlayRenderer.cpp =================================================================== --- source/simulation2/components/ICmpRangeOverlayRenderer.cpp +++ source/simulation2/components/ICmpRangeOverlayRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,4 +23,5 @@ BEGIN_INTERFACE_WRAPPER(RangeOverlayRenderer) DEFINE_INTERFACE_METHOD_4("AddRangeOverlay", void, ICmpRangeOverlayRenderer, AddRangeOverlay, float, std::string, std::string, float) DEFINE_INTERFACE_METHOD_0("ResetRangeOverlays", void, ICmpRangeOverlayRenderer, ResetRangeOverlays) +DEFINE_INTERFACE_METHOD_0("UpdateColor", void, ICmpRangeOverlayRenderer, UpdateColor) END_INTERFACE_WRAPPER(RangeOverlayRenderer) Index: source/simulation2/components/ICmpSelectable.h =================================================================== --- source/simulation2/components/ICmpSelectable.h +++ source/simulation2/components/ICmpSelectable.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,7 +31,7 @@ virtual bool IsEditorOnly() const = 0; /** - * Set the selection highlight state. + * Sets the selection highlight state. * The highlight is typically a circle/square overlay around the unit. * @param color color and alpha of the selection highlight. Set color.a = 0 to hide the highlight. * @param selected whether the entity is selected; affects desaturation for always visible highlights. @@ -54,7 +54,12 @@ } /** - * Set the alpha of the selection highlight. Set to 0 to hide the highlight. + * Updates the selection color to match the current owner. + */ + virtual void UpdateColor() = 0; + + /** + * Sets the alpha of the selection highlight. Set to 0 to hide the highlight. */ virtual void SetSelectionHighlightAlpha(float alpha) = 0; Index: source/simulation2/components/ICmpSelectable.cpp =================================================================== --- source/simulation2/components/ICmpSelectable.cpp +++ source/simulation2/components/ICmpSelectable.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,6 +25,7 @@ BEGIN_INTERFACE_WRAPPER(Selectable) DEFINE_INTERFACE_METHOD_2("SetSelectionHighlight", void, ICmpSelectable, SetSelectionHighlight, CColor, bool) +DEFINE_INTERFACE_METHOD_0("UpdateColor", void, ICmpSelectable, UpdateColor) END_INTERFACE_WRAPPER(Selectable) bool ICmpSelectable::ms_EnableDebugOverlays = false; Index: source/simulation2/components/ICmpTerritoryManager.h =================================================================== --- source/simulation2/components/ICmpTerritoryManager.h +++ source/simulation2/components/ICmpTerritoryManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,8 +29,15 @@ class ICmpTerritoryManager : public IComponent { public: - virtual bool NeedUpdate(size_t* dirtyID) const = 0; - virtual bool NeedUpdate(size_t* dirtyID, size_t* dirtyBlinkingID) const = 0; + /** + * Returns whether the territory texture needs to be updated. + */ + virtual bool NeedUpdateTexture(size_t* dirtyID) = 0; + + /** + * Returns whether the AI territory map needs to be updated. + */ + virtual bool NeedUpdateAI(size_t* dirtyID, size_t* dirtyBlinkingID) const = 0; /** * Number of pathfinder navcells per territory tile. @@ -91,6 +98,11 @@ */ virtual void SetVisibility(bool visible) = 0; + /** + * Updates the boundary and territory colors. + */ + virtual void UpdateColors() = 0; + DECLARE_INTERFACE_TYPE(TerritoryManager) }; Index: source/simulation2/components/ICmpTerritoryManager.cpp =================================================================== --- source/simulation2/components/ICmpTerritoryManager.cpp +++ source/simulation2/components/ICmpTerritoryManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,4 +28,5 @@ DEFINE_INTERFACE_METHOD_3("SetTerritoryBlinking", void, ICmpTerritoryManager, SetTerritoryBlinking, entity_pos_t, entity_pos_t, bool) DEFINE_INTERFACE_METHOD_2("IsTerritoryBlinking", bool, ICmpTerritoryManager, IsTerritoryBlinking, entity_pos_t, entity_pos_t) DEFINE_INTERFACE_METHOD_1("GetTerritoryPercentage", u8, ICmpTerritoryManager, GetTerritoryPercentage, player_id_t) +DEFINE_INTERFACE_METHOD_0("UpdateColors", void, ICmpTerritoryManager, UpdateColors) END_INTERFACE_WRAPPER(TerritoryManager) Index: source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp =================================================================== --- source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp +++ source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -145,7 +145,10 @@ entity_id_t playerEnt = cmpPlayerManager->GetPlayerByID(owner); CmpPtr cmpPlayer(sim, playerEnt); if (cmpPlayer) - color = colorMap[owner] = cmpPlayer->GetColor(); + { + colorMap[owner] = cmpPlayer->GetDisplayedColor(); + color = colorMap[owner]; + } } } return color;