Ticket #1090: playercomponent_savegamesummaryreplaycleanup_v2.patch
File playercomponent_savegamesummaryreplaycleanup_v2.patch, 54.6 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/gui/common/functions_utility.js
function clearChatMessages() 211 211 } 212 212 } 213 213 214 214 /** 215 215 * Returns a formatted string describing the player assignments. 216 * Including civs, teams, AI settings and player colors 217 * which are given in data (array of objects per player). 216 * Needs g_CivData to translate! 218 217 * 218 * @param {object} playerDataArray - As known from gamesetup and simstate. 219 * @param {(string[]|false)} playerStates - One of "won", "defeated", "active" for each player. 219 220 * @returns {string} 220 221 */ 221 function formatPlayerInfo( data)222 function formatPlayerInfo(playerDataArray, playerStates) 222 223 { 223 224 let playerDescriptions = {}; 224 225 let playerIdx = 0; 225 for (let playerData of data) 226 227 for (let playerData of playerDataArray) 226 228 { 229 if (playerData == null || playerData.Civ == "gaia") 230 continue; 231 227 232 ++playerIdx; 228 233 let teamIdx = playerData.Team; 229 let showDefeated = playerData.state && playerData.state == "defeated";230 234 let isAI = playerData.AI && playerData.AI != ""; 235 let playerState = playerStates && playerStates[playerIdx]; 236 let isActive = !playerState || playerState == "active"; 231 237 232 let translated; 233 if (!isAI && !showDefeated) 234 translated = translateWithContext("replay", "%(playerName)s (%(civ)s)"); 235 else if (!isAI && showDefeated) 236 translated = translateWithContext("replay", "%(playerName)s (%(civ)s, defeated)"); 237 else if (isAI && !showDefeated) 238 translated = translateWithContext("replay", "%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s)"); 238 let playerDescription; 239 if (isAI) 240 { 241 if (isActive) 242 playerDescription = translateWithContext("replay", "%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s, %(state)s)"); 243 else 244 playerDescription = translateWithContext("replay", "%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s)"); 245 } 239 246 else 240 translated = translateWithContext("replay", "%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s, defeated)"); 247 { 248 if (isActive) 249 playerDescription = translateWithContext("replay", "%(playerName)s (%(civ)s, %(state)s)"); 250 else 251 playerDescription = translateWithContext("replay", "%(playerName)s (%(civ)s)"); 252 } 241 253 242 254 // Sort player descriptions by team 243 255 if (!playerDescriptions[teamIdx]) 244 256 playerDescriptions[teamIdx] = []; 245 playerDescriptions[teamIdx].push(sprintf(translated, { 246 "playerName": '[color="' + rgbToGuiColor(playerData.Color) + '"]' + escapeText(playerData.Name) + "[/color]", 247 "civ": playerData.Civ, 257 258 playerDescriptions[teamIdx].push(sprintf(playerDescription, { 259 "playerName": 260 '[color="' + 261 rgbToGuiColor(playerData.Color || g_Settings.PlayerDefaults[playerIdx].Color) + 262 '"]' + escapeText(playerData.Name) + "[/color]", 263 264 "civ": 265 !playerData.Civ ? 266 translate("Unknown Civilization") : 267 g_CivData && g_CivData[playerData.Civ] && g_CivData[playerData.Civ].Name ? 268 translate(g_CivData[playerData.Civ].Name) : 269 playerData.Civ, 270 271 "state": 272 playerState == "defeated" ? 273 translateWithContext("playerState", "Defeated") : 274 translateWithContext("playerState", "Won"), 275 248 276 "AIname": isAI ? translateAIName(playerData.AI) : "", 249 277 "AIdifficulty": isAI ? translateAIDifficulty(playerData.AIDiff) : "" 250 278 })); 251 279 } 252 280 … … function formatPlayerInfo(data) 256 284 if (teams.length == 1) 257 285 return playerDescriptions[teams[0]].join("\n") + "\n"; 258 286 259 287 // If there are teams, merge "Team N:" + playerDescriptions 260 288 return teams.map(team => { 261 let teamCaption = (team == -1) ? translate("No Team") : sprintf(translate("Team %(team)s"), { "team": +team + 1 }); 262 return '[font="sans-bold-14"]' + teamCaption + "[/font]:\n" + playerDescriptions[team].join("\n"); 289 290 let teamCaption = team == -1 ? 291 translate("No Team") : 292 sprintf(translate("Team %(team)s"), { "team": +team + 1 }); 293 294 return sprintf(translateWithContext("replay", "%(team)s:\n%(playerDescriptions)s"), { 295 "team": '[font="sans-bold-14"]' + teamCaption + "[/font]", 296 "playerDescriptions": playerDescriptions[team].join("\n") 297 }); 263 298 }).join("\n\n"); 264 299 } -
binaries/data/mods/public/gui/replaymenu/replay_menu.js
2 2 * Used for checking replay compatibility. 3 3 */ 4 4 const g_EngineInfo = Engine.GetEngineInfo(); 5 5 6 6 /** 7 * To show the titles of the selected civs in the replaydetails.7 * Needed for formatPlayerInfo to show the player civs in the details. 8 8 */ 9 9 const g_CivData = loadCivData(); 10 10 11 11 /** 12 12 * Used for creating the mapsize filter. … … function displayReplayList() 188 188 if (replaySelection.selected != -1) 189 189 g_SelectedReplayDirectory = g_ReplaysFiltered[replaySelection.selected].directory; 190 190 191 191 filterReplays(); 192 192 193 // Create GUI list data194 193 var list = g_ReplaysFiltered.map(replay => { 195 194 let works = replay.isCompatible; 196 195 return { 197 196 "directories": replay.directory, 198 197 "months": greyout(getReplayDateTime(replay), works), … … function displayReplayList() 202 201 "durations": greyout(getReplayDuration(replay), works), 203 202 "playerNames": greyout(getReplayPlayernames(replay), works) 204 203 }; 205 204 }); 206 205 207 // Extract arrays208 206 if (list.length) 209 207 list = prepareForDropdown(list); 210 208 211 209 // Push to GUI 212 210 replaySelection.selected = -1; … … function displayReplayList() 219 217 220 218 // Change these last, otherwise crash 221 219 replaySelection.list = list.directories || []; 222 220 replaySelection.list_data = list.directories || []; 223 221 224 // Restore selection225 222 replaySelection.selected = replaySelection.list.findIndex(directory => directory == g_SelectedReplayDirectory); 226 223 227 224 displayReplayDetails(); 228 225 } 229 226 230 227 /** 231 228 * Shows preview image, description and player text in the right panel. 232 229 */ 233 230 function displayReplayDetails() 234 231 { 235 varselected = Engine.GetGUIObjectByName("replaySelection").selected;236 varreplaySelected = selected > -1;232 let selected = Engine.GetGUIObjectByName("replaySelection").selected; 233 let replaySelected = selected > -1; 237 234 238 235 Engine.GetGUIObjectByName("replayInfo").hidden = !replaySelected; 239 236 Engine.GetGUIObjectByName("replayInfoEmpty").hidden = replaySelected; 240 237 Engine.GetGUIObjectByName("startReplayButton").enabled = replaySelected; 241 238 Engine.GetGUIObjectByName("deleteReplayButton").enabled = replaySelected; 242 239 Engine.GetGUIObjectByName("summaryButton").hidden = true; 243 240 244 241 if (!replaySelected) 245 242 return; 246 243 247 var replay = g_ReplaysFiltered[selected]; 248 var mapData = getMapDescriptionAndPreview(replay.attribs.settings.mapType, replay.attribs.map); 244 let replay = g_ReplaysFiltered[selected]; 249 245 250 // Update GUI251 246 Engine.GetGUIObjectByName("sgMapName").caption = translate(replay.attribs.settings.Name); 252 247 Engine.GetGUIObjectByName("sgMapSize").caption = translateMapSize(replay.attribs.settings.Size); 253 248 Engine.GetGUIObjectByName("sgMapType").caption = translateMapType(replay.attribs.settings.mapType); 254 249 Engine.GetGUIObjectByName("sgVictory").caption = translateVictoryCondition(replay.attribs.settings.GameType); 255 250 Engine.GetGUIObjectByName("sgNbPlayers").caption = replay.attribs.settings.PlayerData.length; 256 Engine.GetGUIObjectByName("sgPlayersNames").caption = getReplayTeamText(replay); 251 252 let metadata = Engine.GetReplayMetadata(replay.directory); 253 let mapData = getMapDescriptionAndPreview(replay.attribs.settings.mapType, replay.attribs.map); 254 let playerStates = 255 Engine.GetGUIObjectByName("showSpoiler").checked && 256 metadata && 257 metadata.playerStates && 258 metadata.playerStates.map(pState => pState.state); 259 260 Engine.GetGUIObjectByName("sgPlayersNames").caption = formatPlayerInfo(replay.attribs.settings.PlayerData, playerStates); 257 261 Engine.GetGUIObjectByName("sgMapDescription").caption = mapData.description; 258 262 Engine.GetGUIObjectByName("summaryButton").hidden = !Engine.HasReplayMetadata(replay.directory); 259 263 260 264 setMapPreviewImage("sgMapPreview", mapData.preview); 261 265 } … … function isReplayCompatible(replay) 329 333 */ 330 334 function replayHasSameEngineVersion(replay) 331 335 { 332 336 return replay.attribs.engine_version && replay.attribs.engine_version == g_EngineInfo.engine_version; 333 337 } 334 335 /**336 * Returns a description of the player assignments.337 * Including civs, teams, AI settings and player colors.338 *339 * If the spoiler-checkbox is checked, it also shows defeated players.340 *341 * @returns {string}342 */343 function getReplayTeamText(replay)344 {345 // Load replay metadata346 const metadata = Engine.GetReplayMetadata(replay.directory);347 const spoiler = Engine.GetGUIObjectByName("showSpoiler").checked;348 349 let data = [];350 let playerIdx = 0;351 for (let playerData of replay.attribs.settings.PlayerData)352 {353 ++playerIdx;354 data.push({355 "Team": playerData.Team,356 "Name": playerData.Name,357 "Civ": !playerData.Civ ? translate("Unknown Civilization") :358 (g_CivData[playerData.Civ] && g_CivData[playerData.Civ].Name ? translate(g_CivData[playerData.Civ].Name) : playerData.Civ),359 "Color": playerData.Color ? playerData.Color : g_Settings.PlayerDefaults[playerIdx].Color,360 "AI": playerData.AI,361 "AIDiff": playerData.AIDiff,362 "Defeated": spoiler && metadata && metadata.playerStates && metadata.playerStates[playerIdx].state == "defeated"363 });364 }365 366 return formatPlayerInfo(data);367 } -
binaries/data/mods/public/gui/savedgames/load.js
1 1 var g_SavedGamesMetadata = []; 2 2 3 /** 4 * Needed for formatPlayerInfo to show the player civs in the details. 5 */ 6 const g_CivData = loadCivData(); 7 3 8 function init() 4 9 { 5 10 let gameSelection = Engine.GetGUIObjectByName("gameSelection"); 6 11 7 12 let savedGames = Engine.GetSavedGames().sort(sortDecreasingDate); … … function selectionChanged() 56 61 let caption = sprintf(translate("Mods: %(mods)s"), { "mods": metadata.mods.join(translate(", ")) }); 57 62 if (!hasSameMods(metadata, Engine.GetEngineInfo())) 58 63 caption = "[color=\"orange\"]" + caption + "[/color]"; 59 64 Engine.GetGUIObjectByName("savedMods").caption = caption; 60 65 61 let data = []; 62 let playerIdx = 0; 63 for (let playerData of metadata.initAttributes.settings.PlayerData) 64 { 65 if (playerData == null || playerData.Civ == "gaia") 66 continue; 67 ++playerIdx; 68 data.push({ 69 "Team": playerData.Team, 70 "Name": playerData.Name, 71 "Civ": playerData.Civ, 72 "Color": playerData.Color, 73 "AI": playerData.AI, 74 "AIDiff": playerData.AIDiff, 75 "Defeated": metadata.gui.states && metadata.gui.states[playerIdx] == "defeated" 76 }); 77 } 78 79 Engine.GetGUIObjectByName("savedPlayersNames").caption = formatPlayerInfo(data); 66 Engine.GetGUIObjectByName("savedPlayersNames").caption = formatPlayerInfo( 67 metadata.initAttributes.settings.PlayerData, 68 metadata.gui.states 69 ); 80 70 } 81 71 82 72 function loadGame() 83 73 { 84 74 let gameSelection = Engine.GetGUIObjectByName("gameSelection"); -
binaries/data/mods/public/gui/savedgames/load.xml
1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 3 3 <objects> 4 4 5 5 <script file="gui/common/color.js" /> 6 <script file="gui/common/functions_civinfo.js"/> 6 7 <script file="gui/common/functions_global_object.js" /> 7 8 <script file="gui/common/functions_utility.js" /> 8 9 <script file="gui/common/functions_utility_loadsave.js" /> 9 10 <script file="gui/common/settings.js" /> 10 11 <script file="gui/savedgames/load.js" /> … … 28 29 <action on="Press">Engine.PopGuiPage();</action> 29 30 </object> 30 31 31 32 <object name="deleteGameButton" type="button" size="33%+20 100%-60 66%-15 100%-32" style="StoneButton" hotkey="session.savedgames.delete"> 32 33 <translatableAttribute id="caption">Delete</translatableAttribute> 33 <action on="Press"> 34 if (!this.enabled) 35 return; 36 if (Engine.HotkeyIsPressed("session.savedgames.noconfirmation")) 37 deleteGameWithoutConfirmation(); 38 else 39 deleteGame(); 40 </action> 34 <action on="Press">deleteGame();</action> 41 35 </object> 42 36 43 37 <object name="loadGameButton" type="button" style="StoneButton" size="66%-5 100%-60 100%-25 100%-32"> 44 38 <translatableAttribute id="caption">Load</translatableAttribute> 45 39 <action on="Press">loadGame();</action> -
binaries/data/mods/public/gui/savedgames/save.js
function selectDescription() 15 15 function init(data) 16 16 { 17 17 g_SavedGameData = data && data.savedGameData || {}; 18 18 let simulationState = Engine.GuiInterfaceCall("GetSimulationState"); 19 19 g_SavedGameData.timeElapsed = simulationState.timeElapsed; 20 g_SavedGameData.states = []; 21 for (let player of simulationState.players) 22 g_SavedGameData.states.push(player.state); 20 g_SavedGameData.states = simulationState.players.map(pState => pState.state); 23 21 24 22 let gameSelection = Engine.GetGUIObjectByName("gameSelection"); 25 23 Engine.GetGUIObjectByName("deleteGameButton").enabled = false; 26 24 27 25 let savedGames = Engine.GetSavedGames().sort(sortDecreasingDate); -
binaries/data/mods/public/gui/session/menu.js
function toggleDeveloperOverlay() 751 751 "translateParameters": [], 752 752 "parameters": {} 753 753 }); 754 754 } 755 755 756 // TODO: should also close message boxes 756 757 function closeOpenDialogs() 757 758 { 758 759 closeMenu(); 759 760 closeChat(); 760 761 closeDiplomacy(); -
binaries/data/mods/public/gui/session/messages.js
var g_FormatChatMessage = { 99 99 } 100 100 ), 101 101 "clientlist": msg => getUsernameList(), 102 102 "message": msg => formatChatCommand(msg), 103 103 "defeat": msg => formatDefeatMessage(msg), 104 "won": msg => formatWinMessage(msg), 104 105 "diplomacy": msg => formatDiplomacyMessage(msg), 105 106 "tribute": msg => formatTributeMessage(msg), 106 107 "attack": msg => formatAttackMessage(msg) 107 108 }; 108 109 … … var g_DiplomacyMessages = { 192 193 } 193 194 }; 194 195 195 196 /** 196 197 * Defines how the GUI reacts to notifications that are sent by the simulation. 198 * Don't open new pages (message boxes) here! Otherwise further notifications 199 * handled in the same turn can't access the GUI objects anymore. 197 200 */ 198 201 var g_NotificationsTypes = 199 202 { 200 203 "chat": function(notification, player) 201 204 { … … var g_NotificationsTypes = 244 247 "type": "defeat", 245 248 "guid": findGuidForPlayerID(player), 246 249 "player": player, 247 250 "resign": !!notification.resign 248 251 }); 249 250 updateDiplomacy(); 251 updateChatAddressees(); 252 playerFinished(player, false); 253 }, 254 "won": function(notification, player) 255 { 256 addChatMessage({ 257 "type": "won", 258 "guid": findGuidForPlayerID(player), 259 "player": player 260 }); 261 playerFinished(player, true); 252 262 }, 253 263 "diplomacy": function(notification, player) 254 264 { 255 265 addChatMessage({ 256 266 "type": "diplomacy", … … function findGuidForPlayerID(playerID) 415 425 /** 416 426 * Processes all pending notifications sent from the GUIInterface simulation component. 417 427 */ 418 428 function handleNotifications() 419 429 { 420 let notifications = Engine.GuiInterfaceCall("GetNotifications"); 421 for (let notification of notifications) 430 for (let notification of Engine.GuiInterfaceCall("GetNotifications")) 422 431 { 423 432 if (!notification.players || !notification.type || !g_NotificationsTypes[notification.type]) 424 433 { 425 434 error("Invalid GUI notification: " + uneval(notification)); 426 435 continue; … … function formatDefeatMessage(msg) 743 752 translate("%(player)s has been defeated."), 744 753 { "player": colorizePlayernameByID(msg.player) } 745 754 ); 746 755 } 747 756 757 function formatWinMessage(msg) 758 { 759 return sprintf(translate("%(player)s has won."), { 760 "player": colorizePlayernameByID(msg.player) 761 }); 762 } 763 748 764 function formatDiplomacyMessage(msg) 749 765 { 750 766 let messageType; 751 767 752 768 if (g_IsObserver) -
binaries/data/mods/public/gui/session/session.js
var g_IsObserver = false; 36 36 * True if the current user has rejoined (or joined the game after it started). 37 37 */ 38 38 var g_HasRejoined = false; 39 39 40 40 /** 41 * Shows a message box asking the user to leave if "won" or "defeated". 42 */ 43 var g_ConfirmExit = false; 44 45 /** 41 46 * True if the current player has paused the game explicitly. 42 47 */ 43 48 var g_Paused = false; 44 49 45 50 /** … … var g_EntityStates = {}; 117 122 var g_TemplateData = {}; 118 123 var g_TemplateDataWithoutLocalization = {}; 119 124 var g_TechnologyData = {}; 120 125 121 126 /** 122 * Cache concatenated list of player states ("active", "defeated" or "won").123 */124 var g_CachedLastStates = "";125 126 /**127 * Whether the current player has lost/won and reached the end of their game.128 * Used for reporting the gamestate and showing the game-end message only once.129 */130 var g_GameEnded = false;131 132 /**133 127 * Top coordinate of the research list. 134 128 * Changes depending on the number of displayed counters. 135 129 */ 136 130 var g_ResearchListTop = 4; 137 131 … … function init(initData, hotloadData) 238 232 g_PlayerAssignments = initData.playerAssignments; 239 233 g_MatchID = initData.attribs.matchID; 240 234 g_ReplaySelectionData = initData.replaySelectionData; 241 235 g_HasRejoined = initData.isRejoining; 242 236 243 g_Players = getPlayerData();244 245 237 if (initData.savedGUIData) 246 238 restoreSavedGameData(initData.savedGUIData); 247 239 248 240 Engine.GetGUIObjectByName("gameSpeedButton").hidden = g_IsNetworked; 249 241 } 250 242 else // Needed for autostart loading option 251 243 { 252 244 if (g_IsReplay) 253 245 g_PlayerAssignments.local.player = -1; 254 255 g_Players = getPlayerData();256 246 } 257 247 248 g_Players = getPlayerData(); 249 258 250 g_CivData = loadCivData(); 259 251 g_CivData.gaia = { "Code": "gaia", "Name": translate("Gaia") }; 260 252 261 253 initializeMusic(); // before changing the perspective 262 selectViewPlayer(g_ViewedPlayer);263 254 264 255 let gameSpeed = Engine.GetGUIObjectByName("gameSpeed"); 265 256 gameSpeed.list = g_GameSpeeds.Title; 266 257 gameSpeed.list_data = g_GameSpeeds.Speed; 267 258 let gameSpeedIdx = g_GameSpeeds.Speed.indexOf(Engine.GetSimRate()); … … function init(initData, hotloadData) 279 270 { 280 271 playerIDs.push(player); 281 272 playerNames.push(colorizePlayernameHelper("■", player) + " " + g_Players[player].name); 282 273 } 283 274 275 // Select "observer" item when rejoining as a defeated player 276 let viewedPlayer = g_Players[Engine.GetPlayerID()]; 284 277 let viewPlayerDropdown = Engine.GetGUIObjectByName("viewPlayer"); 285 278 viewPlayerDropdown.list = playerNames; 286 279 viewPlayerDropdown.list_data = playerIDs; 287 viewPlayerDropdown.selected = Engine.GetPlayerID() + 1;280 viewPlayerDropdown.selected = viewedPlayer && viewedPlayer.state == "defeated" ? 0 : Engine.GetPlayerID() + 1; 288 281 289 282 // If in Atlas editor, disable the exit button 290 283 if (Engine.IsAtlasRunning()) 291 284 Engine.GetGUIObjectByName("menuExitButton").enabled = false; 292 285 … … function controlsPlayer(playerID) 433 426 return playerState && ( 434 427 playerState.state != "defeated" || playerState.controlsAll); 435 428 } 436 429 437 430 /** 431 * Called when a player has won or was defeated. 432 */ 433 function playerFinished(player, won) 434 { 435 reportGame(); 436 updateDiplomacy(); 437 updateChatAddressees(); 438 439 if (player != Engine.GetPlayerID() || Engine.IsAtlasRunning()) 440 return; 441 442 global.music.setState( 443 won ? 444 global.music.states.VICTORY : 445 global.music.states.DEFEAT 446 ); 447 448 // Select "observer" item 449 if (!won) 450 Engine.GetGUIObjectByName("viewPlayer").selected = 0; 451 452 g_ConfirmExit = won ? "won" : "defeated"; 453 } 454 455 /** 438 456 * Sets civ icon for the currently viewed player. 439 457 * Hides most gui objects for observers. 440 458 */ 441 459 function updateTopPanel() 442 460 { … … function resignGame(leaveGameAfterResign 490 508 "type": "defeat-player", 491 509 "playerId": Engine.GetPlayerID(), 492 510 "resign": true 493 511 }); 494 512 495 updateTopPanel();496 497 513 global.music.setState(global.music.states.DEFEAT); 498 514 499 515 if (!leaveGameAfterResign) 500 516 resumeGame(true); 501 517 } … … function resignGame(leaveGameAfterResign 505 521 * @param willRejoin If player is going to be rejoining a networked game. 506 522 */ 507 523 function leaveGame(willRejoin) 508 524 { 509 525 let extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState"); 510 let mapSettings = Engine.GetMapSettings(); 511 let gameResult; 512 513 if (Engine.GetPlayerID() == -1) 514 { 515 gameResult = translate("You have left the game."); 516 global.music.setState(global.music.states.VICTORY); 517 } 518 else 519 { 520 let playerState = extendedSimState.players[Engine.GetPlayerID()]; 521 if (g_Disconnected) 522 gameResult = translate("You have been disconnected."); 523 else if (playerState.state == "won") 524 gameResult = translate("You have won the battle!"); 525 else if (playerState.state == "defeated") 526 gameResult = translate("You have been defeated..."); 527 else // "active" 528 { 529 global.music.setState(global.music.states.DEFEAT); 530 if (willRejoin) 531 gameResult = translate("You have left the game."); 532 else 533 { 534 gameResult = translate("You have abandoned the game."); 535 resignGame(true); 536 } 537 } 538 } 539 540 let summary = { 526 let simData = { 541 527 "timeElapsed" : extendedSimState.timeElapsed, 542 528 "playerStates": extendedSimState.players, 543 "players": g_Players, 544 "mapSettings": Engine.GetMapSettings(), 529 "mapSettings": Engine.GetMapSettings() 545 530 }; 546 531 547 532 if (!g_IsReplay) 548 Engine.SaveReplayMetadata(JSON.stringify(summary)); 533 Engine.SaveReplayMetadata(JSON.stringify(simData)); 534 535 let guiData = { 536 "assignedPlayer": Engine.GetPlayerID(), 537 "disconnected": g_Disconnected, 538 "isReplay": g_IsReplay, 539 "replayDirectory": !g_HasRejoined && Engine.GetCurrentReplayDirectory(), 540 "replaySelectionData": g_ReplaySelectionData, 541 }; 549 542 550 if (!g_HasRejoined) 551 summary.replayDirectory = Engine.GetCurrentReplayDirectory(); 552 summary.replaySelectionData = g_ReplaySelectionData; 543 if (!willRejoin && 544 simData[Engine.GetPlayerID()] && 545 simData[Engine.GetPlayerID()].state == "active") 546 resignGame(true); 553 547 554 548 Engine.EndGame(); 555 549 556 550 if (g_IsController && Engine.HasXmppClient()) 557 551 Engine.SendUnregisterGame(); 558 552 559 summary.gameResult = gameResult; 560 summary.isReplay = g_IsReplay; 561 Engine.SwitchGuiPage("page_summary.xml", summary); 553 Engine.SwitchGuiPage("page_summary.xml", { 554 "gui": guiData, 555 "sim": simData 556 }); 562 557 } 563 558 564 559 // Return some data that we'll use when hotloading this file after changes 565 560 function getHotloadData() 566 561 { … … function onTick() 603 598 604 599 let now = new Date(); 605 600 let tickLength = new Date() - lastTickTime; 606 601 lastTickTime = now; 607 602 608 checkPlayerState();609 610 603 handleNetMessages(); 611 604 612 605 updateCursorAndTooltip(); 613 606 614 607 if (g_Selection.dirty) … … function onTick() 630 623 Engine.GetGUIObjectByName("resourcePop").textcolor = g_IsTrainingBlocked && Date.now() % 1000 < 500 ? g_PopulationAlertColor : g_DefaultPopulationColor; 631 624 632 625 Engine.GuiInterfaceCall("ClearRenamedEntities"); 633 626 } 634 627 635 function checkPlayerState()636 {637 if (g_GameEnded || Engine.GetPlayerID() < 1)638 return;639 640 // Send a game report for each player in this game.641 let m_simState = GetSimState();642 let playerState = m_simState.players[Engine.GetPlayerID()];643 let tempStates = "";644 for (let player of m_simState.players)645 tempStates += player.state + ",";646 647 if (g_CachedLastStates != tempStates)648 {649 g_CachedLastStates = tempStates;650 reportGame();651 }652 653 if (playerState.state == "active")654 return;655 656 // Make sure nothing is open to avoid stacking.657 closeOpenDialogs();658 659 // Make sure this doesn't run again.660 g_GameEnded = true;661 662 // Select observermode663 Engine.GetGUIObjectByName("viewPlayer").selected = playerState.state == "won" ? g_ViewedPlayer + 1 : 0;664 665 let btCaptions;666 let btCode;667 let message;668 let title;669 if (Engine.IsAtlasRunning())670 {671 // If we're in Atlas, we can't leave the game672 btCaptions = [translate("OK")];673 btCode = [null];674 message = translate("Press OK to continue");675 }676 else677 {678 btCaptions = [translate("No"), translate("Yes")];679 btCode = [null, leaveGame];680 message = translate("Do you want to quit?");681 }682 683 if (playerState.state == "defeated")684 {685 title = translate("DEFEATED!");686 global.music.setState(global.music.states.DEFEAT);687 }688 else if (playerState.state == "won")689 {690 title = translate("VICTORIOUS!");691 global.music.setState(global.music.states.VICTORY);692 // TODO: Reveal map directly instead of this silly proxy.693 if (!Engine.GetGUIObjectByName("devCommandsRevealMap").checked)694 Engine.GetGUIObjectByName("devCommandsRevealMap").checked = true;695 }696 697 messageBox(400, 200, message, title, btCaptions, btCode);698 }699 700 628 function changeGameSpeed(speed) 701 629 { 702 630 if (!g_IsNetworked) 703 631 Engine.SetSimRate(speed); 704 632 } … … function onSimulationUpdate() 735 663 736 664 if (!g_SimState) 737 665 return; 738 666 739 667 handleNotifications(); 740 741 668 updateGUIObjects(); 669 670 if (g_ConfirmExit) 671 confirmExit(); 672 } 673 674 /** 675 * Don't show the message box before all playerstate changes are processed. 676 */ 677 function confirmExit() 678 { 679 closeOpenDialogs(); 680 681 let subject = g_ConfirmExit == "won" ? 682 translate("You have won!") : 683 translate("You have been defeated!"); 684 685 subject += "\n" + translate("Do you want to quit?"); 686 687 if (g_IsNetworked && g_IsController) 688 subject += "\n" + translate("Leaving will disconnect all other players."); 689 690 messageBox( 691 400, 200, 692 subject, 693 g_ConfirmExit == "won" ? 694 translate("VICTORIOUS!") : 695 translate("DEFEATED!"), 696 [translate("No"), translate("Yes")], 697 [resumeGame, leaveGame] 698 ); 699 700 g_ConfirmExit = false; 742 701 } 743 702 744 703 function updateGUIObjects() 745 704 { 746 705 g_Selection.update(); … … function updateGUIObjects() 768 727 let playerState = GetSimState().players[g_ViewedPlayer]; 769 728 g_DevSettings.controlAll = playerState && playerState.controlsAll; 770 729 Engine.GetGUIObjectByName("devControlAll").checked = g_DevSettings.controlAll; 771 730 } 772 731 773 if ( g_ViewedPlayer != -1 && !g_GameEnded)732 if (!g_IsObserver) 774 733 { 775 734 // Update music state on basis of battle state. 776 735 let battleState = Engine.GuiInterfaceCall("GetBattleState", g_ViewedPlayer); 777 736 if (battleState) 778 737 global.music.setState(global.music.states[battleState]); … … function updateGUIStatusBar(nameOfBar, p 826 785 healthSize.rtop = value; 827 786 828 787 statusBar.size = healthSize; 829 788 } 830 789 831 832 790 function updateHeroes() 833 791 { 834 792 let playerState = GetSimState().players[g_ViewedPlayer]; 835 793 let heroes = playerState ? playerState.heroes : []; 836 794 … … function playAmbient() 1140 1098 Engine.PlayAmbientSound(g_Ambient[Math.floor(Math.random() * g_Ambient.length)], true); 1141 1099 } 1142 1100 1143 1101 function getBuildString() 1144 1102 { 1145 return sprintf(translate("Build: %(buildDate)s (%(revision)s)"), { "buildDate": Engine.GetBuildTimestamp(0), revision: Engine.GetBuildTimestamp(2) }); 1103 return sprintf(translate("Build: %(buildDate)s (%(revision)s)"), { 1104 "buildDate": Engine.GetBuildTimestamp(0), 1105 "revision": Engine.GetBuildTimestamp(2) 1106 }); 1146 1107 } 1147 1108 1148 1109 function showTimeWarpMessageBox() 1149 1110 { 1150 1111 messageBox( … … function showTimeWarpMessageBox() 1158 1119 * Send a report on the gamestatus to the lobby. 1159 1120 */ 1160 1121 function reportGame() 1161 1122 { 1162 1123 // Only 1v1 games are rated (and Gaia is part of g_Players) 1163 if (!Engine.HasXmppClient() || !Engine.IsRankedGame() || g_Players.length != 3) 1124 if (!Engine.HasXmppClient() || !Engine.IsRankedGame() || 1125 g_Players.length != 3 || Engine.GetPlayerID() == -1) 1164 1126 return; 1165 1127 1166 1128 let extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState"); 1167 1129 1168 1130 let unitsClasses = [ -
binaries/data/mods/public/gui/session/utility_functions.js
1 /** 2 * Before removing data, consider this data is partially used in the replay menu. 3 */ 1 4 function getPlayerData(previousData = undefined) 2 5 { 3 6 let players = []; 4 7 5 8 let simState = GetSimState(); -
binaries/data/mods/public/gui/summary/layout.js
function updateGeneralPanelTeams() 315 315 // If there are no players without team, hide "player name" heading 316 316 if (!g_WithoutTeam) 317 317 Engine.GetGUIObjectByName("playerNameHeading").caption = ""; 318 318 } 319 319 320 function updateObjectPlayerPosition()320 function initPlayerBoxPositions() 321 321 { 322 322 for (let h = 0; h < g_MaxPlayers; ++h) 323 323 { 324 324 let playerBox = Engine.GetGUIObjectByName("playerBox[" + h + "]"); 325 325 let boxSize = playerBox.size; -
binaries/data/mods/public/gui/summary/summary.js
function updatePanelData(panelInfo) 80 80 updateGeneralPanelTeams(); 81 81 82 82 let playerBoxesCounts = [ ]; 83 83 for (let i = 0; i < g_PlayerCount; ++i) 84 84 { 85 let playerState = g_GameData. playerStates[i+1];85 let playerState = g_GameData.sim.playerStates[i+1]; 86 86 87 87 if (!playerBoxesCounts[playerState.team+1]) 88 88 playerBoxesCounts[playerState.team+1] = 1; 89 89 else 90 90 playerBoxesCounts[playerState.team+1] += 1; … … function updatePanelData(panelInfo) 104 104 playerCivicBoxColumn = "civIcont[" + playerState.team + "][" + positionObject + "]"; 105 105 playerCounterValue = "valueDataTeam[" + playerState.team + "][" + positionObject + "]"; 106 106 } 107 107 108 108 let colorString = "color: " + 109 110 111 109 Math.floor(playerState.color.r * 255) + " " + 110 Math.floor(playerState.color.g * 255) + " " + 111 Math.floor(playerState.color.b * 255); 112 112 113 113 let rowPlayerObject = Engine.GetGUIObjectByName(rowPlayer); 114 114 rowPlayerObject.hidden = false; 115 115 rowPlayerObject.sprite = colorString + g_PlayerBoxAlpha; 116 116 … … function updatePanelData(panelInfo) 119 119 rowPlayerObject.size = boxSize; 120 120 121 121 let playerColorBox = Engine.GetGUIObjectByName(playerColorBoxColumn); 122 122 playerColorBox.sprite = colorString + g_PlayerColorBoxAlpha; 123 123 124 Engine.GetGUIObjectByName(playerNameColumn).caption = g_GameData. players[i+1].name;124 Engine.GetGUIObjectByName(playerNameColumn).caption = g_GameData.sim.playerStates[i+1].name; 125 125 126 126 let civIcon = Engine.GetGUIObjectByName(playerCivicBoxColumn); 127 127 civIcon.sprite = "stretched:" + g_CivData[playerState.civ].Emblem; 128 128 civIcon.tooltip = g_CivData[playerState.civ].Name; 129 129 … … function updatePanelData(panelInfo) 135 135 let teamCounterFn = panelInfo.teamCounterFn; 136 136 if (g_Teams && teamCounterFn) 137 137 teamCounterFn(panelInfo.counters); 138 138 } 139 139 140 function confirmStartReplay() 141 { 142 if (Engine.HasXmppClient()) 143 messageBox( 144 400, 200, 145 translate("Are you sure you want to quit the lobby?"), 146 translate("Confirmation"), 147 [translate("No"), translate("Yes")], 148 [null, startReplay] 149 ); 150 else 151 startReplay(); 152 } 153 154 function continueButton() 155 { 156 if (g_GameData.gui.isInGame) 157 Engine.PopGuiPageCB(0); 158 else if (g_GameData.gui.isReplay) 159 Engine.SwitchGuiPage("page_replaymenu.xml", { 160 "replaySelectionData": g_GameData.gui.replaySelectionData 161 }); 162 else if (Engine.HasXmppClient()) 163 Engine.SwitchGuiPage("page_lobby.xml"); 164 else 165 Engine.SwitchGuiPage("page_pregame.xml"); 166 } 167 140 168 function startReplay() 141 169 { 142 170 if (Engine.HasXmppClient()) 143 171 Engine.StopXmppClient(); 144 172 145 Engine.StartVisualReplay(g_GameData. replayDirectory);173 Engine.StartVisualReplay(g_GameData.gui.replayDirectory); 146 174 Engine.SwitchGuiPage("page_loading.xml", { 147 "attribs": Engine.GetReplayAttributes(g_GameData. replayDirectory),175 "attribs": Engine.GetReplayAttributes(g_GameData.gui.replayDirectory), 148 176 "isNetworked": false, 149 177 "playerAssignments": { 150 178 "local": { 151 179 "name": singleplayerName(), 152 180 "player": -1 153 181 } 154 182 }, 155 183 "savedGUIData": "", 156 184 "isReplay": true, 157 "replaySelectionData": g_GameData. replaySelectionData185 "replaySelectionData": g_GameData.gui.replaySelectionData 158 186 }); 159 187 } 160 188 161 189 function init(data) 162 190 { 163 updateObjectPlayerPosition();164 191 g_GameData = data; 165 192 166 let mapSize = data.mapSettings.Size && g_Settings.MapSizes.find(size => size.Tiles == data.mapSettings.Size); 167 let mapType = g_Settings.MapTypes.find(mapType => mapType.Name == data.mapSettings.mapType); 193 let assignedState = g_GameData.sim.playerStates[g_GameData.gui.assignedPlayer || -1]; 168 194 195 Engine.GetGUIObjectByName("summaryText").caption = 196 !assignedState ? 197 translate("You have left the game.") : 198 g_GameData.gui.disconnected ? 199 translate("You have been disconnected.") : 200 assignedState.state == "won" ? 201 translate("You have won the battle!") : 202 assignedState.state == "defeated" ? 203 translate("You have been defeated...") : 204 translate("You have abandoned the game."); 205 206 initPlayerBoxPositions(); 207 169 208 Engine.GetGUIObjectByName("timeElapsed").caption = sprintf( 170 209 translate("Game time elapsed: %(time)s"), { 171 "time": timeToString( data.timeElapsed)210 "time": timeToString(g_GameData.sim.timeElapsed) 172 211 }); 173 212 174 Engine.GetGUIObjectByName("summaryText").caption = data.gameResult; 213 let mapType = g_Settings.MapTypes.find(mapType => mapType.Name == g_GameData.sim.mapSettings.mapType); 214 let mapSize = g_Settings.MapSizes.find(size => size.Tiles == g_GameData.sim.mapSettings.Size || 0); 175 215 176 216 Engine.GetGUIObjectByName("mapName").caption = sprintf( 177 217 translate("%(mapName)s - %(mapType)s"), { 178 "mapName": translate( data.mapSettings.Name),218 "mapName": translate(g_GameData.sim.mapSettings.Name), 179 219 "mapType": mapSize ? mapSize.LongName : (mapType ? mapType.Title : "") 180 220 }); 181 221 182 Engine.GetGUIObjectByName("replayButton").hidden = g_GameData. isInGame || !g_GameData.replayDirectory;222 Engine.GetGUIObjectByName("replayButton").hidden = g_GameData.gui.isInGame || !g_GameData.gui.replayDirectory; 183 223 184 224 // Panels 185 g_PlayerCount = data. playerStates.length - 1;225 g_PlayerCount = data.sim.playerStates.length - 1; 186 226 187 if (data. mapSettings.LockTeams)227 if (data.sim.mapSettings.LockTeams) 188 228 { 189 229 // Count teams 190 230 for (let t = 0; t < g_PlayerCount; ++t) 191 231 { 192 let playerTeam = data.playerStates[t+1].team;232 let playerTeam = g_GameData.sim.playerStates[t+1].team; 193 233 g_Teams[playerTeam] = (g_Teams[playerTeam] || 0) + 1; 194 234 } 195 235 196 236 if (g_Teams.length == g_PlayerCount) 197 237 g_Teams = false; // Each player has his own team. Displaying teams makes no sense. … … function init(data) 201 241 202 242 // Erase teams data if teams are not displayed 203 243 if (!g_Teams) 204 244 { 205 245 for (let p = 0; p < g_PlayerCount; ++p) 206 data.playerStates[p+1].team = -1;246 g_GameData.sim.playerStates[p+1].team = -1; 207 247 } 208 248 209 249 g_WithoutTeam = g_PlayerCount; 210 250 if (g_Teams) 211 251 { -
binaries/data/mods/public/gui/summary/summary.xml
1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 3 <!--4 ==========================================5 - POST-GAME SUMMARY SCREEN -6 ==========================================7 -->8 9 3 <objects> 10 4 <script file="gui/common/functions_global_object.js"/> 11 5 <script file="gui/common/functions_civinfo.js"/> 12 6 <script file="gui/common/functions_utility.js"/> 13 7 <script file="gui/common/settings.js"/> … … 162 156 </object> 163 157 </object> 164 158 165 159 <object type="button" name="replayButton" style="ModernButtonRed" size="100%-310 100%-48 100%-170 100%-20"> 166 160 <translatableAttribute id="caption">Replay</translatableAttribute> 167 <action on="Press"><![CDATA[ 168 if (g_GameData.isInGame) 169 return; 170 171 if (Engine.HasXmppClient()) 172 messageBox( 173 400, 200, 174 translate("Are you sure you want to quit the lobby?"), 175 translate("Confirmation"), 176 [translate("No"), translate("Yes")], 177 [null, startReplay] 178 ); 179 else 180 startReplay(); 181 ]]> 182 </action> 161 <action on="Press">confirmStartReplay();</action> 183 162 </object> 184 163 185 164 <object type="button" style="ModernButtonRed" size="100%-160 100%-48 100%-20 100%-20"> 186 165 <translatableAttribute id="caption">Continue</translatableAttribute> 187 <action on="Press"><![CDATA[ 188 if (g_GameData.isInGame) 189 { 190 Engine.PopGuiPageCB(0); 191 } 192 else if (g_GameData.isReplay) 193 { 194 Engine.SwitchGuiPage("page_replaymenu.xml", { "replaySelectionData": g_GameData.replaySelectionData }); 195 } 196 else if (!Engine.HasXmppClient()) 197 { 198 Engine.SwitchGuiPage("page_pregame.xml"); 199 } 200 else 201 { 202 Engine.LobbySetPlayerPresence("available"); 203 Engine.SwitchGuiPage("page_lobby.xml"); 204 } 205 ]]> 206 </action> 166 <action on="Press">continueButton();</action> 207 167 </object> 208 168 </object> 209 169 </objects> -
binaries/data/mods/public/maps/scripts/ConquestCommon.js
Trigger.prototype.ConquestHandlerOwnerSh 23 23 let index = entities.indexOf(msg.entity); 24 24 25 25 if (index >= 0) 26 26 { 27 27 entities.splice(index, 1); 28 if (!entities.length && Engine.QueryInterface(this.conquestEntitiesByPlayer[msg.from].player, IID_Player).GetState() == "active") 29 Engine.PostMessage(this.conquestEntitiesByPlayer[msg.from].player, MT_PlayerDefeated, { "playerId": msg.from } ); 28 if (!entities.length) 29 { 30 let cmpPlayer = QueryPlayerIDInterface(msg.from); 31 if (cmpPlayer) 32 cmpPlayer.SetState("defeated"); 33 } 30 34 } 31 35 } 32 36 33 37 Trigger.prototype.ConquestAddStructure = function(msg) 34 38 { -
binaries/data/mods/public/maps/scripts/TriggerHelper.js
TriggerHelper.GetResourceType = function 112 112 113 113 return cmpResourceSupply.GetType(); 114 114 }; 115 115 116 116 /** 117 * Wins the game for a player 117 * The given player will win the game. 118 * If it's not a last man standing game, the allies will win too. 118 119 */ 119 120 TriggerHelper.SetPlayerWon = function(playerID) 120 121 { 121 122 let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager); 122 123 cmpEndGameManager.MarkPlayerAsWon(playerID); … … TriggerHelper.SetPlayerWon = function(pl 125 126 /** 126 127 * Defeats a player 127 128 */ 128 129 TriggerHelper.DefeatPlayer = function(playerID) 129 130 { 130 let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 131 let playerEnt = cmpPlayerManager.GetPlayerByID(playerID); 132 133 Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": playerID } ); 131 let cmpPlayer = QueryPlayerIDInterface(playerID); 132 if (cmpPlayer) 133 cmpPlayer.SetState("defeated"); 134 134 }; 135 135 136 136 /** 137 137 * Returns the number of current players 138 138 */ -
binaries/data/mods/public/simulation/components/EndGameManager.js
1 1 /** 2 * System component which regularly checks victory/defeat conditions3 * and if they are satisfied then it marks the player as victorious/defeated.2 * System component to store the gametype, gametype settings and 3 * check for allied victory / last-man-standing. 4 4 */ 5 5 function EndGameManager() {} 6 6 7 7 EndGameManager.prototype.Schema = 8 8 "<a:component type='system'/><empty/>"; … … EndGameManager.prototype.Init = function 17 17 18 18 // Allied victory means allied players can win if victory conditions are met for each of them 19 19 // False for a "last man standing" game 20 20 this.alliedVictory = true; 21 21 22 // Don't do any checks before the diplomacies were set for each player 23 // or when marking a player as won. 24 this.skipAlliedVictoryCheck = true; 25 22 26 this.lastManStandingMessage = undefined; 23 27 }; 24 28 25 29 EndGameManager.prototype.GetGameType = function() 26 30 { … … EndGameManager.prototype.CheckGameType = 39 43 40 44 EndGameManager.prototype.SetGameType = function(newGameType, newSettings = {}) 41 45 { 42 46 this.gameType = newGameType; 43 47 this.gameTypeSettings = newSettings; 48 this.skipAlliedVictoryCheck = false; 44 49 45 50 Engine.BroadcastMessage(MT_GameTypeChanged, {}); 46 51 }; 47 52 48 53 EndGameManager.prototype.MarkPlayerAsWon = function(playerID) 49 54 { 50 55 let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 51 56 let numPlayers = cmpPlayerManager.GetNumPlayers(); 52 57 53 for (let i = 1; i < numPlayers; ++i) 54 { 55 let playerEntityId = cmpPlayerManager.GetPlayerByID(i); 56 let cmpPlayer = Engine.QueryInterface(playerEntityId, IID_Player); 58 this.skipAlliedVictoryCheck = true; 57 59 58 if (cmpPlayer.GetState() != "active") 59 continue; 60 // Group win/defeat messages 61 for (let won of [false, true]) 62 for (let i = 1; i < numPlayers; ++i) 63 { 64 let cmpPlayer = QueryPlayerIDInterface(i); 65 let hasWon = playerID == i || this.alliedVictory && cmpPlayer.IsMutualAlly(playerID); 60 66 61 if (playerID == cmpPlayer.GetPlayerID() || this.alliedVictory && cmpPlayer.IsMutualAlly(playerID)) 62 cmpPlayer.SetState("won"); 63 else 64 Engine.PostMessage(playerEntityId, MT_PlayerDefeated, { 65 "playerId": i, 66 "skipAlliedVictoryCheck": true 67 }); 68 } 67 if (hasWon == won) 68 cmpPlayer.SetState(won ? "won" : "defeated"); 69 } 69 70 70 // Reveal the map to all players 71 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 72 cmpRangeManager.SetLosRevealAll(-1, true); 71 this.skipAlliedVictoryCheck = false; 73 72 }; 74 73 75 74 EndGameManager.prototype.SetAlliedVictory = function(flag) 76 75 { 77 76 this.alliedVictory = flag; 78 77 }; 79 78 80 79 EndGameManager.prototype.AlliedVictoryCheck = function() 81 80 { 81 if (this.skipAlliedVictoryCheck) 82 return; 83 82 84 let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 83 85 let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 84 86 if (!cmpGuiInterface || !cmpPlayerManager) 85 87 return; 86 88 … … EndGameManager.prototype.AlliedVictoryCh 99 101 100 102 allies.push(playerID); 101 103 } 102 104 103 105 if (this.alliedVictory || allies.length == 1) 104 {105 106 for (let playerID of allies) 106 107 { 107 108 let cmpPlayer = QueryPlayerIDInterface(playerID); 108 109 if (cmpPlayer) 109 110 cmpPlayer.SetState("won"); 110 111 } 111 112 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);113 if (cmpRangeManager)114 cmpRangeManager.SetLosRevealAll(-1, true);115 }116 112 else 117 113 this.lastManStandingMessage = cmpGuiInterface.AddTimeNotification({ 118 114 "message": markForTranslation("Last remaining player wins."), 119 115 "translateMessage": true, 120 116 }, 12 * 60 * 60 * 1000); // 12 hours … … EndGameManager.prototype.OnInitGame = fu 125 121 this.AlliedVictoryCheck(); 126 122 }; 127 123 128 124 EndGameManager.prototype.OnGlobalDiplomacyChanged = function(msg) 129 125 { 130 if (!msg.skipAlliedVictoryCheck) 131 this.AlliedVictoryCheck(); 126 this.AlliedVictoryCheck(); 132 127 }; 133 128 134 129 EndGameManager.prototype.OnGlobalPlayerDefeated = function(msg) 135 130 { 136 if (!msg.skipAlliedVictoryCheck) 137 this.AlliedVictoryCheck(); 131 this.AlliedVictoryCheck(); 138 132 }; 139 133 140 134 Engine.RegisterSystemComponentType(IID_EndGameManager, "EndGameManager", EndGameManager); -
binaries/data/mods/public/simulation/components/Player.js
Player.prototype.SetTradingGoods = funct 357 357 Player.prototype.GetState = function() 358 358 { 359 359 return this.state; 360 360 }; 361 361 362 Player.prototype.SetState = function(newState )362 Player.prototype.SetState = function(newState, resign) 363 363 { 364 if (this.state != "active") 365 return; 366 367 if (newState != "won" && newState != "defeated") 368 { 369 warn("Can't change playerstate to " + this.state); 370 return; 371 } 372 364 373 this.state = newState; 374 375 let won = newState == "won"; 376 377 // Reveal map to all or only that player 378 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 379 cmpRangeManager.SetLosRevealAll(won ? -1 : this.playerID, true); 380 381 if (!won) 382 { 383 // Reassign all player's entities to Gaia 384 let entities = cmpRangeManager.GetEntitiesByPlayer(this.playerID); 385 386 // The ownership change is done in two steps so that entities don't hit idle 387 // (and thus possibly look for "enemies" to attack) before nearby allies get 388 // converted to Gaia as well. 389 for (let entity of entities) 390 { 391 let cmpOwnership = Engine.QueryInterface(entity, IID_Ownership); 392 cmpOwnership.SetOwnerQuiet(0); 393 } 394 395 // With the real ownership change complete, send OwnershipChanged messages. 396 for (let entity of entities) 397 Engine.PostMessage(entity, MT_OwnershipChanged, { 398 "entity": entity, 399 "from": this.playerID, 400 "to": 0 401 }); 402 } 403 404 Engine.BroadcastMessage(won ? MT_PlayerWon : MT_PlayerDefeated, { "playerId": this.playerID }); 405 406 let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 407 if (won) 408 cmpGUIInterface.PushNotification({ 409 "type": "won", 410 "players": [this.playerID] 411 }); 412 else 413 cmpGUIInterface.PushNotification({ 414 "type": "defeat", 415 "players": [this.playerID], 416 "resign": resign 417 }); 365 418 }; 366 419 367 420 Player.prototype.GetTeam = function() 368 421 { 369 422 return this.team; 370 423 }; 371 424 372 Player.prototype.SetTeam = function(team , skipAlliedVictoryCheck = false)425 Player.prototype.SetTeam = function(team) 373 426 { 374 427 if (this.teamsLocked) 375 428 return; 376 429 377 430 this.team = team; … … Player.prototype.SetTeam = function(team 383 436 { 384 437 let cmpPlayer = QueryPlayerIDInterface(i); 385 438 if (this.team != cmpPlayer.GetTeam()) 386 439 continue; 387 440 388 this.SetAlly(i , skipAlliedVictoryCheck);389 cmpPlayer.SetAlly(this.playerID , skipAlliedVictoryCheck);441 this.SetAlly(i); 442 cmpPlayer.SetAlly(this.playerID); 390 443 } 391 444 392 445 Engine.BroadcastMessage(MT_DiplomacyChanged, { 393 446 "player": this.playerID, 394 "otherPlayer": null, 395 "skipAlliedVictoryCheck": skipAlliedVictoryCheck 447 "otherPlayer": null 396 448 }); 397 449 }; 398 450 399 451 Player.prototype.SetLockTeams = function(value) 400 452 { … … Player.prototype.GetLockTeams = function 409 461 Player.prototype.GetDiplomacy = function() 410 462 { 411 463 return this.diplomacy; 412 464 }; 413 465 414 Player.prototype.SetDiplomacy = function(dipl , skipAlliedVictoryCheck = false)466 Player.prototype.SetDiplomacy = function(dipl) 415 467 { 416 468 this.diplomacy = dipl; 417 469 418 470 Engine.BroadcastMessage(MT_DiplomacyChanged, { 419 471 "player": this.playerID, 420 "otherPlayer": null, 421 "skipAlliedVictoryCheck": skipAlliedVictoryCheck 472 "otherPlayer": null 422 473 }); 423 474 }; 424 475 425 Player.prototype.SetDiplomacyIndex = function(idx, value , skipAlliedVictoryCheck = false)476 Player.prototype.SetDiplomacyIndex = function(idx, value) 426 477 { 427 478 let cmpPlayer = QueryPlayerIDInterface(idx); 428 479 if (!cmpPlayer) 429 480 return; 430 481 … … Player.prototype.SetDiplomacyIndex = fun 433 484 434 485 this.diplomacy[idx] = value; 435 486 436 487 Engine.BroadcastMessage(MT_DiplomacyChanged, { 437 488 "player": this.playerID, 438 "otherPlayer": cmpPlayer.GetPlayerID(), 439 "skipAlliedVictoryCheck": skipAlliedVictoryCheck 489 "otherPlayer": cmpPlayer.GetPlayerID() 440 490 }); 441 491 442 492 // Mutual worsening of relations 443 493 if (cmpPlayer.diplomacy[this.playerID] > value) 444 cmpPlayer.SetDiplomacyIndex(this.playerID, value , skipAlliedVictoryCheck);494 cmpPlayer.SetDiplomacyIndex(this.playerID, value); 445 495 }; 446 496 447 497 Player.prototype.UpdateSharedLos = function() 448 498 { 449 499 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); … … Player.prototype.SetAI = function(flag) 518 568 Player.prototype.IsAI = function() 519 569 { 520 570 return this.isAI; 521 571 }; 522 572 523 Player.prototype.SetAlly = function(id , skipAlliedVictoryCheck = false)573 Player.prototype.SetAlly = function(id) 524 574 { 525 this.SetDiplomacyIndex(id, 1 , skipAlliedVictoryCheck);575 this.SetDiplomacyIndex(id, 1); 526 576 }; 527 577 528 578 /** 529 579 * Check if given player is our ally 530 580 */ … … Player.prototype.IsMutualAlly = function 556 606 Player.prototype.IsExclusiveMutualAlly = function(id) 557 607 { 558 608 return this.playerID != id && this.IsMutualAlly(id); 559 609 }; 560 610 561 Player.prototype.SetEnemy = function(id , skipAlliedVictoryCheck = false)611 Player.prototype.SetEnemy = function(id) 562 612 { 563 this.SetDiplomacyIndex(id, -1 , skipAlliedVictoryCheck);613 this.SetDiplomacyIndex(id, -1); 564 614 }; 565 615 566 616 /** 567 617 * Get all enemies of a given player. 568 618 */ … … Player.prototype.GetEnemies = function() 581 631 Player.prototype.IsEnemy = function(id) 582 632 { 583 633 return this.diplomacy[id] < 0; 584 634 }; 585 635 586 Player.prototype.SetNeutral = function(id , skipAlliedVictoryCheck = false)636 Player.prototype.SetNeutral = function(id) 587 637 { 588 this.SetDiplomacyIndex(id, 0 , skipAlliedVictoryCheck);638 this.SetDiplomacyIndex(id, 0); 589 639 }; 590 640 591 641 /** 592 642 * Check if given player is neutral 593 643 */ … … Player.prototype.OnGlobalOwnershipChange 647 697 if (cmpIdentity && cmpIdentity.HasClass("Hero")) 648 698 this.heroes.push(msg.entity); 649 699 } 650 700 }; 651 701 652 Player.prototype.OnPlayerDefeated = function(msg)653 {654 this.state = "defeated";655 656 // Reassign all player's entities to Gaia657 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);658 var entities = cmpRangeManager.GetEntitiesByPlayer(this.playerID);659 660 // The ownership change is done in two steps so that entities don't hit idle661 // (and thus possibly look for "enemies" to attack) before nearby allies get662 // converted to Gaia as well.663 for (var entity of entities)664 {665 var cmpOwnership = Engine.QueryInterface(entity, IID_Ownership);666 cmpOwnership.SetOwnerQuiet(0);667 }668 669 // With the real ownership change complete, send OwnershipChanged messages.670 for (var entity of entities)671 Engine.PostMessage(entity, MT_OwnershipChanged, {672 "entity": entity,673 "from": this.playerID,674 "to": 0675 });676 677 // Reveal the map for this player.678 cmpRangeManager.SetLosRevealAll(this.playerID, true);679 680 // Send a chat message notifying of the player's defeat.681 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);682 cmpGUIInterface.PushNotification({683 "type": "defeat",684 "players": [this.playerID],685 "resign": !!msg.resign686 });687 };688 689 702 Player.prototype.OnResearchFinished = function(msg) 690 703 { 691 704 if (msg.tech == this.template.SharedLosTech) 692 705 this.UpdateSharedLos(); 693 706 else if (msg.tech == this.template.SharedDropsitesTech) -
binaries/data/mods/public/simulation/components/PlayerManager.js
PlayerManager.prototype.AddPlayer = func 21 21 var cmpOtherPlayer = Engine.QueryInterface(this.GetPlayerByID(i), IID_Player); 22 22 cmpOtherPlayer.diplomacy[id] = -1; 23 23 newDiplo[i] = -1; 24 24 } 25 25 newDiplo[id] = 1; 26 cmpPlayer.SetDiplomacy(newDiplo , true);26 cmpPlayer.SetDiplomacy(newDiplo); 27 27 28 28 return id; 29 29 }; 30 30 31 31 /** -
binaries/data/mods/public/simulation/components/interfaces/EndGameManager.js
1 1 Engine.RegisterInterface("EndGameManager"); 2 2 Engine.RegisterMessageType("PlayerDefeated"); 3 Engine.RegisterMessageType("PlayerWon"); 3 4 Engine.RegisterMessageType("GameTypeChanged"); -
binaries/data/mods/public/simulation/helpers/Cheat.js
function Cheat(input) 46 46 else 47 47 Engine.DestroyEntity(ent); 48 48 } 49 49 return; 50 50 case "defeatplayer": 51 var playerEnt = cmpPlayerManager.GetPlayerByID(input.parameter); 52 if (playerEnt == INVALID_ENTITY) 53 return; 54 Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": input.parameter }); 51 cmpPlayer = QueryPlayerIDInterface(input.parameter); 52 if (cmpPlayer) 53 cmpPlayer.SetState("defeated"); 55 54 return; 56 55 case "createunits": 57 56 var cmpProductionQueue = input.selected.length && Engine.QueryInterface(input.selected[0], IID_ProductionQueue); 58 57 if (!cmpProductionQueue) 59 58 { -
binaries/data/mods/public/simulation/helpers/Commands.js
var g_Commands = { 412 412 } 413 413 }, 414 414 415 415 "defeat-player": function(player, cmd, data) 416 416 { 417 // Send "OnPlayerDefeated" message to player 418 Engine.PostMessage(data.playerEnt, MT_PlayerDefeated, { "playerId": player, "resign": !!cmd.resign }); 417 let cmpPlayer = QueryPlayerIDInterface(player); 418 if (cmpPlayer) 419 cmpPlayer.SetState("defeated", !!cmd.resign); 419 420 }, 420 421 421 422 "garrison": function(player, cmd, data) 422 423 { 423 424 // Verify that the building can be controlled by the player or is mutualAlly -
binaries/data/mods/public/simulation/helpers/Player.js
function LoadPlayerSettings(settings, ne 121 121 if (disabledTemplates.length) 122 122 cmpPlayer.SetDisabledTemplates(disabledTemplates); 123 123 124 124 // If diplomacy explicitly defined, use that; otherwise use teams 125 125 if (getSetting(playerData, playerDefaults, i, "Diplomacy") !== undefined) 126 cmpPlayer.SetDiplomacy(getSetting(playerData, playerDefaults, i, "Diplomacy") , true);126 cmpPlayer.SetDiplomacy(getSetting(playerData, playerDefaults, i, "Diplomacy")); 127 127 else 128 128 { 129 129 // Init diplomacy 130 130 var myTeam = getSetting(playerData, playerDefaults, i, "Team"); 131 131 … … function LoadPlayerSettings(settings, ne 135 135 if (i == j) 136 136 cmpPlayer.SetAlly(j); 137 137 else 138 138 cmpPlayer.SetEnemy(j); 139 139 } 140 cmpPlayer.SetTeam(myTeam === undefined ? -1 : myTeam , true);140 cmpPlayer.SetTeam(myTeam === undefined ? -1 : myTeam); 141 141 } 142 142 143 143 // If formations explicitly defined, use that; otherwise use civ defaults 144 144 var formations = getSetting(playerData, playerDefaults, i, "Formations"); 145 145 if (formations !== undefined)