Index: ps/trunk/binaries/data/mods/public/gui/session/session.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/session.js (revision 14702) +++ ps/trunk/binaries/data/mods/public/gui/session/session.js (revision 14703) @@ -1,968 +1,1015 @@ // Network Mode var g_IsNetworked = false; // Is this user in control of game settings (i.e. is a network server, or offline player) var g_IsController; // Match ID for tracking var g_MatchID; // Cache the basic player data (name, civ, color) var g_Players = []; // Cache the useful civ data var g_CivData = {}; var g_GameSpeeds = {}; var g_CurrentSpeed; var g_PlayerAssignments = { "local": { "name": "You", "player": 1 } }; // Cache dev-mode settings that are frequently or widely used var g_DevSettings = { controlAll: false }; // Whether status bars should be shown for all of the player's units. var g_ShowAllStatusBars = false; // Indicate when one of the current player's training queues is blocked // (this is used to support population counter blinking) var g_IsTrainingBlocked = false; // Cache simulation state (updated on every simulation update) var g_SimState; // Cache EntityStates var g_EntityStates = {}; // {id:entState} // Whether the player has lost/won and reached the end of their game var g_GameEnded = false; var g_Disconnected = false; // Lost connection to server // Holds player states from the last tick var g_CachedLastStates = ""; // Colors to flash when pop limit reached const DEFAULT_POPULATION_COLOR = "white"; const POPULATION_ALERT_COLOR = "orange"; // List of additional entities to highlight var g_ShowGuarding = false; var g_ShowGuarded = false; var g_AdditionalHighlight = []; // for saving the hitpoins of the hero (is there a better way to do that?) // Should be possible with AttackDetection but might be an overkill because it would have to loop // always through the list of all ongoing attacks... var g_previousHeroHitPoints = undefined; function GetSimState() { if (!g_SimState) g_SimState = Engine.GuiInterfaceCall("GetSimulationState"); return g_SimState; } function GetEntityState(entId) { if (!(entId in g_EntityStates)) { var entState = Engine.GuiInterfaceCall("GetEntityState", entId); if (entState) entState.extended = false; g_EntityStates[entId] = entState; } return g_EntityStates[entId]; } function GetExtendedEntityState(entId) { if (entId in g_EntityStates) var entState = g_EntityStates[entId]; else var entState = Engine.GuiInterfaceCall("GetEntityState", entId); if (!entState || entState.extended) return entState; var extension = Engine.GuiInterfaceCall("GetExtendedEntityState", entId); for (var prop in extension) entState[prop] = extension[prop]; entState.extended = true; g_EntityStates[entId] = entState; return entState; } // Cache TemplateData var g_TemplateData = {}; // {id:template} function GetTemplateData(templateName) { if (!(templateName in g_TemplateData)) { var template = Engine.GuiInterfaceCall("GetTemplateData", templateName); g_TemplateData[templateName] = template; } return g_TemplateData[templateName]; } // Cache TechnologyData var g_TechnologyData = {}; // {id:template} function GetTechnologyData(technologyName) { if (!(technologyName in g_TechnologyData)) { var template = Engine.GuiInterfaceCall("GetTechnologyData", technologyName); g_TechnologyData[technologyName] = template; } return g_TechnologyData[technologyName]; } // Init function init(initData, hotloadData) { if (initData) { g_IsNetworked = initData.isNetworked; // Set network mode g_IsController = initData.isController; // Set controller mode g_PlayerAssignments = initData.playerAssignments; g_MatchID = initData.attribs.matchID; // Cache the player data // (This may be updated at runtime by handleNetMessage) g_Players = getPlayerData(g_PlayerAssignments); if (initData.savedGUIData) restoreSavedGameData(initData.savedGUIData); Engine.GetGUIObjectByName("gameSpeedButton").hidden = g_IsNetworked; } else // Needed for autostart loading option { g_Players = getPlayerData(null); } // Cache civ data g_CivData = loadCivData(); g_CivData["gaia"] = { "Code": "gaia", "Name": "Gaia" }; g_GameSpeeds = initGameSpeeds(); g_CurrentSpeed = Engine.GetSimRate(); var gameSpeed = Engine.GetGUIObjectByName("gameSpeed"); gameSpeed.list = g_GameSpeeds.names; gameSpeed.list_data = g_GameSpeeds.speeds; var idx = g_GameSpeeds.speeds.indexOf(g_CurrentSpeed); gameSpeed.selected = idx != -1 ? idx : g_GameSpeeds["default"]; gameSpeed.onSelectionChange = function() { changeGameSpeed(+this.list_data[this.selected]); } Engine.GetGUIObjectByName("civIcon").sprite = "stretched:" + g_CivData[g_Players[Engine.GetPlayerID()].civ].Emblem; Engine.GetGUIObjectByName("civIcon").tooltip = g_CivData[g_Players[Engine.GetPlayerID()].civ].Name; initMenuPosition(); // set initial position // Populate player selection dropdown var playerNames = []; var playerIDs = []; for (var player in g_Players) { playerNames.push(g_Players[player].name); playerIDs.push(player); } var viewPlayerDropdown = Engine.GetGUIObjectByName("viewPlayer"); viewPlayerDropdown.list = playerNames; viewPlayerDropdown.list_data = playerIDs; viewPlayerDropdown.selected = Engine.GetPlayerID(); // If in Atlas editor, disable the exit button if (Engine.IsAtlasRunning()) Engine.GetGUIObjectByName("menuExitButton").enabled = false; if (hotloadData) { g_Selection.selected = hotloadData.selection; } else { // Starting for the first time: var civMusic = g_CivData[g_Players[Engine.GetPlayerID()].civ].Music; initMusic(); global.music.storeTracks(civMusic); global.music.setState(global.music.states.PEACE); playRandomAmbient("temperate"); } if (Engine.ConfigDB_GetValue("user", "gui.session.timeelapsedcounter") === "true") Engine.GetGUIObjectByName("timeElapsedCounter").hidden = false; onSimulationUpdate(); // Report the performance after 5 seconds (when we're still near // the initial camera view) and a minute (when the profiler will // have settled down if framerates as very low), to give some // extremely rough indications of performance setTimeout(function() { reportPerformance(5); }, 5000); setTimeout(function() { reportPerformance(60); }, 60000); } function selectViewPlayer(playerID) { Engine.SetPlayerID(playerID); if (playerID != 0) { Engine.GetGUIObjectByName("civIcon").sprite = "stretched:" + g_CivData[g_Players[playerID].civ].Emblem; Engine.GetGUIObjectByName("civIcon").tooltip = g_CivData[g_Players[playerID].civ].Name; } } function reportPerformance(time) { var settings = Engine.GetMapSettings(); var data = { time: time, map: settings.Name, seed: settings.Seed, // only defined for random maps size: settings.Size, // only defined for random maps profiler: Engine.GetProfilerState() }; Engine.SubmitUserReport("profile", 3, JSON.stringify(data)); } function resignGame() { var simState = GetSimState(); // Players can't resign if they've already won or lost. if (simState.players[Engine.GetPlayerID()].state != "active" || g_Disconnected) return; // Tell other players that we have given up and been defeated Engine.PostNetworkCommand({ "type": "defeat-player", "playerId": Engine.GetPlayerID() }); global.music.setState(global.music.states.DEFEAT); resumeGame(); } function leaveGame() { var extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState"); var playerState = extendedSimState.players[Engine.GetPlayerID()]; var mapSettings = Engine.GetMapSettings(); var gameResult; if (g_Disconnected) { gameResult = "You have been disconnected." } else if (playerState.state == "won") { gameResult = "You have won the battle!"; } else if (playerState.state == "defeated") { gameResult = "You have been defeated..."; } else // "active" { gameResult = "You have abandoned the game."; // Tell other players that we have given up and been defeated Engine.PostNetworkCommand({ "type": "defeat-player", "playerId": Engine.GetPlayerID() }); global.music.setState(global.music.states.DEFEAT); } stopAmbient(); Engine.EndGame(); if (g_IsController && Engine.HasXmppClient()) Engine.SendUnregisterGame(); Engine.SwitchGuiPage("page_summary.xml", { "gameResult" : gameResult, "timeElapsed" : extendedSimState.timeElapsed, "playerStates": extendedSimState.players, "players": g_Players, "mapSettings": mapSettings }); } // Return some data that we'll use when hotloading this file after changes function getHotloadData() { return { selection: g_Selection.selected }; } // Return some data that will be stored in saved game files function getSavedGameData() { var data = {}; data.playerAssignments = g_PlayerAssignments; data.groups = g_Groups.groups; // TODO: any other gui state? return data; } function restoreSavedGameData(data) { // Clear selection when loading a game g_Selection.reset(); // Restore control groups for (var groupNumber in data.groups) { g_Groups.groups[groupNumber].groups = data.groups[groupNumber].groups; g_Groups.groups[groupNumber].ents = data.groups[groupNumber].ents; } updateGroups(); } var lastTickTime = new Date; var lastXmppClientPoll = Date.now(); /** * Called every frame. */ function onTick() { var now = new Date; var tickLength = new Date - lastTickTime; lastTickTime = now; checkPlayerState(); while (true) { var message = Engine.PollNetworkClient(); if (!message) break; handleNetMessage(message); } updateCursorAndTooltip(); // If the selection changed, we need to regenerate the sim display (the display depends on both the // simulation state and the current selection). if (g_Selection.dirty) { g_Selection.dirty = false; onSimulationUpdate(); // Display rally points for selected buildings Engine.GuiInterfaceCall("DisplayRallyPoint", { "entities": g_Selection.toList() }); } // Run timers updateTimers(); // Animate menu updateMenuPosition(tickLength); // When training is blocked, flash population (alternates colour every 500msec) if (g_IsTrainingBlocked && (Date.now() % 1000) < 500) Engine.GetGUIObjectByName("resourcePop").textcolor = POPULATION_ALERT_COLOR; else Engine.GetGUIObjectByName("resourcePop").textcolor = DEFAULT_POPULATION_COLOR; // Clear renamed entities list Engine.GuiInterfaceCall("ClearRenamedEntities"); // If the lobby is running, wake it up every 10 seconds so we stay connected. if (Engine.HasXmppClient() && (Date.now() - lastXmppClientPoll) > 10000) { Engine.RecvXmppClient(); lastXmppClientPoll = Date.now(); } } function checkPlayerState() { // Once the game ends, we're done here. if (g_GameEnded) return; // Send a game report for each player in this game. var m_simState = GetSimState(); var playerState = m_simState.players[Engine.GetPlayerID()]; var tempStates = ""; for each (var player in m_simState.players) {tempStates += player.state + ",";} if (g_CachedLastStates != tempStates) { g_CachedLastStates = tempStates; reportGame(Engine.GuiInterfaceCall("GetExtendedSimulationState")); } // If the local player hasn't finished playing, we return here to avoid the victory/defeat messages. if (playerState.state == "active") return; // We can't resign once the game is over. Engine.GetGUIObjectByName("menuResignButton").enabled = false; // Make sure nothing is open to avoid stacking. closeMenu(); closeOpenDialogs(); // Make sure this doesn't run again. g_GameEnded = true; if (Engine.IsAtlasRunning()) { // If we're in Atlas, we can't leave the game var btCaptions = ["OK"]; var btCode = [null]; var message = "Press OK to continue"; } else { var btCaptions = ["Yes", "No"]; var btCode = [leaveGame, null]; var message = "Do you want to quit?"; } if (playerState.state == "defeated") { global.music.setState(global.music.states.DEFEAT); messageBox(400, 200, message, "DEFEATED!", 0, btCaptions, btCode); } else if (playerState.state == "won") { global.music.setState(global.music.states.VICTORY); // TODO: Reveal map directly instead of this silly proxy. if (!Engine.GetGUIObjectByName("devCommandsRevealMap").checked) Engine.GetGUIObjectByName("devCommandsRevealMap").checked = true; messageBox(400, 200, message, "VICTORIOUS!", 0, btCaptions, btCode); } } function changeGameSpeed(speed) { // For non-networked games only if (!g_IsNetworked) { Engine.SetSimRate(speed); g_CurrentSpeed = speed; } } /** * Recomputes GUI state that depends on simulation state or selection state. Called directly every simulation * update (see session.xml), or from onTick when the selection has changed. */ function onSimulationUpdate() { g_EntityStates = {}; g_TemplateData = {}; g_TechnologyData = {}; g_SimState = Engine.GuiInterfaceCall("GetSimulationState"); // If we're called during init when the game is first loading, there will be no simulation yet, so do nothing if (!g_SimState) return; handleNotifications(); if (g_ShowAllStatusBars) recalculateStatusBarDisplay(); if (g_ShowGuarding || g_ShowGuarded) updateAdditionalHighlight(); updateHero(); updateGroups(); updateDebug(); updatePlayerDisplay(); updateSelectionDetails(); updateResearchDisplay(); updateBuildingPlacementPreview(); updateTimeElapsedCounter(); updateTimeNotifications(); // Update music state on basis of battle state. var battleState = Engine.GuiInterfaceCall("GetBattleState", Engine.GetPlayerID()); if (battleState) global.music.setState(global.music.states[battleState]); } /** * updates a status bar on the GUI * nameOfBar: name of the bar * points: points to show * maxPoints: max points * direction: gets less from (right to left) 0; (top to bottom) 1; (left to right) 2; (bottom to top) 3; */ function updateGUIStatusBar(nameOfBar, points, maxPoints, direction) { // check, if optional direction parameter is valid. if (!direction || !(direction >= 0 && direction < 4)) direction = 0; // get the bar and update it var statusBar = Engine.GetGUIObjectByName(nameOfBar); if (!statusBar) return; var healthSize = statusBar.size; var value = 100*Math.max(0, Math.min(1, points / maxPoints)); // inverse bar if(direction == 2 || direction == 3) value = 100 - value; if(direction == 0) healthSize.rright = value; else if(direction == 1) healthSize.rbottom = value; else if(direction == 2) healthSize.rleft = value; else if(direction == 3) healthSize.rtop = value; // update bar statusBar.size = healthSize; } function updateHero() { var simState = GetSimState(); var playerState = simState.players[Engine.GetPlayerID()]; var unitHeroPanel = Engine.GetGUIObjectByName("unitHeroPanel"); var heroButton = Engine.GetGUIObjectByName("unitHeroButton"); if (!playerState || playerState.heroes.length <= 0) { g_previousHeroHitPoints = undefined; unitHeroPanel.hidden = true; return; } var heroImage = Engine.GetGUIObjectByName("unitHeroImage"); var heroState = GetExtendedEntityState(playerState.heroes[0]); var template = GetTemplateData(heroState.template); heroImage.sprite = "stretched:session/portraits/" + template.icon; var hero = playerState.heroes[0]; heroButton.onpress = function() { if (!Engine.HotkeyIsPressed("selection.add")) g_Selection.reset(); g_Selection.addList([hero]); }; heroButton.ondoublepress = function() { selectAndMoveTo(getEntityOrHolder(hero)); }; unitHeroPanel.hidden = false; // Setup tooltip var tooltip = "[font=\"serif-bold-16\"]" + template.name.specific + "[/font]"; tooltip += "\n[font=\"serif-bold-13\"]Health:[/font] " + heroState.hitpoints + "/" + heroState.maxHitpoints; tooltip += "\n[font=\"serif-bold-13\"]" + (heroState.attack ? heroState.attack.type + " " : "") + "Attack:[/font] " + damageTypeDetails(heroState.attack); // Show max attack range if ranged attack, also convert to tiles (4m per tile) if (heroState.attack && heroState.attack.type == "Ranged") tooltip += ", [font=\"serif-bold-13\"]Range:[/font] " + Math.round(heroState.attack.maxRange/4); tooltip += "\n[font=\"serif-bold-13\"]Armor:[/font] " + damageTypeDetails(heroState.armour); tooltip += "\n" + template.tooltip; heroButton.tooltip = tooltip; // update heros health bar updateGUIStatusBar("heroHealthBar", heroState.hitpoints, heroState.maxHitpoints); // define the hit points if not defined if (!g_previousHeroHitPoints) g_previousHeroHitPoints = heroState.hitpoints; // check, if the health of the hero changed since the last update if (heroState.hitpoints < g_previousHeroHitPoints) { g_previousHeroHitPoints = heroState.hitpoints; // trigger the animation startColorFade("heroHitOverlay", 100, 0, colorFade_attackUnit, true, smoothColorFadeRestart_attackUnit); return; } } function updateGroups() { var guiName = "Group"; g_Groups.update(); for (var i = 0; i < 10; i++) { var button = Engine.GetGUIObjectByName("unit"+guiName+"Button["+i+"]"); var label = Engine.GetGUIObjectByName("unit"+guiName+"Label["+i+"]").caption = i; if (g_Groups.groups[i].getTotalCount() == 0) button.hidden = true; else button.hidden = false; button.onpress = (function(i) { return function() { performGroup((Engine.HotkeyIsPressed("selection.add") ? "add" : "select"), i); } })(i); button.ondoublepress = (function(i) { return function() { performGroup("snap", i); } })(i); button.onpressright = (function(i) { return function() { performGroup("breakUp", i); } })(i); } var numButtons = i; var rowLength = 1; var numRows = Math.ceil(numButtons / rowLength); var buttonSideLength = Engine.GetGUIObjectByName("unit"+guiName+"Button[0]").size.bottom; var buttonSpacer = buttonSideLength+1; for (var i = 0; i < numRows; i++) layoutButtonRow(i, guiName, buttonSideLength, buttonSpacer, rowLength*i, rowLength*(i+1) ); } function updateDebug() { var simState = GetSimState(); var debug = Engine.GetGUIObjectByName("debug"); if (Engine.GetGUIObjectByName("devDisplayState").checked) { debug.hidden = false; } else { debug.hidden = true; return; } var conciseSimState = deepcopy(simState); conciseSimState.players = "<<>>"; var text = "simulation: " + uneval(conciseSimState); var selection = g_Selection.toList(); if (selection.length) { var entState = GetExtendedEntityState(selection[0]); if (entState) { var template = GetTemplateData(entState.template); text += "\n\nentity: {\n"; for (var k in entState) text += " "+k+":"+uneval(entState[k])+"\n"; text += "}\n\ntemplate: " + uneval(template); } } debug.caption = text; } function updatePlayerDisplay() { var simState = GetSimState(); var playerState = simState.players[Engine.GetPlayerID()]; if (!playerState) return; Engine.GetGUIObjectByName("resourceFood").caption = playerState.resourceCounts.food; Engine.GetGUIObjectByName("resourceWood").caption = playerState.resourceCounts.wood; Engine.GetGUIObjectByName("resourceStone").caption = playerState.resourceCounts.stone; Engine.GetGUIObjectByName("resourceMetal").caption = playerState.resourceCounts.metal; Engine.GetGUIObjectByName("resourcePop").caption = playerState.popCount + "/" + playerState.popLimit; g_IsTrainingBlocked = playerState.trainingBlocked; } function selectAndMoveTo(ent) { var entState = GetEntityState(ent); if (!entState || !entState.position) return; g_Selection.reset(); g_Selection.addList([ent]); var position = entState.position; Engine.CameraMoveTo(position.x, position.z); } function updateResearchDisplay() { var researchStarted = Engine.GuiInterfaceCall("GetStartedResearch", Engine.GetPlayerID()); if (!researchStarted) return; // Set up initial positioning. var buttonSideLength = Engine.GetGUIObjectByName("researchStartedButton[0]").size.right; for (var i = 0; i < 10; ++i) { var button = Engine.GetGUIObjectByName("researchStartedButton[" + i + "]"); var size = button.size; size.top = (4 + buttonSideLength) * i; size.bottom = size.top + buttonSideLength; button.size = size; } var numButtons = 0; for (var tech in researchStarted) { // Show at most 10 in-progress techs. if (numButtons >= 10) break; var template = GetTechnologyData(tech); var button = Engine.GetGUIObjectByName("researchStartedButton[" + numButtons + "]"); button.hidden = false; button.tooltip = getEntityNames(template); button.onpress = (function(e) { return function() { selectAndMoveTo(e) } })(researchStarted[tech].researcher); var icon = "stretched:session/portraits/" + template.icon; Engine.GetGUIObjectByName("researchStartedIcon[" + numButtons + "]").sprite = icon; // Scale the progress indicator. var size = Engine.GetGUIObjectByName("researchStartedProgressSlider[" + numButtons + "]").size; // Buttons are assumed to be square, so left/right offsets can be used for top/bottom. size.top = size.left + Math.round(researchStarted[tech].progress * (size.right - size.left)); Engine.GetGUIObjectByName("researchStartedProgressSlider[" + numButtons + "]").size = size; ++numButtons; } // Hide unused buttons. for (var i = numButtons; i < 10; ++i) Engine.GetGUIObjectByName("researchStartedButton[" + i + "]").hidden = true; } function updateTimeElapsedCounter() { var simState = GetSimState(); var speed = g_CurrentSpeed != 1.0 ? " (" + g_CurrentSpeed + "x)" : ""; var timeElapsedCounter = Engine.GetGUIObjectByName("timeElapsedCounter"); timeElapsedCounter.caption = timeToString(simState.timeElapsed) + speed; } // Toggles the display of status bars for all of the player's entities. function recalculateStatusBarDisplay() { if (g_ShowAllStatusBars) var entities = Engine.PickFriendlyEntitiesOnScreen(Engine.GetPlayerID()); else { var selected = g_Selection.toList(); for each (var ent in g_Selection.highlighted) selected.push(ent); // Remove selected entities from the 'all entities' array, to avoid disabling their status bars. var entities = Engine.GuiInterfaceCall("GetPlayerEntities").filter( function(idx) { return (selected.indexOf(idx) == -1); } ); } Engine.GuiInterfaceCall("SetStatusBars", { "entities": entities, "enabled": g_ShowAllStatusBars }); } // Update the additional list of entities to be highlighted. function updateAdditionalHighlight() { var entsAdd = []; // list of entities units to be highlighted var entsRemove = []; var highlighted = g_Selection.toList(); for each (var ent in g_Selection.highlighted) highlighted.push(ent); if (g_ShowGuarding) { // flag the guarding entities to add in this additional highlight for each (var sel in g_Selection.selected) { var state = GetEntityState(sel); if (!state.guard || !state.guard.entities.length) continue; for each (var ent in state.guard.entities) if (highlighted.indexOf(ent) == -1 && entsAdd.indexOf(ent) == -1) entsAdd.push(ent); } } if (g_ShowGuarded) { // flag the guarded entities to add in this additional highlight for each (var sel in g_Selection.selected) { var state = GetEntityState(sel); if (!state.unitAI || !state.unitAI.isGuarding) continue; var ent = state.unitAI.isGuarding; if (highlighted.indexOf(ent) == -1 && entsAdd.indexOf(ent) == -1) entsAdd.push(ent); } } // flag the entities to remove (from the previously added) from this additional highlight for each (var ent in g_AdditionalHighlight) if (highlighted.indexOf(ent) == -1 && entsAdd.indexOf(ent) == -1 && entsRemove.indexOf(ent) == -1) entsRemove.push(ent); _setHighlight(entsAdd , HIGHLIGHTED_ALPHA, true ); _setHighlight(entsRemove, 0 , false); g_AdditionalHighlight = entsAdd; } // Temporarily adding this here const AMBIENT_TEMPERATE = "temperate"; var currentAmbient; function playRandomAmbient(type) { switch (type) { case AMBIENT_TEMPERATE: // Seem to need the underscore at the end of "temperate" to avoid crash // (Might be caused by trying to randomly load day_temperate.xml) // currentAmbient = newRandomSound("ambient", "temperate_", "dayscape"); const AMBIENT = "audio/ambient/dayscape/day_temperate_gen_03.ogg"; Engine.PlayAmbientSound( AMBIENT, true ); break; default: Engine.Console_Write("Unrecognized ambient type: " + type); break; } } // Temporarily adding this here function stopAmbient() { if (currentAmbient) { currentAmbient.free(); currentAmbient = null; } } // Send a report on the game status to the lobby function reportGame(extendedSimState) { if (!Engine.HasXmppClient()) return; + // units + var unitsClasses = [ + "total", + "Infantry", + "Worker", + "Female", + "Cavalry", + "Champion", + "Hero", + "Ship" + ]; + var unitsCountersTypes = [ + "unitsTrained", + "unitsLost", + "enemyUnitsKilled" + ]; + // buildings + var buildingsClasses = [ + "total", + "CivCentre", + "House", + "Economic", + "Outpost", + "Military", + "Fortress", + "Wonder" + ]; + var buildingsCountersTypes = [ + "buildingsConstructed", + "buildingsLost", + "enemyBuildingsDestroyed" + ]; + // resources + var resourcesTypes = [ + "wood", + "food", + "stone", + "metal" + ]; + var resourcesCounterTypes = [ + "resourcesGathered", + "resourcesUsed", + "resourcesSold", + "resourcesBought" + ]; + - // Resources gathered and used - var playerFoodGatheredString = ""; - var playerWoodGatheredString = ""; - var playerStoneGatheredString = ""; - var playerMetalGatheredString = ""; - var playerFoodUsedString = ""; - var playerWoodUsedString = ""; - var playerStoneUsedString = ""; - var playerMetalUsedString = ""; - // Resources exchanged - var playerFoodBoughtString = ""; - var playerWoodBoughtString = ""; - var playerStoneBoughtString = ""; - var playerMetalBoughtString = ""; - var playerFoodSoldString = ""; - var playerWoodSoldString = ""; - var playerStoneSoldString = ""; - var playerMetalSoldString = ""; - var playerTradeIncomeString = ""; + var playerStatistics = { }; + // Unit Stats - var playerUnitsLostString = ""; - var playerUnitsTrainedString = ""; - var playerEnemyUnitsKilledString = ""; + for each (var unitCounterType in unitsCountersTypes) + { + if (!playerStatistics[unitCounterType]) + playerStatistics[unitCounterType] = { }; + for each (var unitsClass in unitsClasses) + playerStatistics[unitCounterType][unitsClass] = ""; + } + + playerStatistics.unitsLostValue = ""; + playerStatistics.unitsKilledValue = ""; // Building stats - var playerBuildingsConstructedString = ""; - var playerBuildingsLostString = ""; - var playerEnemyBuildingsDestroyedString = ""; - var playerCivCentersBuiltString = ""; - var playerEnemyCivCentersDestroyedString = ""; + for each (var buildingCounterType in buildingsCountersTypes) + { + if (!playerStatistics[buildingCounterType]) + playerStatistics[buildingCounterType] = { }; + for each (var buildingsClass in buildingsClasses) + playerStatistics[buildingCounterType][buildingsClass] = ""; + } + + playerStatistics.buildingsLostValue = ""; + playerStatistics.enemyBuildingsDestroyedValue = ""; + // Resources + for each (var resourcesCounterType in resourcesCounterTypes) + { + if (!playerStatistics[resourcesCounterType]) + playerStatistics[resourcesCounterType] = { }; + for each (var resourcesType in resourcesTypes) + playerStatistics[resourcesCounterType][resourcesType] = ""; + } + playerStatistics.resourcesGathered.vegetarianFood = ""; + + playerStatistics.tradeIncome = ""; // Tribute - var playerTributeSentString = ""; - var playerTributeReceivedString = ""; + playerStatistics.tributesSent = ""; + playerStatistics.tributesReceived = ""; // Various + playerStatistics.treasuresCollected = ""; + playerStatistics.feminisation = ""; + playerStatistics.percentMapExplored = ""; var mapName = Engine.GetMapSettings().Name; - var playerStatesString = ""; - var playerCivsString = ""; - var playerPercentMapExploredString = ""; - var playerTreasuresCollectedString = ""; + var playerStates = ""; + var playerCivs = ""; + var teams = ""; + var teamsLocked = true; // Serialize the statistics for each player into a comma-separated list. for each (var player in extendedSimState.players) { - playerStatesString += player.state + ","; - playerCivsString += player.civ + ","; - playerFoodGatheredString += player.statistics.resourcesGathered.food + ","; - playerWoodGatheredString += player.statistics.resourcesGathered.wood + ","; - playerStoneGatheredString += player.statistics.resourcesGathered.stone + ","; - playerMetalGatheredString += player.statistics.resourcesGathered.metal + ","; - playerFoodUsedString += player.statistics.resourcesUsed.food + ","; - playerWoodUsedString += player.statistics.resourcesUsed.wood + ","; - playerStoneUsedString += player.statistics.resourcesUsed.stone + ","; - playerMetalUsedString += player.statistics.resourcesUsed.metal + ","; - playerUnitsLostString += player.statistics.unitsLost + ","; - playerUnitsTrainedString += player.statistics.unitsTrained + ","; - playerEnemyUnitsKilledString += player.statistics.enemyUnitsKilled + ","; - playerBuildingsConstructedString += player.statistics.buildingsConstructed + ","; - playerBuildingsLostString += player.statistics.buildingsLost + ","; - playerEnemyBuildingsDestroyedString += player.statistics.enemyBuildingsDestroyed + ","; - playerFoodBoughtString += player.statistics.resourcesBought.food + ","; - playerWoodBoughtString += player.statistics.resourcesBought.wood + ","; - playerStoneBoughtString += player.statistics.resourcesBought.stone + ","; - playerMetalBoughtString += player.statistics.resourcesBought.metal + ","; - playerFoodSoldString += player.statistics.resourcesSold.food + ","; - playerWoodSoldString += player.statistics.resourcesSold.wood + ","; - playerStoneSoldString += player.statistics.resourcesSold.stone + ","; - playerMetalSoldString += player.statistics.resourcesSold.metal + ","; - playerTributeSentString += player.statistics.tributesSent + ","; - playerTributeReceivedString += player.statistics.tributesReceived + ","; - playerPercentMapExploredString += player.statistics.precentMapExplored = ","; - playerCivCentersBuiltString += player.statistics.civCentresBuilt + ","; - playerEnemyCivCentersDestroyedString += player.statistics.enemyCivCentresDestroyed + ","; - playerTreasuresCollectedString += player.statistics.treasuresCollected + ","; - playerTradeIncomeString += player.statistics.tradeIncome + ","; + playerStates += player.state + ","; + playerCivs += player.civ + ","; + teams += player.team + ","; + teamsLocked = teamsLocked && player.teamsLocked; + for each (var resourcesCounterType in resourcesCounterTypes) + for each (var resourcesType in resourcesTypes) + playerStatistics[resourcesCounterType][resourcesType] += player.statistics[resourcesCounterType][resourcesType] + ","; + playerStatistics.resourcesGathered.vegetarianFood += player.statistics.resourcesGathered.vegetarianFood + ","; + + for each (var unitCounterType in unitsCountersTypes) + for each (var unitsClass in unitsClasses) + playerStatistics[unitCounterType][unitsClass] += player.statistics[unitCounterType][unitsClass] + ","; + + for each (var buildingCounterType in buildingsCountersTypes) + for each (var buildingsClass in buildingsClasses) + playerStatistics[buildingCounterType][buildingsClass] += player.statistics[buildingCounterType][buildingsClass] + ","; + + playerStatistics.tradeIncome += player.statistics.tradeIncome + ","; + playerStatistics.tributesSent += player.statistics.tributesSent + ","; + playerStatistics.tributesReceived += player.statistics.tributesReceived + ","; + playerStatistics.percentMapExplored += player.statistics.percentMapExplored + ","; + playerStatistics.treasuresCollected += player.statistics.treasuresCollected + ","; } // Send the report with serialized data - Engine.SendGameReport({ - "timeElapsed" : extendedSimState.timeElapsed, - "playerStates" : playerStatesString, - "playerID": Engine.GetPlayerID(), - "matchID": g_MatchID, - "civs" : playerCivsString, - "mapName" : mapName, - "foodGathered": playerFoodGatheredString, - "woodGathered": playerWoodGatheredString, - "stoneGathered": playerStoneGatheredString, - "metalGathered": playerMetalGatheredString, - "foodUsed": playerFoodUsedString, - "woodUsed": playerWoodUsedString, - "stoneUsed": playerStoneUsedString, - "metalUsed": playerMetalUsedString, - "unitsLost": playerUnitsLostString, - "unitsTrained": playerUnitsTrainedString, - "enemyUnitsKilled": playerEnemyUnitsKilledString, - "buildingsLost": playerBuildingsLostString, - "buildingsConstructed": playerBuildingsConstructedString, - "enemyBuildingsDestroyed": playerEnemyBuildingsDestroyedString, - "foodBought": playerFoodBoughtString, - "woodBought": playerWoodBoughtString, - "stoneBought": playerStoneBoughtString, - "metalBought": playerMetalBoughtString, - "foodSold": playerFoodSoldString, - "woodSold": playerWoodSoldString, - "stoneSold": playerStoneSoldString, - "metalSold": playerMetalSoldString, - "tributeSent": playerTributeSentString, - "tributeReceived": playerTributeReceivedString, - "precentMapExplored": playerPercentMapExploredString, - "civCentersBuilt": playerCivCentersBuiltString, - "enemyCivCentersDestroyed": playerEnemyCivCentersDestroyedString, - "treasuresCollected": playerTreasuresCollectedString, - "tradeIncome": playerTradeIncomeString - }); + var reportObject = { }; + reportObject.timeElapsed = extendedSimState.timeElapsed; + reportObject.playerStates = playerStates; + reportObject.playerID = Engine.GetPlayerID(); + reportObject.matchID = g_MatchID; + reportObject.civs = playerCivs; + reportObject.teams = teams; + reportObject.teamsLocked = teamsLocked; + reportObject.mapName = mapName; + for each (var rct in resourcesCounterTypes) + { + for each (var rt in resourcesTypes) + reportObject[rt+rct.substr(9)] = playerStatistics[rct][rt]; + // eg. rt = food rct.substr = Gathered rct = resourcesGathered + } + reportObject.vegetarianFoodGathered = playerStatistics.resourcesGathered.vegetarianFood; + for each (var type in unitsClasses) + { + // eg. type = Infantry (type.substr(0,1)).toLowerCase()+type.substr(1) = infantry + reportObject[(type.substr(0,1)).toLowerCase()+type.substr(1)+"UnitsTrained"] = playerStatistics.unitsTrained[type]; + reportObject[(type.substr(0,1)).toLowerCase()+type.substr(1)+"UnitsLost"] = playerStatistics.unitsLost[type]; + reportObject["enemy"+type+"UnitsKilled"] = playerStatistics.enemyUnitsKilled[type]; + } + for each (var type in buildingsClasses) + { + reportObject[(type.substr(0,1)).toLowerCase()+type.substr(1)+"BuildingsConstructed"] = playerStatistics.buildingsConstructed[type]; + reportObject[(type.substr(0,1)).toLowerCase()+type.substr(1)+"BuildingsLost"] = playerStatistics.buildingsLost[type]; + reportObject["enemy"+type+"BuildingsDestroyed"] = playerStatistics.enemyBuildingsDestroyed[type]; + } + reportObject.tributesSent = playerStatistics.tributesSent; + reportObject.tributesReceived = playerStatistics.tributesReceived; + reportObject.precentMapExplored = playerStatistics.percentMapExplored; + reportObject.treasuresCollected = playerStatistics.treasuresCollected; + reportObject.tradeIncome = playerStatistics.tradeIncome; + + Engine.SendGameReport(reportObject); } + + Index: ps/trunk/binaries/data/mods/public/gui/summary/summary.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/summary/summary.js (revision 14702) +++ ps/trunk/binaries/data/mods/public/gui/summary/summary.js (revision 14703) @@ -1,311 +1,830 @@ // Max player slots for any map (should read from config) const MAX_SLOTS = 8; -var panelNames = [ 'scorePanel', 'unitsBuildingsPanel', 'conquestPanel', 'resourcesPanel', 'marketPanel' ]; -var panelButtonNames = [ 'scorePanelButton', 'unitsBuildingsPanelButton', 'conquestPanelButton', 'resourcesPanelButton', 'marketPanelButton' ]; - /** * Select active panel * @param panelNumber Number of panel, which should get active state (integer) */ function selectPanel(panelNumber) { + var panelNames = [ 'scorePanel', 'buildingsPanel', 'unitsPanel', 'resourcesPanel', 'marketPanel', 'miscPanel' ]; + + function adjustTabDividers(tabSize) + { + var leftSpacer = Engine.GetGUIObjectByName("tabDividerLeft"); + var rightSpacer = Engine.GetGUIObjectByName("tabDividerRight"); + leftSpacer.size = "20 " + leftSpacer.size.top + " " + (tabSize.left + 2) + " " + leftSpacer.size.bottom; + rightSpacer.size = (tabSize.right - 2) + " " + rightSpacer.size.top + " 100%-20 " + rightSpacer.size.bottom; + } + for (var i = 0; i < panelNames.length; i++) { if (i != panelNumber) { Engine.GetGUIObjectByName(panelNames[i]).hidden = true; - Engine.GetGUIObjectByName(panelButtonNames[i]).sprite = "BackgroundTab"; + Engine.GetGUIObjectByName(panelNames[i] + 'Button').sprite = "BackgroundTab"; } else { Engine.GetGUIObjectByName(panelNames[i]).hidden = false; - Engine.GetGUIObjectByName(panelButtonNames[i]).sprite = "ForegroundTab"; - adjustTabDividers(Engine.GetGUIObjectByName(panelButtonNames[i]).size); + Engine.GetGUIObjectByName(panelNames[i] + 'Button').sprite = "ForegroundTab"; + adjustTabDividers(Engine.GetGUIObjectByName(panelNames[i] + 'Button').size); } } } -function adjustTabDividers(tabSize) -{ - var leftSpacer = Engine.GetGUIObjectByName("tabDividerLeft"); - var rightSpacer = Engine.GetGUIObjectByName("tabDividerRight"); - leftSpacer.size = "20 " + leftSpacer.size.top + " " + (tabSize.left + 2) + " " + leftSpacer.size.bottom; - rightSpacer.size = (tabSize.right - 2) + " " + rightSpacer.size.top + " 100%-20 " + rightSpacer.size.bottom; -} - function init(data) { + // LOCAL CONSTS, VARIABLES & FUNCTIONS + // const for filtering long collective headings + const LONG_HEADING_WIDTH = 250; + // number of panels + const PANELS_COUNT = 6; + // alpha for player box + const PLAYER_BOX_ALPHA = " 32"; + // alpha for player colour box + const PLAYER_COLOUR_BOX_ALPHA = " 255"; + // yStart value for spaceing teams boxes (and noTeamsBox) + const TEAMS_BOX_Y_START = 65; + // vertical size of player box + const PLAYER_BOX_Y_SIZE = 30; + // gap between players boxes + const PLAYER_BOX_GAP = 2; + + // colours used for units and buildings + const TRAINED_COLOR = '[color="201 255 200"]'; + const LOST_COLOR = '[color="255 213 213"]'; + const KILLED_COLOR = '[color="196 198 255"]'; + + // colours used for gathered and traded resources + const INCOME_COLOR = '[color="201 255 200"]'; + const OUTCOME_COLOR = '[color="255 213 213"]'; + + const BUILDINGS_TYPES = [ "total", "House", "Economic", "Outpost", "Military", "Fortress", "CivCentre", "Wonder" ]; + const UNITS_TYPES = [ "total", "Infantry", "Worker", "Cavalry", "Champion", "Hero", "Ship" ]; + const RESOURCES_TYPES = [ "food", "wood", "stone", "metal" ]; + + var panels = { + "score": { // score panel + "headings": { // headings on score panel + "playerName0Heading": { "yStart": 26, "width": 200 }, + "economyScoreHeading": { "yStart": 16, "width": 100 }, + "militaryScoreHeading": { "yStart": 16, "width": 100 }, + "explorationScoreHeading": { "yStart": 16, "width": 100 }, + "totalScoreHeading": { "yStart": 16, "width": 100 } + }, + "counters": { // counters on score panel + "economyScore": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "militaryScore": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "explorationScore": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "totalScore": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] } + } + }, + "buildings": { // buildings panel + "headings": { // headings on buildings panel + "playerName1Heading": {"yStart": 26, "width": 200 }, + "buildingsHeading": {"yStart": 16, "width": (85 * 7 + 105) }, // width = 735 + "totalBuildingsHeading": {"yStart": 34, "width": 105 }, + "houseBuildingsHeading": {"yStart": 34, "width": 85 }, + "economicBuildingsHeading": {"yStart": 34, "width": 85 }, + "outpostBuildingsHeading": {"yStart": 34, "width": 85 }, + "militaryBuildingsHeading": {"yStart": 34, "width": 85 }, + "fortressBuildingsHeading": {"yStart": 34, "width": 85 }, + "civCentreBuildingsHeading": {"yStart": 34, "width": 85 }, + "wonderBuildingsHeading": {"yStart": 34, "width": 85 } + }, + "counters": { // counters on buildings panel + "totalBuildings": {"width": 105, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "houseBuildings": {"width": 85, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "economicBuildings": {"width": 85, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "outpostBuildings": {"width": 85, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "militaryBuildings": {"width": 85, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "fortressBuildings": {"width": 85, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "civCentreBuildings": {"width": 85, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "wonderBuildings": {"width": 85, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] } + } + }, + "units": { // units panel + "headings": { // headings on units panel + "playerName2Heading": {"yStart": 26, "width": 200 }, + "unitsHeading": {"yStart": 16, "width": (100 * 6 + 120) }, // width = 720 + "totalUnitsHeading": {"yStart": 34, "width": 120 }, + "infantryUnitsHeading": {"yStart": 34, "width": 100 }, + "workerUnitsHeading": {"yStart": 34, "width": 100 }, + "cavalryUnitsHeading": {"yStart": 34, "width": 100 }, + "championUnitsHeading": {"yStart": 34, "width": 100 }, + "heroesUnitsHeading": {"yStart": 34, "width": 100 }, + "navyUnitsHeading": {"yStart": 34, "width": 100 } + }, + "counters": { // counters on units panel + "totalUnits": {"width": 120, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "infantryUnits": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "workerUnits": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "cavalryUnits": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "championUnits": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "heroesUnits": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "navyUnits": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] } + } + }, + "resources": { // resources panel + "headings": { // headings on resources panel + "playerName3Heading": {"yStart": 26, "width": 200 }, + "resourceHeading": {"yStart": 16, "width": (100 * 4 + 110) },//width = 510 + "foodGatheredHeading": {"yStart": 34, "width": 100 }, + "woodGatheredHeading": {"yStart": 34, "width": 100 }, + "stoneGatheredHeading": {"yStart": 34, "width": 100 }, + "metalGatheredHeading": {"yStart": 34, "width": 100 }, + "totalGatheredHeading": {"yStart": 34, "width": 110 }, + "treasuresCollectedHeading": {"yStart": 16, "width": 100 }, + "resourcesTributedHeading": {"yStart": 16, "width": 121 } + }, + "counters": { // counters on resources panel + "foodGathered": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "woodGathered": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "stoneGathered": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "metalGathered": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "totalGathered": {"width": 110, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "treasuresCollected": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "resourcesTributed": {"width": 121, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] } + } + }, + "market": { // market panel + "headings": { // headings on market panel + "playerName4Heading": {"yStart": 26, "width": 200 }, + "exchangedFoodHeading": {"yStart": 16, "width": 100 }, + "exchangedWoodHeading": {"yStart": 16, "width": 100 }, + "exchangedStoneHeading": {"yStart": 16, "width": 100 }, + "exchangedMetalHeading": {"yStart": 16, "width": 100 }, + "barterEfficiencyHeading": {"yStart": 16, "width": 100 }, + "tradeIncomeHeading": {"yStart": 16, "width": 100 } + }, + "counters": { // counters on market panel + "exchangedFood": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "exchangedWood": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "exchangedStone": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "exchangedMetal": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "barterEfficiency": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "tradeIncome": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] } + } + }, + "miscelanous": { // miscelanous panel + "headings": { // headings on miscelanous panel + "playerName5Heading": {"yStart": 26, "width": 200 }, + "vegetarianRatioHeading": {"yStart": 16, "width": 100 }, + "feminisationHeading": {"yStart": 26, "width": 100 }, + "killDeathRatioHeading": {"yStart": 16, "width": 100 }, + "mapExplorationHeading": {"yStart": 16, "width": 100 } + }, + "counters": { // counters on miscelanous panel + "vegetarianRatio": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "feminisation": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "killDeathRatio": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] }, + "mapExploration": {"width": 100, "objects": [ ], "teamsScores": [ ], "teamsScoresCaption": [ ] } + } + } + }; + + function alignHeaders(headings) + { + left = 50; + for (var h in headings) + { + Engine.GetGUIObjectByName(h).size = left + " " + headings[h].yStart + " " + (left + headings[h].width) + " 100%"; + if (headings[h].width < LONG_HEADING_WIDTH) + left += headings[h].width; + } + } + + function alignCounters(counters, player) + { + left = 240; + for each (var counter in counters) + { + counter.objects[player].size = left + " 2 " + (left + counter.width) + " 100%"; + left += counter.width; + } + + return left; + } + + // caption counters functions + function captionEconomyScore() + { + var total = 0; + for each (var res in playerState.statistics.resourcesGathered) + total += res; + + return Math.round(total / 10); + } + + function captionBuildings(object, type) + { + object.caption = TRAINED_COLOR + playerState.statistics.buildingsConstructed[type] + '[/color] / ' + + LOST_COLOR + playerState.statistics.buildingsLost[type] + '[/color] / ' + + KILLED_COLOR + playerState.statistics.enemyBuildingsDestroyed[type] + '[/color]'; + } + + function captionUnits(object, type) + { + object.caption = TRAINED_COLOR + playerState.statistics.unitsTrained[type] + '[/color] / ' + + LOST_COLOR + playerState.statistics.unitsLost[type] + '[/color] / ' + + KILLED_COLOR + playerState.statistics.enemyUnitsKilled[type] + '[/color]'; + } + + function captionResourcesGathered(object, type) + { + object.caption = INCOME_COLOR + playerState.statistics.resourcesGathered[type] + '[/color] / ' + + OUTCOME_COLOR + (playerState.statistics.resourcesUsed[type] - playerState.statistics.resourcesSold[type]) + '[/color]'; + } + + function captionTotalResourcesGathered() + { + var totalGathered = 0; + var totalUsed = 0; + + for each (var type in RESOURCES_TYPES) + { + totalGathered += playerState.statistics.resourcesGathered[type]; + totalUsed += playerState.statistics.resourcesUsed[type] - playerState.statistics.resourcesSold[type]; + } + + return INCOME_COLOR + totalGathered + '[/color] / ' + OUTCOME_COLOR + totalUsed + '[/color]'; + } + + function captionResourcesTributed() + { + return INCOME_COLOR + playerState.statistics.tributesSent + "[/color] / " + OUTCOME_COLOR + playerState.statistics.tributesReceived + "[/color]"; + } + + function captionResourcesExchanged(object, type) + { + object.caption = INCOME_COLOR + '+' + playerState.statistics.resourcesBought[type] + '[/color] ' + + OUTCOME_COLOR + '-' + playerState.statistics.resourcesSold[type] + '[/color]'; + } + + function captionBarterEfficiency() + { + var totalBought = 0; + for each (var boughtAmount in playerState.statistics.resourcesBought) + totalBought += boughtAmount; + var totalSold = 0; + for each (var soldAmount in playerState.statistics.resourcesSold) + totalSold += soldAmount; + + return Math.floor(totalSold > 0 ? (totalBought / totalSold) * 100 : 0) + "%"; + } + + function captionVegetarianRatio() + { + if (playerState.statistics.resourcesGathered.vegetarianFood && playerState.statistics.resourcesGathered.food) + return Math.floor((playerState.statistics.resourcesGathered.vegetarianFood / playerState.statistics.resourcesGathered.food) * 100) + "%"; + else + return 0 + "%"; + } + + function captionFeminisation() + { + if (playerState.statistics.unitsTrained.Worker && playerState.statistics.unitsTrained.Female) + return Math.floor((playerState.statistics.unitsTrained.Female / playerState.statistics.unitsTrained.Worker) * 100) + "%"; + else + return 0 + "%"; + } + + function captionKillDeathRatio() + { + if (!playerState.statistics.enemyUnitsKilled.total) + return "0.00"; + if (!playerState.statistics.unitsLost.total) // and enemyUnitsKilled.total > 0 + return "\u221E"; // infinity symbol + return Math.round((playerState.statistics.enemyUnitsKilled.total / playerState.statistics.unitsLost.total)*100)/100; + } + + function sumTeamBuildings(counter, type) + { + if (counter.teamsScores[playerState.team] == 0) + { + counter.teamsScores[playerState.team] = { }; + counter.teamsScores[playerState.team].buildingsConstructed = 0; + counter.teamsScores[playerState.team].buildingsLost = 0; + counter.teamsScores[playerState.team].enemyBuildingsDestroyed = 0; + } + + counter.teamsScores[playerState.team].buildingsConstructed += playerState.statistics.buildingsConstructed[type]; + counter.teamsScores[playerState.team].buildingsLost += playerState.statistics.buildingsLost[type]; + counter.teamsScores[playerState.team].enemyBuildingsDestroyed += playerState.statistics.enemyBuildingsDestroyed[type]; + + counter.teamsScoresCaption[playerState.team] = TRAINED_COLOR + counter.teamsScores[playerState.team].buildingsConstructed + '[/color] / ' + + LOST_COLOR + counter.teamsScores[playerState.team].buildingsLost + '[/color] / ' + + KILLED_COLOR + counter.teamsScores[playerState.team].enemyBuildingsDestroyed + '[/color]'; + } + + function sumTeamUnits(counter, type) + { + if (counter.teamsScores[playerState.team] == 0) + { + counter.teamsScores[playerState.team] = { }; + counter.teamsScores[playerState.team].unitsTrained = 0; + counter.teamsScores[playerState.team].unitsLost = 0; + counter.teamsScores[playerState.team].enemyUnitsKilled = 0; + } + + counter.teamsScores[playerState.team].unitsTrained += playerState.statistics.unitsTrained[type]; + counter.teamsScores[playerState.team].unitsLost += playerState.statistics.unitsLost[type]; + counter.teamsScores[playerState.team].enemyUnitsKilled += playerState.statistics.enemyUnitsKilled[type]; + + counter.teamsScoresCaption[playerState.team] = TRAINED_COLOR + counter.teamsScores[playerState.team].unitsTrained + '[/color] / ' + + LOST_COLOR + counter.teamsScores[playerState.team].unitsLost + '[/color] / ' + + KILLED_COLOR + counter.teamsScores[playerState.team].enemyUnitsKilled + '[/color]'; + } + + function sumResourcesGathered(counter, type) + { + if (counter.teamsScores[playerState.team] == 0) + { + counter.teamsScores[playerState.team] = { }; + counter.teamsScores[playerState.team].resourcesGathered = 0; + counter.teamsScores[playerState.team].resourcesUsed = 0; + } + + counter.teamsScores[playerState.team].resourcesGathered += playerState.statistics.resourcesGathered[type]; + counter.teamsScores[playerState.team].resourcesUsed += playerState.statistics.resourcesUsed[type] - playerState.statistics.resourcesSold[type]; + + counter.teamsScoresCaption[playerState.team] = INCOME_COLOR + counter.teamsScores[playerState.team].resourcesGathered + '[/color] / ' + + OUTCOME_COLOR + counter.teamsScores[playerState.team].resourcesUsed + '[/color]'; + } + + function sumTotalResourcesGathered() + { + if (panels.resources.counters.totalGathered.teamsScores[playerState.team] == 0) + { + panels.resources.counters.totalGathered.teamsScores[playerState.team] = { }; + panels.resources.counters.totalGathered.teamsScores[playerState.team].resourcesGathered = 0; + panels.resources.counters.totalGathered.teamsScores[playerState.team].resourcesUsed = 0; + } + + for each (var type in RESOURCES_TYPES) + { + panels.resources.counters.totalGathered.teamsScores[playerState.team].resourcesGathered += playerState.statistics.resourcesGathered[type]; + panels.resources.counters.totalGathered.teamsScores[playerState.team].resourcesUsed += + playerState.statistics.resourcesUsed[type] - playerState.statistics.resourcesSold[type]; + } + + panels.resources.counters.totalGathered.teamsScoresCaption[playerState.team] = + INCOME_COLOR + panels.resources.counters.totalGathered.teamsScores[playerState.team].resourcesGathered + '[/color] / ' + + OUTCOME_COLOR + panels.resources.counters.totalGathered.teamsScores[playerState.team].resourcesUsed + '[/color]'; + } + + function sumResourcesTributed() + { + if (panels.resources.counters.resourcesTributed.teamsScores[playerState.team] == 0) + { + panels.resources.counters.resourcesTributed.teamsScores[playerState.team] = { }; + panels.resources.counters.resourcesTributed.teamsScores[playerState.team].tributesSent = 0; + panels.resources.counters.resourcesTributed.teamsScores[playerState.team].tributesReceived = 0; + } + + panels.resources.counters.resourcesTributed.teamsScores[playerState.team].tributesSent += playerState.statistics.tributesSent; + panels.resources.counters.resourcesTributed.teamsScores[playerState.team].tributesReceived += playerState.statistics.tributesReceived; + + panels.resources.counters.resourcesTributed.teamsScoresCaption[playerState.team] = + INCOME_COLOR + panels.resources.counters.resourcesTributed.teamsScores[playerState.team].tributesSent + "[/color] / " + + OUTCOME_COLOR + panels.resources.counters.resourcesTributed.teamsScores[playerState.team].tributesReceived + "[/color]"; + } + + function sumResourcesExchanged(counter, type) + { + if (counter.teamsScores[playerState.team] == 0) + { + counter.teamsScores[playerState.team] = { }; + counter.teamsScores[playerState.team].resourcesBought = 0; + counter.teamsScores[playerState.team].resourcesSold = 0; + } + + counter.teamsScores[playerState.team].resourcesBought += playerState.statistics.resourcesBought[type]; + counter.teamsScores[playerState.team].resourcesSold += playerState.statistics.resourcesSold[type]; + + counter.teamsScoresCaption[playerState.team] = + INCOME_COLOR + '+' + counter.teamsScores[playerState.team].resourcesBought + '[/color] ' + + OUTCOME_COLOR + '-' + counter.teamsScores[playerState.team].resourcesSold + '[/color]'; + } + + function sumBarterEfficiency() + { + if (panels.market.counters.barterEfficiency.teamsScores[playerState.team] == 0) + { + panels.market.counters.barterEfficiency.teamsScores[playerState.team] = { }; + panels.market.counters.barterEfficiency.teamsScores[playerState.team].resourcesBought = 0; + panels.market.counters.barterEfficiency.teamsScores[playerState.team].resourcesSold = 0; + } + + for each (var boughtAmount in playerState.statistics.resourcesBought) + panels.market.counters.barterEfficiency.teamsScores[playerState.team].resourcesBought += boughtAmount; + for each (var soldAmount in playerState.statistics.resourcesSold) + panels.market.counters.barterEfficiency.teamsScores[playerState.team].resourcesSold += soldAmount; + + panels.market.counters.barterEfficiency.teamsScoresCaption[playerState.team] = + Math.floor(panels.market.counters.barterEfficiency.teamsScores[playerState.team].resourcesSold > 0 ? + (panels.market.counters.barterEfficiency.teamsScores[playerState.team].resourcesBought / + panels.market.counters.barterEfficiency.teamsScores[playerState.team].resourcesSold) * 100 : 0) + "%"; + } + + function sumVegetarianRatio() + { + if (panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team] == 0) + { + panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team] = { }; + panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team].vegetarianFood = 0; + panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team].food = 0; + } + + panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team].vegetarianFood += playerState.statistics.resourcesGathered.vegetarianFood; + panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team].food += playerState.statistics.resourcesGathered.food; + + if (panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team].food && + panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team].vegetarianFood) + { + panels.miscelanous.counters.vegetarianRatio.teamsScoresCaption[playerState.team] = + Math.floor((panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team].vegetarianFood / + panels.miscelanous.counters.vegetarianRatio.teamsScores[playerState.team].food) * 100) + "%"; + return; + } + panels.miscelanous.counters.vegetarianRatio.teamsScoresCaption[playerState.team] = 0 + "%"; + } + + function sumFeminisation() + { + if (panels.miscelanous.counters.feminisation.teamsScores[playerState.team] == 0) + { + panels.miscelanous.counters.feminisation.teamsScores[playerState.team] = { }; + panels.miscelanous.counters.feminisation.teamsScores[playerState.team].femalesTrained = 0; + panels.miscelanous.counters.feminisation.teamsScores[playerState.team].workersTrained = 0; + } + + panels.miscelanous.counters.feminisation.teamsScores[playerState.team].femalesTrained += playerState.statistics.unitsTrained.Female; + panels.miscelanous.counters.feminisation.teamsScores[playerState.team].workersTrained += playerState.statistics.unitsTrained.Worker; + + if (panels.miscelanous.counters.feminisation.teamsScores[playerState.team].femalesTrained && + panels.miscelanous.counters.feminisation.teamsScores[playerState.team].workersTrained) + { + panels.miscelanous.counters.feminisation.teamsScoresCaption[playerState.team] = + Math.floor((panels.miscelanous.counters.feminisation.teamsScores[playerState.team].femalesTrained / + panels.miscelanous.counters.feminisation.teamsScores[playerState.team].workersTrained) * 100) + "%"; + return; + } + panels.miscelanous.counters.feminisation.teamsScoresCaption[playerState.team] = 0 + "%"; + } + + function sumKillDeathRatio() + { + if (panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team] == 0) + { + panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team] = { }; + panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team].enemyUnitsKilled = 0; + panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team].unitsLost = 0; + } + + panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team].enemyUnitsKilled += playerState.statistics.enemyUnitsKilled.total; + panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team].unitsLost += playerState.statistics.unitsLost.total; + + if (!panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team].enemyUnitsKilled) + { + panels.miscelanous.counters.killDeathRatio.teamsScoresCaption[playerState.team] = "0.00"; + return; + } + if (!panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team].unitsLost) + { + panels.miscelanous.counters.killDeathRatio.teamsScoresCaption[playerState.team] = "\u221E"; // infinity symbol + return; + } + panels.miscelanous.counters.killDeathRatio.teamsScoresCaption[playerState.team] = + Math.round((panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team].enemyUnitsKilled / + panels.miscelanous.counters.killDeathRatio.teamsScores[playerState.team].unitsLost) * 100)/100; + } + + // FUNCTION BODY + // Load data var civData = loadCivData(); + // Map var mapSize = "Scenario"; Engine.GetGUIObjectByName("timeElapsed").caption = "Time elapsed: " + timeToString(data.timeElapsed); Engine.GetGUIObjectByName("summaryText").caption = data.gameResult; // This is only defined for random maps if (data.mapSettings.Size) { // load the map sizes from the JSON file var mapSizes = initMapSizes(); // retrieve the index of the map size for (var mapSizeIndex in mapSizes.tiles) { if (mapSizes.tiles[mapSizeIndex] == data.mapSettings.Size) { mapSize = mapSizes.names[mapSizeIndex]; break; } } } Engine.GetGUIObjectByName("mapName").caption = data.mapSettings.Name + " - " + mapSize; - - // Space player boxes - var boxSpacing = 32; - for (var i = 0; i < panelNames.length; ++i) - { - for (var j = 0; j < MAX_SLOTS; ++j) - { - var box = Engine.GetGUIObjectByName("playerBox"+i+"["+j+"]"); - var boxSize = box.size; - var h = boxSize.bottom - boxSize.top; - boxSize.top = j * boxSpacing; - boxSize.bottom = j * boxSpacing + h; - box.size = boxSize; - } - } + + // Panels + // Align headers + var left = 50; + for each (var panel in panels) // for all panels + alignHeaders(panel.headings); // TODO set maxPlayers as playerCounters.length var maxPlayers = data.playerStates.length - 1; + var maxTeams = 0; - // Align headers - var left = 50; - var width = 100; - var playerNameHeadingWidth = 200; - // Special cased to make the (Sent / Received) part fit - var tributesWidth = 121; - Engine.GetGUIObjectByName("playerName0Heading").size = left + " 26 " + (left + playerNameHeadingWidth) + " 100%"; left += playerNameHeadingWidth; - Engine.GetGUIObjectByName("economyScoreHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("militaryScoreHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("explorationScoreHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("totalScoreHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - - left = 50; - Engine.GetGUIObjectByName("playerName1Heading").size = left + " 26 " + (left + playerNameHeadingWidth) + " 100%"; left += playerNameHeadingWidth; - Engine.GetGUIObjectByName("unitsTrainedHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("unitsLostHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("enemyUnitsKilledHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("buildingsConstructedHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("buildingsLostHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("enemyBuildingsDestroyedHeading").size = left + " 6 " + (left + width) + " 100%"; left += width; - - left = 50; - Engine.GetGUIObjectByName("playerName2Heading").size = left + " 26 " + (left + playerNameHeadingWidth) + " 100%"; left += playerNameHeadingWidth; - Engine.GetGUIObjectByName("civCentresBuiltHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("enemyCivCentresDestroyedHeading").size = left + " 6 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("mapExplorationHeading").size = left + " 6 " + (left + width) + " 100%"; left += width; - - left = 50; - Engine.GetGUIObjectByName("playerName3Heading").size = left + " 26 " + (left + playerNameHeadingWidth) + " 100%"; left += playerNameHeadingWidth; - Engine.GetGUIObjectByName("resourceHeading").size = left + " 16 " + (left + width * 4) + " 100%"; - Engine.GetGUIObjectByName("foodGatheredHeading").size = left + " 34 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("woodGatheredHeading").size = left + " 34 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("stoneGatheredHeading").size = left + " 34 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("metalGatheredHeading").size = left + " 34 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("vegetarianRatioHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("treasuresCollectedHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("resourcesTributedHeading").size = left + " 16 " + (left + tributesWidth) + " 100%"; left += tributesWidth; - - left = 50; - Engine.GetGUIObjectByName("playerName4Heading").size = left + " 26 " + (left + playerNameHeadingWidth) + " 100%"; left += playerNameHeadingWidth; - Engine.GetGUIObjectByName("exchangedFoodHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("exchangedWoodHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("exchangedStoneHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("exchangedMetalHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("barterEfficiencyHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - Engine.GetGUIObjectByName("tradeIncomeHeading").size = left + " 16 " + (left + width) + " 100%"; left += width; - - // Show counters - for (var i = 0; i < MAX_SLOTS; ++i) + var teams = [ ]; + if (data.mapSettings.LockTeams) // teams ARE locked { - if (i < maxPlayers) + // count teams + for(var t = 0; t < maxPlayers; ++t) { - var playerState = data.playerStates[i+1]; - - for (var k = 0; k < panelNames.length; ++k) + if (!teams[data.playerStates[t+1].team]) { - var playerBox = Engine.GetGUIObjectByName("playerBox"+k+"["+i+"]"); - playerBox.hidden = false; - - var colourString = "colour: " - + Math.floor(playerState.colour.r * 255) + " " - + Math.floor(playerState.colour.g * 255) + " " - + Math.floor(playerState.colour.b * 255); - playerBox.sprite = colourString + " 32"; - var playerColourBox = Engine.GetGUIObjectByName("playerColourBox"+k+"["+i+"]"); - playerColourBox.sprite = colourString + " 255"; - - // Show the multiplayer name, e.g. "Foobar" rather than "Player 1". - // TODO: Perhaps show both the multiplayer and map-specific name? - var playerName = Engine.GetGUIObjectByName("playerName"+k+"["+i+"]"); - playerName.caption = data.players[i+1].name; - - Engine.GetGUIObjectByName("civIcon"+k+"["+i+"]").sprite = "stretched:"+civData[playerState.civ].Emblem; - Engine.GetGUIObjectByName("civIcon"+k+"["+i+"]").tooltip = civData[playerState.civ].Name; - } - - var economyScore = Engine.GetGUIObjectByName("economyScore["+i+"]"); - var militaryScore = Engine.GetGUIObjectByName("militaryScore["+i+"]"); - var explorationScore = Engine.GetGUIObjectByName("explorationScore["+i+"]"); - var totalScore = Engine.GetGUIObjectByName("totalScore["+i+"]"); - - var unitsTrained = Engine.GetGUIObjectByName("unitsTrained["+i+"]"); - var unitsLost = Engine.GetGUIObjectByName("unitsLost["+i+"]"); - var enemyUnitsKilled = Engine.GetGUIObjectByName("enemyUnitsKilled["+i+"]"); - var buildingsConstructed = Engine.GetGUIObjectByName("buildingsConstructed["+i+"]"); - var buildingsLost = Engine.GetGUIObjectByName("buildingsLost["+i+"]"); - var enemyBuildingsDestroyed = Engine.GetGUIObjectByName("enemyBuildingsDestroyed["+i+"]"); - - var civCentresBuilt = Engine.GetGUIObjectByName("civCentresBuilt["+i+"]"); - var enemyCivCentresDestroyed = Engine.GetGUIObjectByName("enemyCivCentresDestroyed["+i+"]"); - var mapExploration = Engine.GetGUIObjectByName("mapExploration["+i+"]"); - - var foodGathered = Engine.GetGUIObjectByName("foodGathered["+i+"]"); - var woodGathered = Engine.GetGUIObjectByName("woodGathered["+i+"]"); - var stoneGathered = Engine.GetGUIObjectByName("stoneGathered["+i+"]"); - var metalGathered = Engine.GetGUIObjectByName("metalGathered["+i+"]"); - var vegetarianRatio = Engine.GetGUIObjectByName("vegetarianRatio["+i+"]"); - var treasuresCollected = Engine.GetGUIObjectByName("treasuresCollected["+i+"]"); - var resourcesTributed = Engine.GetGUIObjectByName("resourcesTributed["+i+"]"); - - var exchangedFood = Engine.GetGUIObjectByName("exchangedFood["+i+"]"); - var exchangedWood = Engine.GetGUIObjectByName("exchangedWood["+i+"]"); - var exchangedStone = Engine.GetGUIObjectByName("exchangedStone["+i+"]"); - var exchangedMetal = Engine.GetGUIObjectByName("exchangedMetal["+i+"]"); - var barterEfficiency = Engine.GetGUIObjectByName("barterEfficiency["+i+"]"); - var tradeIncome = Engine.GetGUIObjectByName("tradeIncome["+i+"]"); - - // align counters - - left = 240; - width = 100; - economyScore.size = left + " 2 " + (left + width) + " 100%"; left += width; - militaryScore.size = left + " 2 " + (left + width) + " 100%"; left += width; - explorationScore.size = left + " 2 " + (left + width) + " 100%"; left += width; - totalScore.size = left + " 2 " + (left + width) + " 100%"; left += width; - var size = Engine.GetGUIObjectByName("playerBox0["+i+"]").size; - size.right = left + 10; - Engine.GetGUIObjectByName("playerBox0["+i+"]").size = size; - - left = 240; - unitsTrained.size = left + " 2 " + (left + width) + " 100%"; left += width; - unitsLost.size = left + " 2 " + (left + width) + " 100%"; left += width; - enemyUnitsKilled.size = left + " 2 " + (left + width) + " 100%"; left += width; - buildingsConstructed.size = left + " 2 " + (left + width) + " 100%"; left += width; - buildingsLost.size = left + " 2 " + (left + width) + " 100%"; left += width; - enemyBuildingsDestroyed.size = left + " 2 " + (left + width) + " 100%"; left += width; - size = Engine.GetGUIObjectByName("playerBox1["+i+"]").size; - size.right = left + 10; - Engine.GetGUIObjectByName("playerBox1["+i+"]").size = size; - - left = 240; - civCentresBuilt.size = left + " 2 " + (left + width) + " 100%"; left += width; - enemyCivCentresDestroyed.size = left + " 2 " + (left + width) + " 100%"; left += width; - mapExploration.size = left + " 2 " + (left + width) + " 100%"; left += width; - size = Engine.GetGUIObjectByName("playerBox2["+i+"]").size; - size.right = left + 10; - Engine.GetGUIObjectByName("playerBox2["+i+"]").size = size; - - left = 240; - foodGathered.size = left + " 2 " + (left + width) + " 100%"; left += width; - woodGathered.size = left + " 2 " + (left + width) + " 100%"; left += width; - stoneGathered.size = left + " 2 " + (left + width) + " 100%"; left += width; - metalGathered.size = left + " 2 " + (left + width) + " 100%"; left += width; - vegetarianRatio.size = left + " 2 " + (left + width) + " 100%"; left += width; - treasuresCollected.size = left + " 2 " + (left + width) + " 100%"; left += width; - resourcesTributed.size = left + " 2 " + (left + tributesWidth) + " 100%"; left += tributesWidth; - size = Engine.GetGUIObjectByName("playerBox3["+i+"]").size; - size.right = left + 10; - Engine.GetGUIObjectByName("playerBox3["+i+"]").size = size; - - left = 240; - exchangedFood.size = left + " 2 " + (left + width) + " 100%"; left += width; - exchangedWood.size = left + " 2 " + (left + width) + " 100%"; left += width; - exchangedStone.size = left + " 2 " + (left + width) + " 100%"; left += width; - exchangedMetal.size = left + " 2 " + (left + width) + " 100%"; left += width; - barterEfficiency.size = left + " 2 " + (left + width) + " 100%"; left += width; - tradeIncome.size = left + " 2 " + (left + width) + " 100%"; left += width; - size = Engine.GetGUIObjectByName("playerBox4["+i+"]").size; - size.right = left + 10; - Engine.GetGUIObjectByName("playerBox4["+i+"]").size = size; - - // display counters - economyScore.caption = Math.round((playerState.statistics.resourcesGathered.food + playerState.statistics.resourcesGathered.wood + - playerState.statistics.resourcesGathered.stone + playerState.statistics.resourcesGathered.metal) / 10); - militaryScore.caption = Math.round((playerState.statistics.enemyUnitsKilledValue + playerState.statistics.enemyBuildingsDestroyedValue) / 10); - explorationScore.caption = playerState.statistics.percentMapExplored * 10; - totalScore.caption = Number(economyScore.caption) + Number(militaryScore.caption) + Number(explorationScore.caption); - - unitsTrained.caption = playerState.statistics.unitsTrained; - unitsLost.caption = playerState.statistics.unitsLost; - enemyUnitsKilled.caption = playerState.statistics.enemyUnitsKilled; - buildingsConstructed.caption = playerState.statistics.buildingsConstructed; - buildingsLost.caption = playerState.statistics.buildingsLost; - enemyBuildingsDestroyed.caption = playerState.statistics.enemyBuildingsDestroyed; - - civCentresBuilt.caption = playerState.statistics.civCentresBuilt; - enemyCivCentresDestroyed.caption = playerState.statistics.enemyCivCentresDestroyed; - mapExploration.caption = playerState.statistics.percentMapExplored + "%"; - - const SOLD_COLOR = '[color="201 255 200"]'; - const BOUGHT_COLOR = '[color="255 213 213"]'; - foodGathered.caption = SOLD_COLOR + playerState.statistics.resourcesGathered.food + "[/color] / " + - BOUGHT_COLOR + (playerState.statistics.resourcesUsed.food - playerState.statistics.resourcesSold.food) + "[/color]"; - woodGathered.caption = SOLD_COLOR + playerState.statistics.resourcesGathered.wood + "[/color] / " + - BOUGHT_COLOR + (playerState.statistics.resourcesUsed.wood - playerState.statistics.resourcesSold.wood) + "[/color]"; - stoneGathered.caption = SOLD_COLOR + playerState.statistics.resourcesGathered.stone + "[/color] / " + - BOUGHT_COLOR + (playerState.statistics.resourcesUsed.stone - playerState.statistics.resourcesSold.stone) + "[/color]"; - metalGathered.caption = SOLD_COLOR + playerState.statistics.resourcesGathered.metal + "[/color] / " + - BOUGHT_COLOR + (playerState.statistics.resourcesUsed.metal - playerState.statistics.resourcesSold.metal) + "[/color]"; - vegetarianRatio.caption = Math.floor(playerState.statistics.resourcesGathered.food > 0 ? - (playerState.statistics.resourcesGathered.vegetarianFood / playerState.statistics.resourcesGathered.food) * 100 : 0) + "%"; - treasuresCollected.caption = playerState.statistics.treasuresCollected; - resourcesTributed.caption = SOLD_COLOR + playerState.statistics.tributesSent + "[/color] / " + - BOUGHT_COLOR + playerState.statistics.tributesReceived + "[/color]"; - - exchangedFood.caption = SOLD_COLOR + '+' + playerState.statistics.resourcesBought.food - + '[/color] ' + BOUGHT_COLOR + '-' + playerState.statistics.resourcesSold.food + '[/color]'; - exchangedWood.caption = SOLD_COLOR + '+' + playerState.statistics.resourcesBought.wood - + '[/color] ' + BOUGHT_COLOR + '-' + playerState.statistics.resourcesSold.wood + '[/color]'; - exchangedStone.caption = SOLD_COLOR + '+' + playerState.statistics.resourcesBought.stone - + '[/color] ' + BOUGHT_COLOR + '-' + playerState.statistics.resourcesSold.stone + '[/color]'; - exchangedMetal.caption = SOLD_COLOR + '+' + playerState.statistics.resourcesBought.metal - + '[/color] ' + BOUGHT_COLOR + '-' + playerState.statistics.resourcesSold.metal + '[/color]'; - var totalBought = 0; - for each (var boughtAmount in playerState.statistics.resourcesBought) - totalBought += boughtAmount; - var totalSold = 0; - for each (var soldAmount in playerState.statistics.resourcesSold) - totalSold += soldAmount; - barterEfficiency.caption = Math.floor(totalSold > 0 ? (totalBought / totalSold) * 100 : 0) + "%"; - tradeIncome.caption = playerState.statistics.tradeIncome; + teams[data.playerStates[t+1].team] = 1; + continue; + } + teams[data.playerStates[t+1].team]++; } + + if (teams.length == maxPlayers) + teams = false; // Each player has his own team. Displaying teams makes no sense. + } + else // teams are NOT locked + teams = false; + + // Erase teams data if teams are not displayed + if (!teams) + { + for(var p = 0; p < maxPlayers; ++p) + data.playerStates[p+1].team = -1; + } + + // Count players without team (or all if teams are not displayed) + var withoutTeam = maxPlayers; + if (teams) + { + // count players without team (or all if teams are not displayed) + for (var i = 0; i < teams.length; ++i) + withoutTeam -= teams[i]; + + // Display teams boxes + var p = 0; + for each (var panel in panels) + { + var yStart = TEAMS_BOX_Y_START + withoutTeam * (PLAYER_BOX_Y_SIZE + PLAYER_BOX_GAP); + for (var i = 0; i < teams.length; ++i) + { + var teamBox = Engine.GetGUIObjectByName("teamBox"+p+"t"+i); + teamBox.hidden = false; + var teamBoxSize = teamBox.size; + teamBoxSize.top = yStart; + teamBox.size = teamBoxSize; + + yStart += 30 + teams[i] * (PLAYER_BOX_Y_SIZE + PLAYER_BOX_GAP) + 32; + + Engine.GetGUIObjectByName("teamNameHeading"+p+"t"+i).caption = "Team "+(i+1); + + // Make place to store team scores + for each (var counter in panel.counters) + { + counter.teamsScores[i] = 0; + counter.teamsScoresCaption[i] = "0"; + } + } + + // If there are no players without team, hide "player name" heading + if (!withoutTeam) + Engine.GetGUIObjectByName("playerName"+p+"Heading").caption = ""; + + p++; + } + } + + if (withoutTeam) + { + // Show boxes for no teams + for (var b = 0; b < PANELS_COUNT; ++b) + Engine.GetGUIObjectByName("noTeamsBox"+b).hidden = false; + } + + var playerBoxesCounts = [ ]; + for (var i = 0; i < maxPlayers; ++i) + { + var tn = ""; + var playerState = data.playerStates[i+1]; + + if (!playerBoxesCounts[playerState.team+1]) + playerBoxesCounts[playerState.team+1] = 1; else + playerBoxesCounts[playerState.team+1] += 1; + + if (playerState.team != -1) + tn = "t"+playerState.team+"p"; + + var j = 0; + for each (var panel in panels) + { + var playerIdentityString = tn+"["+(playerBoxesCounts[playerState.team+1]-1)+"]"; + // Display boxes for players + var playerBox = Engine.GetGUIObjectByName("playerBox"+j+playerIdentityString); + playerBox.hidden = false; + + var boxSize = playerBox.size; + boxSize.top += (playerBoxesCounts[playerState.team+1] - 1) * (PLAYER_BOX_Y_SIZE + PLAYER_BOX_GAP); + boxSize.bottom = boxSize.top + PLAYER_BOX_Y_SIZE; + playerBox.size = boxSize; + + var colourString = "colour: " + + Math.floor(playerState.colour.r * 255) + " " + + Math.floor(playerState.colour.g * 255) + " " + + Math.floor(playerState.colour.b * 255); + + playerBox.sprite = colourString + PLAYER_BOX_ALPHA; + + var playerColourBox = Engine.GetGUIObjectByName("playerColourBox"+j+playerIdentityString); + playerColourBox.sprite = colourString + PLAYER_COLOUR_BOX_ALPHA; + + // Show the multiplayer name, e.g. "Foobar" rather than "Player 1". + // TODO: Perhaps show both the multiplayer and map-specific name? + var playerName = Engine.GetGUIObjectByName("playerName"+j+playerIdentityString); + playerName.caption = data.players[i+1].name; + + var civIcon = Engine.GetGUIObjectByName("civIcon"+j+playerIdentityString); + civIcon.sprite = "stretched:"+civData[playerState.civ].Emblem; + civIcon.tooltip = civData[playerState.civ].Name; + + // Get counters + for (var c in panel.counters) + { + panel.counters[c].objects[i] = Engine.GetGUIObjectByName(c+playerIdentityString); + } + + // Align counters + var right = alignCounters(panel.counters, i); + boxSize.right = right; + playerBox.size = boxSize; + + j++; + } + + // Assign counters + // score panel + panels.score.counters.economyScore.objects[i].caption = captionEconomyScore(); + panels.score.counters.militaryScore.objects[i].caption = Math.round((playerState.statistics.enemyUnitsKilledValue + + playerState.statistics.enemyBuildingsDestroyedValue) / 10); + panels.score.counters.explorationScore.objects[i].caption = playerState.statistics.percentMapExplored * 10; + panels.score.counters.totalScore.objects[i].caption = (+panels.score.counters.economyScore.objects[i].caption) + + (+panels.score.counters.militaryScore.objects[i].caption) + + (+panels.score.counters.explorationScore.objects[i].caption); + // buildings panel + var t = 0; + for each (var counter in panels.buildings.counters) + { + captionBuildings(counter.objects[i], BUILDINGS_TYPES[t]); + t++; + } + // units panel + t = 0; + for each (var counter in panels.units.counters) + { + captionUnits(counter.objects[i], UNITS_TYPES[t]); + t++; + } + // resources panel + t = 0; + for each (var counter in panels.resources.counters) + { + if (t >= 4) // only 4 first counters + break; + + captionResourcesGathered(counter.objects[i], RESOURCES_TYPES[t]); + t++; + } + panels.resources.counters.totalGathered.objects[i].caption = captionTotalResourcesGathered(); + panels.resources.counters.treasuresCollected.objects[i].caption = playerState.statistics.treasuresCollected; + panels.resources.counters.resourcesTributed.objects[i].caption = captionResourcesTributed(); + // market panel + t = 0; + for (var c in panels.market.counters) { - // hide player boxes - for (var k = 0; k < panelNames.length; ++k) + if (t >= 4) // only 4 first counters + break; + + captionResourcesExchanged(panels.market.counters[c].objects[i], RESOURCES_TYPES[t]); + t++; + } + panels.market.counters.barterEfficiency.objects[i].caption = captionBarterEfficiency(); + panels.market.counters.tradeIncome.objects[i].caption = playerState.statistics.tradeIncome; + // miscelanous panel + panels.miscelanous.counters.vegetarianRatio.objects[i].caption = captionVegetarianRatio(); + panels.miscelanous.counters.feminisation.objects[i].caption = captionFeminisation(); + panels.miscelanous.counters.killDeathRatio.objects[i].caption = captionKillDeathRatio(); + panels.miscelanous.counters.mapExploration.objects[i].caption = playerState.statistics.percentMapExplored + "%"; + + if (!teams) + continue; + + if (playerState.team == -1) + continue; + + // Evaluate team total score + // score panel + for (var c in panels.score.counters) + { + panels.score.counters[c].teamsScores[playerState.team] += (+panels.score.counters[c].objects[i].caption); + panels.score.counters[c].teamsScoresCaption[playerState.team] = panels.score.counters[c].teamsScores[playerState.team]; + } + // buildings panel + var t = 0; + for each (var counter in panels.buildings.counters) + { + sumTeamBuildings(counter, BUILDINGS_TYPES[t]); + t++; + } + // units panel + t = 0; + for each (var counter in panels.units.counters) + { + sumTeamUnits(counter, UNITS_TYPES[t]); + t++; + } + // resources panel + t = 0; + for each (var counter in panels.resources.counters) + { + if (t >= 4) // only 4 first counters + break; + + sumResourcesGathered(counter, RESOURCES_TYPES[t]); + t++; + } + sumTotalResourcesGathered(); + panels.resources.counters.treasuresCollected.teamsScores[playerState.team] += playerState.statistics.treasuresCollected; + panels.resources.counters.treasuresCollected.teamsScoresCaption[playerState.team] = panels.resources.counters.treasuresCollected.teamsScores[playerState.team]; + sumResourcesTributed(); + // market panel + t = 0; + for (var c in panels.market.counters) + { + if (t >= 4) // only 4 first counters + break; + + sumResourcesExchanged(panels.market.counters[c], RESOURCES_TYPES[t]); + t++; + } + sumBarterEfficiency(); + panels.market.counters.tradeIncome.teamsScores[playerState.team] += playerState.statistics.tradeIncome; + panels.market.counters.tradeIncome.teamsScoresCaption[playerState.team] = panels.market.counters.tradeIncome.teamsScores[playerState.team]; + // miscelanous panel + sumVegetarianRatio(); + sumFeminisation(); + sumKillDeathRatio(); + // TODO: probably change from simple sum to union from range manager + panels.miscelanous.counters.mapExploration.teamsScores[playerState.team] += playerState.statistics.percentMapExplored; + panels.miscelanous.counters.mapExploration.teamsScoresCaption[playerState.team] = panels.miscelanous.counters.mapExploration.teamsScores[playerState.team] + "%"; + } + + if (!teams) + { + selectPanel(0); + return; + } + + // Display teams totals counters + for (var i = 0; i < teams.length; ++i) + { + var pn = 0; + for each (var panel in panels) + { + var teamHeading = Engine.GetGUIObjectByName("teamHeading"+pn+"t"+i); + var yStart = 30 + teams[i] * (PLAYER_BOX_Y_SIZE + PLAYER_BOX_GAP) + 2; + teamHeading.size = "50 "+yStart+" 100% "+(yStart+20); + teamHeading.caption = "Team total"; + + var left = 250; + for (var c in panel.counters) { - var playerBox = Engine.GetGUIObjectByName("playerBox"+k+"["+i+"]"); - playerBox.hidden = true; + var counter = Engine.GetGUIObjectByName(c+"t"+i); + counter.size = left + " " + yStart + " " + (left + panel.counters[c].width) + " " + (yStart+20); + counter.caption = panel.counters[c].teamsScoresCaption[i]; + + left += panel.counters[c].width; } + pn++; } } selectPanel(0); } function onTick() { } Index: ps/trunk/binaries/data/mods/public/gui/summary/summary.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/summary/summary.xml (revision 14702) +++ ps/trunk/binaries/data/mods/public/gui/summary/summary.xml (revision 14703) @@ -1,304 +1,980 @@