Line data Source code
1 : /** 2 : * System component to store the victory conditions and their settings and 3 : * check for allied victory / last-man-standing. 4 : */ 5 : function EndGameManager() {} 6 : 7 1 : EndGameManager.prototype.Schema = 8 : "<a:component type='system'/><empty/>"; 9 : 10 1 : EndGameManager.prototype.Init = function() 11 : { 12 : // Contains settings specific to the victory condition, 13 : // for example wonder victory duration. 14 1 : this.gameSettings = {}; 15 : 16 : // Allied victory means allied players can win if victory conditions are met for each of them 17 : // False for a "last man standing" game 18 1 : this.alliedVictory = true; 19 : 20 : // Don't do any checks before the diplomacies were set for each player 21 : // or when marking a player as won. 22 1 : this.skipAlliedVictoryCheck = true; 23 : 24 1 : this.lastManStandingMessage = undefined; 25 : 26 1 : this.endlessGame = false; 27 : }; 28 : 29 1 : EndGameManager.prototype.GetGameSettings = function() 30 : { 31 1 : return this.gameSettings; 32 : }; 33 : 34 1 : EndGameManager.prototype.GetVictoryConditions = function() 35 : { 36 1 : return this.gameSettings.victoryConditions; 37 : }; 38 : 39 1 : EndGameManager.prototype.SetGameSettings = function(newSettings = {}) 40 : { 41 1 : this.gameSettings = newSettings; 42 1 : this.skipAlliedVictoryCheck = false; 43 1 : this.endlessGame = !this.gameSettings.victoryConditions.length; 44 : 45 1 : Engine.BroadcastMessage(MT_VictoryConditionsChanged, {}); 46 : }; 47 : 48 : /** 49 : * Sets the given player (and the allies if allied victory is enabled) as a winner. 50 : * 51 : * @param {number} playerID - The player that should win. 52 : * @param {function} victoryReason - Function that maps from number to plural string, for example 53 : * n => markForPluralTranslation( 54 : * "%(lastPlayer)s has won (game mode).", 55 : * "%(players)s and %(lastPlayer)s have won (game mode).", 56 : * n)); 57 : */ 58 1 : EndGameManager.prototype.MarkPlayerAndAlliesAsWon = function(playerID, victoryString, defeatString) 59 : { 60 0 : const cmpPlayer = QueryPlayerIDInterface(playerID); 61 0 : if (!cmpPlayer.IsActive()) 62 : { 63 0 : warn("Can't mark player " + playerID + " as won, since the state is " + cmpPlayer.GetState()); 64 0 : return; 65 : } 66 : 67 0 : let winningPlayers = [playerID]; 68 0 : if (this.alliedVictory) 69 0 : winningPlayers = cmpPlayer.GetMutualAllies(playerID).filter( 70 0 : player => QueryPlayerIDInterface(player).IsActive()); 71 : 72 0 : this.MarkPlayersAsWon(winningPlayers, victoryString, defeatString); 73 : }; 74 : 75 : /** 76 : * Sets the given players as won and others as defeated. 77 : * 78 : * @param {array} winningPlayers - The players that should win. 79 : * @param {function} victoryReason - Function that maps from number to plural string, for example 80 : * n => markForPluralTranslation( 81 : * "%(lastPlayer)s has won (game mode).", 82 : * "%(players)s and %(lastPlayer)s have won (game mode).", 83 : * n)); 84 : */ 85 1 : EndGameManager.prototype.MarkPlayersAsWon = function(winningPlayers, victoryString, defeatString) 86 : { 87 0 : this.skipAlliedVictoryCheck = true; 88 0 : for (let playerID of winningPlayers) 89 : { 90 0 : let cmpPlayer = QueryPlayerIDInterface(playerID); 91 0 : if (!cmpPlayer.IsActive()) 92 : { 93 0 : warn("Can't mark player " + playerID + " as won, since the state is " + cmpPlayer.GetState()); 94 0 : continue; 95 : } 96 0 : cmpPlayer.Win(undefined); 97 : } 98 : 99 0 : let defeatedPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetActivePlayers().filter( 100 0 : playerID => winningPlayers.indexOf(playerID) == -1); 101 : 102 0 : for (let playerID of defeatedPlayers) 103 0 : QueryPlayerIDInterface(playerID).Defeat(undefined); 104 : 105 0 : let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 106 0 : cmpGUIInterface.PushNotification({ 107 : "type": "won", 108 : "players": [winningPlayers[0]], 109 : "allies": winningPlayers, 110 : "message": victoryString(winningPlayers.length) 111 : }); 112 : 113 0 : if (defeatedPlayers.length) 114 0 : cmpGUIInterface.PushNotification({ 115 : "type": "defeat", 116 : "players": [defeatedPlayers[0]], 117 : "allies": defeatedPlayers, 118 : "message": defeatString(defeatedPlayers.length) 119 : }); 120 : 121 0 : this.skipAlliedVictoryCheck = false; 122 : }; 123 : 124 1 : EndGameManager.prototype.SetAlliedVictory = function(flag) 125 : { 126 1 : this.alliedVictory = flag; 127 : }; 128 : 129 1 : EndGameManager.prototype.GetAlliedVictory = function() 130 : { 131 1 : return this.alliedVictory; 132 : }; 133 : 134 1 : EndGameManager.prototype.AlliedVictoryCheck = function() 135 : { 136 0 : if (this.skipAlliedVictoryCheck || this.endlessGame) 137 0 : return; 138 : 139 0 : let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 140 0 : cmpGuiInterface.DeleteTimeNotification(this.lastManStandingMessage); 141 : 142 : // Proceed if only allies are remaining 143 0 : let allies = []; 144 0 : let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); 145 0 : for (let playerID = 1; playerID < numPlayers; ++playerID) 146 : { 147 0 : let cmpPlayer = QueryPlayerIDInterface(playerID); 148 0 : if (!cmpPlayer.IsActive()) 149 0 : continue; 150 : 151 0 : if (allies.length && !cmpPlayer.IsMutualAlly(allies[0])) 152 0 : return; 153 : 154 0 : allies.push(playerID); 155 : } 156 : 157 0 : if (!allies.length) 158 0 : return; 159 : 160 0 : if (this.alliedVictory || allies.length == 1) 161 : { 162 0 : for (const playerID of allies) 163 0 : QueryPlayerIDInterface(playerID)?.Win(undefined); 164 : 165 0 : cmpGuiInterface.PushNotification({ 166 : "type": "won", 167 : "players": [allies[0]], 168 : "allies": allies, 169 : "message": markForPluralTranslation( 170 : "%(lastPlayer)s has won (last player alive).", 171 : "%(players)s and %(lastPlayer)s have won (last players alive).", 172 : allies.length) 173 : }); 174 : } 175 : else 176 0 : this.lastManStandingMessage = cmpGuiInterface.AddTimeNotification({ 177 : "message": markForTranslation("Last remaining player wins."), 178 : "translateMessage": true, 179 : }, 12 * 60 * 60 * 1000); // 12 hours 180 : }; 181 : 182 1 : EndGameManager.prototype.OnInitGame = function(msg) 183 : { 184 0 : this.AlliedVictoryCheck(); 185 : }; 186 : 187 1 : EndGameManager.prototype.OnGlobalDiplomacyChanged = function(msg) 188 : { 189 0 : this.AlliedVictoryCheck(); 190 : }; 191 : 192 1 : EndGameManager.prototype.OnGlobalPlayerDefeated = function(msg) 193 : { 194 0 : this.AlliedVictoryCheck(); 195 : }; 196 : 197 1 : Engine.RegisterSystemComponentType(IID_EndGameManager, "EndGameManager", EndGameManager);