mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-07-10 00:45:47 -07:00
When starting a game with exactly one player that instantly wins the game (consequest victory) and after that ceasefire running out will trigger first the correct victory chat message, then a broken and undefined have won the game chat message, initiated from the ceasefiremanager. Check for allies emptyness and do not send it if no players are active, what means they all have been defeated or won. Differential Revision: https://code.wildfiregames.com/D2891 Fixes: #5675 This was SVN commit r23857.
202 lines
5.7 KiB
JavaScript
202 lines
5.7 KiB
JavaScript
/**
|
|
* System component to store the victory conditions and their settings and
|
|
* check for allied victory / last-man-standing.
|
|
*/
|
|
function EndGameManager() {}
|
|
|
|
EndGameManager.prototype.Schema =
|
|
"<a:component type='system'/><empty/>";
|
|
|
|
EndGameManager.prototype.Init = function()
|
|
{
|
|
// Contains settings specific to the victory condition,
|
|
// for example wonder victory duration.
|
|
this.gameSettings = {};
|
|
|
|
// Allied victory means allied players can win if victory conditions are met for each of them
|
|
// False for a "last man standing" game
|
|
this.alliedVictory = true;
|
|
|
|
// Don't do any checks before the diplomacies were set for each player
|
|
// or when marking a player as won.
|
|
this.skipAlliedVictoryCheck = true;
|
|
|
|
this.lastManStandingMessage = undefined;
|
|
|
|
this.endlessGame = false;
|
|
};
|
|
|
|
EndGameManager.prototype.GetGameSettings = function()
|
|
{
|
|
return this.gameSettings;
|
|
};
|
|
|
|
EndGameManager.prototype.GetVictoryConditions = function()
|
|
{
|
|
return this.gameSettings.victoryConditions;
|
|
};
|
|
|
|
EndGameManager.prototype.SetGameSettings = function(newSettings = {})
|
|
{
|
|
this.gameSettings = newSettings;
|
|
this.skipAlliedVictoryCheck = false;
|
|
this.endlessGame = !this.gameSettings.victoryConditions.length;
|
|
|
|
Engine.BroadcastMessage(MT_VictoryConditionsChanged, {});
|
|
};
|
|
|
|
/**
|
|
* Sets the given player (and the allies if allied victory is enabled) as a winner.
|
|
*
|
|
* @param {number} playerID - The player that should win.
|
|
* @param {function} victoryReason - Function that maps from number to plural string, for example
|
|
* n => markForPluralTranslation(
|
|
* "%(lastPlayer)s has won (game mode).",
|
|
* "%(players)s and %(lastPlayer)s have won (game mode).",
|
|
* n));
|
|
*/
|
|
EndGameManager.prototype.MarkPlayerAndAlliesAsWon = function(playerID, victoryString, defeatString)
|
|
{
|
|
let state = QueryPlayerIDInterface(playerID).GetState();
|
|
if (state != "active")
|
|
{
|
|
warn("Can't mark player " + playerID + " as won, since the state is " + state);
|
|
return;
|
|
}
|
|
|
|
let winningPlayers = [playerID];
|
|
if (this.alliedVictory)
|
|
winningPlayers = QueryPlayerIDInterface(playerID).GetMutualAllies(playerID).filter(
|
|
player => QueryPlayerIDInterface(player).GetState() == "active");
|
|
|
|
this.MarkPlayersAsWon(winningPlayers, victoryString, defeatString);
|
|
};
|
|
|
|
/**
|
|
* Sets the given players as won and others as defeated.
|
|
*
|
|
* @param {array} winningPlayers - The players that should win.
|
|
* @param {function} victoryReason - Function that maps from number to plural string, for example
|
|
* n => markForPluralTranslation(
|
|
* "%(lastPlayer)s has won (game mode).",
|
|
* "%(players)s and %(lastPlayer)s have won (game mode).",
|
|
* n));
|
|
*/
|
|
EndGameManager.prototype.MarkPlayersAsWon = function(winningPlayers, victoryString, defeatString)
|
|
{
|
|
this.skipAlliedVictoryCheck = true;
|
|
for (let playerID of winningPlayers)
|
|
{
|
|
let cmpPlayer = QueryPlayerIDInterface(playerID);
|
|
let state = cmpPlayer.GetState();
|
|
if (state != "active")
|
|
{
|
|
warn("Can't mark player " + playerID + " as won, since the state is " + state);
|
|
continue;
|
|
}
|
|
cmpPlayer.SetState("won", undefined);
|
|
}
|
|
|
|
let defeatedPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetActivePlayers().filter(
|
|
playerID => winningPlayers.indexOf(playerID) == -1);
|
|
|
|
for (let playerID of defeatedPlayers)
|
|
QueryPlayerIDInterface(playerID).SetState("defeated", undefined);
|
|
|
|
let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
|
cmpGUIInterface.PushNotification({
|
|
"type": "won",
|
|
"players": [winningPlayers[0]],
|
|
"allies" : winningPlayers,
|
|
"message": victoryString(winningPlayers.length)
|
|
});
|
|
|
|
if (defeatedPlayers.length)
|
|
cmpGUIInterface.PushNotification({
|
|
"type": "defeat",
|
|
"players": [defeatedPlayers[0]],
|
|
"allies" : defeatedPlayers,
|
|
"message": defeatString(defeatedPlayers.length)
|
|
});
|
|
|
|
this.skipAlliedVictoryCheck = false;
|
|
};
|
|
|
|
EndGameManager.prototype.SetAlliedVictory = function(flag)
|
|
{
|
|
this.alliedVictory = flag;
|
|
};
|
|
|
|
EndGameManager.prototype.GetAlliedVictory = function()
|
|
{
|
|
return this.alliedVictory;
|
|
};
|
|
|
|
EndGameManager.prototype.AlliedVictoryCheck = function()
|
|
{
|
|
if (this.skipAlliedVictoryCheck || this.endlessGame)
|
|
return;
|
|
|
|
let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
|
cmpGuiInterface.DeleteTimeNotification(this.lastManStandingMessage);
|
|
|
|
// Proceed if only allies are remaining
|
|
let allies = [];
|
|
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
|
|
for (let playerID = 1; playerID < numPlayers; ++playerID)
|
|
{
|
|
let cmpPlayer = QueryPlayerIDInterface(playerID);
|
|
if (cmpPlayer.GetState() != "active")
|
|
continue;
|
|
|
|
if (allies.length && !cmpPlayer.IsMutualAlly(allies[0]))
|
|
return;
|
|
|
|
allies.push(playerID);
|
|
}
|
|
|
|
if (!allies.length)
|
|
return;
|
|
|
|
if (this.alliedVictory || allies.length == 1)
|
|
{
|
|
for (let playerID of allies)
|
|
{
|
|
let cmpPlayer = QueryPlayerIDInterface(playerID);
|
|
if (cmpPlayer)
|
|
cmpPlayer.SetState("won", undefined);
|
|
}
|
|
|
|
cmpGuiInterface.PushNotification({
|
|
"type": "won",
|
|
"players": [allies[0]],
|
|
"allies" : allies,
|
|
"message": markForPluralTranslation(
|
|
"%(lastPlayer)s has won (last player alive).",
|
|
"%(players)s and %(lastPlayer)s have won (last players alive).",
|
|
allies.length)
|
|
});
|
|
}
|
|
else
|
|
this.lastManStandingMessage = cmpGuiInterface.AddTimeNotification({
|
|
"message": markForTranslation("Last remaining player wins."),
|
|
"translateMessage": true,
|
|
}, 12 * 60 * 60 * 1000); // 12 hours
|
|
};
|
|
|
|
EndGameManager.prototype.OnInitGame = function(msg)
|
|
{
|
|
this.AlliedVictoryCheck();
|
|
};
|
|
|
|
EndGameManager.prototype.OnGlobalDiplomacyChanged = function(msg)
|
|
{
|
|
this.AlliedVictoryCheck();
|
|
};
|
|
|
|
EndGameManager.prototype.OnGlobalPlayerDefeated = function(msg)
|
|
{
|
|
this.AlliedVictoryCheck();
|
|
};
|
|
|
|
Engine.RegisterSystemComponentType(IID_EndGameManager, "EndGameManager", EndGameManager);
|