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 @@ -514,7 +514,7 @@ */ function updateDiplomacy() { - g_Players = getPlayerData(g_Players); + updatePlayerData(); if (g_IsDiplomacyOpen) openDiplomacy(); 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 @@ -475,3 +475,55 @@ if (Engine.GetGUIObjectByName("unitGarrisonPanel") && !Engine.GetGUIObjectByName("unitGarrisonPanel").hidden) updateGarrisonHealthBar(entStates[0], g_Selection.toList()); } + +function getRankIconSprite(entState) +{ + if (entState.identity.rank == "Elite") + return "stretched:session/icons/rank3.png"; + + if (entState.identity.rank == "Advanced") + return "stretched:session/icons/rank2.png"; + + if (entState.identity.classes.indexOf("CitizenSoldier") != -1) + return "stretched:session/icons/rank1.png"; + + return ""; +} + +/** + * Returns a message with the details of the trade gain. + */ +function getTradingTooltip(gain) +{ + if (!gain) + return ""; + + let markets = [ + { "gain": gain.market1Gain, "owner": gain.market1Owner }, + { "gain": gain.market2Gain, "owner": gain.market2Owner } + ]; + + let primaryGain = gain.traderGain; + + for (let market of markets) + if (market.gain && market.owner == gain.traderOwner) + // Translation: Used in the trading gain tooltip to concatenate profits of different players + primaryGain += translate("+") + market.gain; + + let playerStates = GetSimState().players; + + // Translation: Used in the trading gain tooltip + let gainString = (gain, owner) => sprintf(translate("%(gain)s (%(player)s)"), { + "gain": gain, + "player": playerStates[owner].name + }); + + // Translation: Used in the trading gain tooltip + let tooltip = gainString(primaryGain, gain.traderOwner); + + for (let market of markets) + if (market.gain && market.owner != gain.traderOwner) + tooltip += translate(", ") + gainString(market.gain, market.owner); + + return tooltip; +} Index: binaries/data/mods/public/gui/session/selection_panels.js =================================================================== --- binaries/data/mods/public/gui/session/selection_panels.js +++ binaries/data/mods/public/gui/session/selection_panels.js @@ -40,6 +40,18 @@ return "color:" + rgbToGuiColor(g_Players[player].color) + " 160"; } +/** + * Returns a "color:255 0 0 Alpha" string based on how many resources are needed. + */ +function resourcesToAlphaMask(neededResources) +{ + let totalCost = 0; + for (let resource in neededResources) + totalCost += +neededResources[resource]; + + return "color:255 0 0 " + Math.min(125, Math.round(+totalCost/10.0) + 50); +} + g_SelectionPanels.Alert = { "getMaxNumberOfItems": function() { 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 @@ -265,7 +265,7 @@ g_PlayerAssignments.local.player = -1; } - g_Players = getPlayerData(); + updatePlayerData(); g_CivData = loadCivData(); g_CivData.gaia = { "Code": "gaia", "Name": translate("Gaia") }; @@ -326,6 +326,54 @@ //setTimeout(function() { reportPerformance(60); }, 60000); } +function updatePlayerData() +{ + let simState = GetSimState(); + if (!simState) + return; + + let playerData = []; + + for (let i = 0; i < simState.players.length; ++i) + { + let playerState = simState.players[i]; + + playerData.push({ + "name": playerState.name, + "civ": playerState.civ, + "color": { + "r": playerState.color.r*255, + "g": playerState.color.g*255, + "b": playerState.color.b*255, + "a": playerState.color.a*255 + }, + "team": playerState.team, + "teamsLocked": playerState.teamsLocked, + "cheatsEnabled": playerState.cheatsEnabled, + "state": playerState.state, + "isAlly": playerState.isAlly, + "isMutualAlly": playerState.isMutualAlly, + "isNeutral": playerState.isNeutral, + "isEnemy": playerState.isEnemy, + "guid": undefined, // network guid for players controlled by hosts + "offline": g_Players[i] && !!g_Players[i].offline + }); + } + + for (let guid in g_PlayerAssignments) + { + let playerID = g_PlayerAssignments[guid].player; + + if (!playerData[playerID]) + continue; + + playerData[playerID].guid = guid; + playerData[playerID].name = g_PlayerAssignments[guid].name; + } + + g_Players = playerData; +} + /** * Depends on the current player (g_IsObserver). */ @@ -374,6 +422,19 @@ }; } +/** + * Returns the entity itself except when garrisoned where it returns its garrisonHolder + */ +function getEntityOrHolder(ent) +{ + let entState = GetEntityState(ent); + if (entState && !entState.position && entState.unitAI && entState.unitAI.orders.length && + (entState.unitAI.orders[0].type == "Garrison" || entState.unitAI.orders[0].type == "Autogarrison")) + return getEntityOrHolder(entState.unitAI.orders[0].data.target); + + return ent; +} + function initializeMusic() { initMusic(); @@ -1217,6 +1278,64 @@ } /** + * Send the current list of players, teams, AIs, observers and defeated/won and offline states to the lobby. + * The playerData format from g_GameAttributes is kept to reuse the GUI function presenting the data. + */ +function sendLobbyPlayerlistUpdate() +{ + if (!g_IsController || !Engine.HasXmppClient()) + return; + + // Extract the relevant player data and minimize packet load + let minPlayerData = []; + for (let playerID in g_GameAttributes.settings.PlayerData) + { + if (+playerID == 0) + continue; + + let pData = g_GameAttributes.settings.PlayerData[playerID]; + + let minPData = { "Name": pData.Name }; + + if (g_GameAttributes.settings.LockTeams) + minPData.Team = pData.Team; + + if (pData.AI) + { + minPData.AI = pData.AI; + minPData.AIDiff = pData.AIDiff; + } + + if (g_Players[playerID].offline) + minPData.Offline = true; + + // Whether the player has won or was defeated + let state = g_Players[playerID].state; + if (state != "active") + minPData.State = state; + + minPlayerData.push(minPData); + } + + // Add observers + let connectedPlayers = 0; + for (let guid in g_PlayerAssignments) + { + let pData = g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player]; + + if (pData) + ++connectedPlayers; + else + minPlayerData.push({ + "Name": g_PlayerAssignments[guid].name, + "Team": "observer" + }); + } + + Engine.SendChangeStateGame(connectedPlayers, playerDataToStringifiedTeamList(minPlayerData)); +} + +/** * Send a report on the gamestatus to the lobby. */ function reportGame() Index: binaries/data/mods/public/gui/session/unit_actions.js =================================================================== --- binaries/data/mods/public/gui/session/unit_actions.js +++ binaries/data/mods/public/gui/session/unit_actions.js @@ -1398,6 +1398,12 @@ return false; } +function hasClass(entState, className) +{ + // note: use the functions in globalscripts/Templates.js for more versatile matching + return entState.identity && entState.identity.classes.indexOf(className) != -1; +} + /** * Work out whether at least part of the selected entities have UnitAI. */ Index: binaries/data/mods/public/gui/session/utility_functions.js =================================================================== --- binaries/data/mods/public/gui/session/utility_functions.js +++ /dev/null @@ -1,191 +0,0 @@ -function getPlayerData(previousData = undefined) -{ - let players = []; - - let simState = GetSimState(); - if (!simState) - return players; - - for (let i = 0; i < simState.players.length; ++i) - { - let playerState = simState.players[i]; - players.push({ - "name": playerState.name, - "civ": playerState.civ, - "color": { - "r": playerState.color.r*255, - "g": playerState.color.g*255, - "b": playerState.color.b*255, - "a": playerState.color.a*255 - }, - "team": playerState.team, - "teamsLocked": playerState.teamsLocked, - "cheatsEnabled": playerState.cheatsEnabled, - "state": playerState.state, - "isAlly": playerState.isAlly, - "isMutualAlly": playerState.isMutualAlly, - "isNeutral": playerState.isNeutral, - "isEnemy": playerState.isEnemy, - "guid": undefined, // network guid for players controlled by hosts - "offline": previousData && !!previousData[i].offline - }); - } - - if (g_PlayerAssignments) - for (let guid in g_PlayerAssignments) - { - let playerID = g_PlayerAssignments[guid].player; - - if (!players[playerID]) - continue; - - players[playerID].guid = guid; - players[playerID].name = g_PlayerAssignments[guid].name; - } - - return players; -} - -function hasClass(entState, className) -{ - // note: use the functions in globalscripts/Templates.js for more versatile matching - if (entState.identity) - { - var classes = entState.identity.classes; - if (classes && classes.length) - return (classes.indexOf(className) != -1); - } - return false; -} - -function getRankIconSprite(entState) -{ - if ("Elite" == entState.identity.rank) - return "stretched:session/icons/rank3.png"; - else if ("Advanced" == entState.identity.rank) - return "stretched:session/icons/rank2.png"; - else if (entState.identity.classes && entState.identity.classes.length && -1 != entState.identity.classes.indexOf("CitizenSoldier")) - return "stretched:session/icons/rank1.png"; - - return ""; -} - -/** - * Returns a message with the details of the trade gain. - */ -function getTradingTooltip(gain) -{ - if (!gain) - return ""; - - var simState = GetSimState(); - - var gainString = gain.traderGain; - if (gain.market1Gain && gain.market1Owner == gain.traderOwner) - gainString += translate("+") + gain.market1Gain; - if (gain.market2Gain && gain.market2Owner == gain.traderOwner) - gainString += translate("+") + gain.market2Gain; - - var tooltip = sprintf(translate("%(gain)s (%(player)s)"), { - "gain": gainString, - "player": simState.players[gain.traderOwner].name - }); - - if (gain.market1Gain && gain.market1Owner != gain.traderOwner) - tooltip += translateWithContext("Separation mark in an enumeration", ", ") + sprintf(translate("%(gain)s (%(player)s)"), { - "gain": gain.market1Gain, - "player": simState.players[gain.market1Owner].name - }); - - if (gain.market2Gain && gain.market2Owner != gain.traderOwner) - tooltip += translateWithContext("Separation mark in an enumeration", ", ") + sprintf(translate("%(gain)s (%(player)s)"), { - "gain": gain.market2Gain, - "player": simState.players[gain.market2Owner].name - }); - - return tooltip; -} - -/** - * Returns the entity itself except when garrisoned where it returns its garrisonHolder - */ -function getEntityOrHolder(ent) -{ - let entState = GetEntityState(ent); - if (entState && !entState.position && entState.unitAI && entState.unitAI.orders.length && - (entState.unitAI.orders[0].type == "Garrison" || entState.unitAI.orders[0].type == "Autogarrison")) - return getEntityOrHolder(entState.unitAI.orders[0].data.target); - - return ent; -} - -/** - * Returns a "color:255 0 0 Alpha" string based on how many resources are needed. - */ -function resourcesToAlphaMask(neededResources) -{ - var totalCost = 0; - for (var resource in neededResources) - totalCost += +neededResources[resource]; - var alpha = 50 + Math.round(+totalCost/10.0); - alpha = alpha > 125 ? 125 : alpha; - return "color:255 0 0 " + alpha; -} - -/** - * Send the current list of players, teams, AIs, observers and defeated/won and offline states to the lobby. - * The playerData format from g_GameAttributes is kept to reuse the GUI function presenting the data. - */ -function sendLobbyPlayerlistUpdate() -{ - if (!g_IsController || !Engine.HasXmppClient()) - return; - - // Extract the relevant player data and minimize packet load - let minPlayerData = []; - for (let playerID in g_GameAttributes.settings.PlayerData) - { - if (+playerID == 0) - continue; - - let pData = g_GameAttributes.settings.PlayerData[playerID]; - - let minPData = { "Name": pData.Name }; - - if (g_GameAttributes.settings.LockTeams) - minPData.Team = pData.Team; - - if (pData.AI) - { - minPData.AI = pData.AI; - minPData.AIDiff = pData.AIDiff; - } - - if (g_Players[playerID].offline) - minPData.Offline = true; - - // Whether the player has won or was defeated - let state = g_Players[playerID].state; - if (state != "active") - minPData.State = state; - - minPlayerData.push(minPData); - } - - // Add observers - let connectedPlayers = 0; - for (let guid in g_PlayerAssignments) - { - let pData = g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player]; - - if (pData) - ++connectedPlayers; - else - minPlayerData.push({ - "Name": g_PlayerAssignments[guid].name, - "Team": "observer" - }); - } - - Engine.SendChangeStateGame(connectedPlayers, playerDataToStringifiedTeamList(minPlayerData)); -}