Win and defeat cleanup, fixes #4013.

Add a new simulation message and chat notification for players who won.
Avoid duplicate playerstate messages in the sim and GUI by triggering
changes with a function instead of a message.
Reveal the map on defeat/win exclusively in the player component
(instead of having a silly GUI proxy and doing it also in the
EndGameManager sometimes).
Remove the skipAlliedVictory argument from the player component, since
that shouldn't contain references to the EndGameManager, refs #3970.

Show a proper message box on win/loss and add the hint for hosts
disconnecting other players.
Do defeat/win procedure in the GUI when such a message arrives, instead
of checking onTick for playerstate changes.
Thus don't show that confirmation again on every rejoin.
Don't show a pointless message box if IsAtlasRunning.

Explain that the session.js variable is needed to avoid an
order-of-execution bug.
Select "observer" item when rejoining as a defeated player.
Remove an unneeded call to updateTopPanel.

This was SVN commit r18441.
This commit is contained in:
elexis 2016-06-26 04:40:50 +00:00
parent 8da8d28102
commit 9f796068f8
12 changed files with 211 additions and 199 deletions

View file

@ -755,6 +755,7 @@ function toggleDeveloperOverlay()
function closeOpenDialogs()
{
// TODO: also close message boxes
closeMenu();
closeChat();
closeDiplomacy();

View file

@ -101,6 +101,7 @@ var g_FormatChatMessage = {
"clientlist": msg => getUsernameList(),
"message": msg => formatChatCommand(msg),
"defeat": msg => formatDefeatMessage(msg),
"won": msg => formatWinMessage(msg),
"diplomacy": msg => formatDiplomacyMessage(msg),
"tribute": msg => formatTributeMessage(msg),
"attack": msg => formatAttackMessage(msg)
@ -194,6 +195,8 @@ var g_DiplomacyMessages = {
/**
* Defines how the GUI reacts to notifications that are sent by the simulation.
* Don't open new pages (message boxes) here! Otherwise further notifications
* handled in the same turn can't access the GUI objects anymore.
*/
var g_NotificationsTypes =
{
@ -246,9 +249,16 @@ var g_NotificationsTypes =
"player": player,
"resign": !!notification.resign
});
updateDiplomacy();
updateChatAddressees();
playerFinished(player, false);
},
"won": function(notification, player)
{
addChatMessage({
"type": "won",
"guid": findGuidForPlayerID(player),
"player": player
});
playerFinished(player, true);
},
"diplomacy": function(notification, player)
{
@ -417,8 +427,7 @@ function findGuidForPlayerID(playerID)
*/
function handleNotifications()
{
let notifications = Engine.GuiInterfaceCall("GetNotifications");
for (let notification of notifications)
for (let notification of Engine.GuiInterfaceCall("GetNotifications"))
{
if (!notification.players || !notification.type || !g_NotificationsTypes[notification.type])
{
@ -745,6 +754,13 @@ function formatDefeatMessage(msg)
);
}
function formatWinMessage(msg)
{
return sprintf(translate("%(player)s has won."), {
"player": colorizePlayernameByID(msg.player)
});
}
function formatDiplomacyMessage(msg)
{
let messageType;

View file

@ -37,6 +37,11 @@ var g_IsObserver = false;
*/
var g_HasRejoined = false;
/**
* Shows a message box asking the user to leave if "won" or "defeated".
*/
var g_ConfirmExit = false;
/**
* True if the current player has paused the game explicitly.
*/
@ -118,17 +123,6 @@ var g_TemplateData = {};
var g_TemplateDataWithoutLocalization = {};
var g_TechnologyData = {};
/**
* Cache concatenated list of player states ("active", "defeated" or "won").
*/
var g_CachedLastStates = "";
/**
* Whether the current player has lost/won and reached the end of their game.
* Used for reporting the gamestate and showing the game-end message only once.
*/
var g_GameEnded = false;
/**
* Top coordinate of the research list.
* Changes depending on the number of displayed counters.
@ -240,8 +234,6 @@ function init(initData, hotloadData)
g_ReplaySelectionData = initData.replaySelectionData;
g_HasRejoined = initData.isRejoining;
g_Players = getPlayerData();
if (initData.savedGUIData)
restoreSavedGameData(initData.savedGUIData);
@ -251,15 +243,14 @@ function init(initData, hotloadData)
{
if (g_IsReplay)
g_PlayerAssignments.local.player = -1;
g_Players = getPlayerData();
}
g_Players = getPlayerData();
g_CivData = loadCivData();
g_CivData.gaia = { "Code": "gaia", "Name": translate("Gaia") };
initializeMusic(); // before changing the perspective
selectViewPlayer(g_ViewedPlayer);
let gameSpeed = Engine.GetGUIObjectByName("gameSpeed");
gameSpeed.list = g_GameSpeeds.Title;
@ -281,10 +272,12 @@ function init(initData, hotloadData)
playerNames.push(colorizePlayernameHelper("■", player) + " " + g_Players[player].name);
}
// Select "observer" item when rejoining as a defeated player
let viewedPlayer = g_Players[Engine.GetPlayerID()];
let viewPlayerDropdown = Engine.GetGUIObjectByName("viewPlayer");
viewPlayerDropdown.list = playerNames;
viewPlayerDropdown.list_data = playerIDs;
viewPlayerDropdown.selected = Engine.GetPlayerID() + 1;
viewPlayerDropdown.selected = viewedPlayer && viewedPlayer.state == "defeated" ? 0 : Engine.GetPlayerID() + 1;
// If in Atlas editor, disable the exit button
if (Engine.IsAtlasRunning())
@ -434,6 +427,31 @@ function controlsPlayer(playerID)
playerState.state != "defeated" || playerState.controlsAll);
}
/**
* Called when a player has won or was defeated.
*/
function playerFinished(player, won)
{
reportGame();
updateDiplomacy();
updateChatAddressees();
if (player != Engine.GetPlayerID() || Engine.IsAtlasRunning())
return;
global.music.setState(
won ?
global.music.states.VICTORY :
global.music.states.DEFEAT
);
// Select "observer" item
if (!won)
Engine.GetGUIObjectByName("viewPlayer").selected = 0;
g_ConfirmExit = won ? "won" : "defeated";
}
/**
* Sets civ icon for the currently viewed player.
* Hides most gui objects for observers.
@ -492,8 +510,6 @@ function resignGame(leaveGameAfterResign)
"resign": true
});
updateTopPanel();
global.music.setState(global.music.states.DEFEAT);
if (!leaveGameAfterResign)
@ -582,8 +598,6 @@ function onTick()
let tickLength = new Date() - lastTickTime;
lastTickTime = now;
checkPlayerState();
handleNetMessages();
updateCursorAndTooltip();
@ -609,71 +623,6 @@ function onTick()
Engine.GuiInterfaceCall("ClearRenamedEntities");
}
function checkPlayerState()
{
if (g_GameEnded || Engine.GetPlayerID() < 1)
return;
// Send a game report for each player in this game.
let m_simState = GetSimState();
let playerState = m_simState.players[Engine.GetPlayerID()];
let tempStates = "";
for (let player of m_simState.players)
tempStates += player.state + ",";
if (g_CachedLastStates != tempStates)
{
g_CachedLastStates = tempStates;
reportGame();
}
if (playerState.state == "active")
return;
// Make sure nothing is open to avoid stacking.
closeOpenDialogs();
// Make sure this doesn't run again.
g_GameEnded = true;
// Select observermode
Engine.GetGUIObjectByName("viewPlayer").selected = playerState.state == "won" ? g_ViewedPlayer + 1 : 0;
let btCaptions;
let btCode;
let message;
let title;
if (Engine.IsAtlasRunning())
{
// If we're in Atlas, we can't leave the game
btCaptions = [translate("OK")];
btCode = [null];
message = translate("Press OK to continue");
}
else
{
btCaptions = [translate("No"), translate("Yes")];
btCode = [null, leaveGame];
message = translate("Do you want to quit?");
}
if (playerState.state == "defeated")
{
title = translate("DEFEATED!");
global.music.setState(global.music.states.DEFEAT);
}
else if (playerState.state == "won")
{
title = translate("VICTORIOUS!");
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, title, btCaptions, btCode);
}
function changeGameSpeed(speed)
{
if (!g_IsNetworked)
@ -714,8 +663,39 @@ function onSimulationUpdate()
return;
handleNotifications();
updateGUIObjects();
if (g_ConfirmExit)
confirmExit();
}
/**
* Don't show the message box before all playerstate changes are processed.
*/
function confirmExit()
{
closeOpenDialogs();
let subject = g_ConfirmExit == "won" ?
translate("You have won!") :
translate("You have been defeated!");
subject += "\n" + translate("Do you want to quit?");
if (g_IsNetworked && g_IsController)
subject += "\n" + translate("Leaving will disconnect all other players.");
messageBox(
400, 200,
subject,
g_ConfirmExit == "won" ?
translate("VICTORIOUS!") :
translate("DEFEATED!"),
[translate("No"), translate("Yes")],
[resumeGame, leaveGame]
);
g_ConfirmExit = false;
}
function updateGUIObjects()
@ -747,7 +727,7 @@ function updateGUIObjects()
Engine.GetGUIObjectByName("devControlAll").checked = g_DevSettings.controlAll;
}
if (g_ViewedPlayer != -1 && !g_GameEnded)
if (!g_IsObserver)
{
// Update music state on basis of battle state.
let battleState = Engine.GuiInterfaceCall("GetBattleState", g_ViewedPlayer);
@ -805,7 +785,6 @@ function updateGUIStatusBar(nameOfBar, points, maxPoints, direction)
statusBar.size = healthSize;
}
function updateHeroes()
{
let playerState = GetSimState().players[g_ViewedPlayer];
@ -1119,7 +1098,10 @@ function playAmbient()
function getBuildString()
{
return sprintf(translate("Build: %(buildDate)s (%(revision)s)"), { "buildDate": Engine.GetBuildTimestamp(0), revision: Engine.GetBuildTimestamp(2) });
return sprintf(translate("Build: %(buildDate)s (%(revision)s)"), {
"buildDate": Engine.GetBuildTimestamp(0),
"revision": Engine.GetBuildTimestamp(2)
});
}
function showTimeWarpMessageBox()
@ -1137,7 +1119,8 @@ function showTimeWarpMessageBox()
function reportGame()
{
// Only 1v1 games are rated (and Gaia is part of g_Players)
if (!Engine.HasXmppClient() || !Engine.IsRankedGame() || g_Players.length != 3)
if (!Engine.HasXmppClient() || !Engine.IsRankedGame() ||
g_Players.length != 3 || Engine.GetPlayerID() == -1)
return;
let extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState");

View file

@ -25,8 +25,12 @@ Trigger.prototype.ConquestHandlerOwnerShipChanged = function(msg)
if (index >= 0)
{
entities.splice(index, 1);
if (!entities.length && Engine.QueryInterface(this.conquestEntitiesByPlayer[msg.from].player, IID_Player).GetState() == "active")
Engine.PostMessage(this.conquestEntitiesByPlayer[msg.from].player, MT_PlayerDefeated, { "playerId": msg.from } );
if (!entities.length)
{
let cmpPlayer = QueryPlayerIDInterface(msg.from);
if (cmpPlayer)
cmpPlayer.SetState("defeated");
}
}
}
@ -67,7 +71,7 @@ Trigger.prototype.ConquestTrainingFinished = function(msg)
return;
}
this.conquestEntitiesByPlayer[player].entities.push(...msg.entities);
}
};
Trigger.prototype.ConquestStartGameCount = function()
{
@ -90,7 +94,7 @@ Trigger.prototype.ConquestStartGameCount = function()
});
this.conquestDataInit = true;
}
};
var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);

View file

@ -114,7 +114,8 @@ TriggerHelper.GetResourceType = function(entity)
};
/**
* Wins the game for a player
* The given player will win the game.
* If it's not a last man standing game, then allies will win too.
*/
TriggerHelper.SetPlayerWon = function(playerID)
{
@ -127,10 +128,9 @@ TriggerHelper.SetPlayerWon = function(playerID)
*/
TriggerHelper.DefeatPlayer = function(playerID)
{
let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
let playerEnt = cmpPlayerManager.GetPlayerByID(playerID);
Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": playerID } );
let cmpPlayer = QueryPlayerIDInterface(playerID);
if (cmpPlayer)
cmpPlayer.SetState("defeated");
};
/**

View file

@ -1,6 +1,6 @@
/**
* System component which regularly checks victory/defeat conditions
* and if they are satisfied then it marks the player as victorious/defeated.
* System component to store the gametype, gametype settings and
* check for allied victory / last-man-standing.
*/
function EndGameManager() {}
@ -19,6 +19,10 @@ EndGameManager.prototype.Init = function()
// 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;
};
@ -41,6 +45,7 @@ EndGameManager.prototype.SetGameType = function(newGameType, newSettings = {})
{
this.gameType = newGameType;
this.gameTypeSettings = newSettings;
this.skipAlliedVictoryCheck = false;
Engine.BroadcastMessage(MT_GameTypeChanged, {});
};
@ -50,26 +55,20 @@ EndGameManager.prototype.MarkPlayerAsWon = function(playerID)
let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
let numPlayers = cmpPlayerManager.GetNumPlayers();
for (let i = 1; i < numPlayers; ++i)
{
let playerEntityId = cmpPlayerManager.GetPlayerByID(i);
let cmpPlayer = Engine.QueryInterface(playerEntityId, IID_Player);
this.skipAlliedVictoryCheck = true;
if (cmpPlayer.GetState() != "active")
continue;
// Group win/defeat messages
for (let won of [false, true])
for (let i = 1; i < numPlayers; ++i)
{
let cmpPlayer = QueryPlayerIDInterface(i);
let hasWon = playerID == i || this.alliedVictory && cmpPlayer.IsMutualAlly(playerID);
if (playerID == cmpPlayer.GetPlayerID() || this.alliedVictory && cmpPlayer.IsMutualAlly(playerID))
cmpPlayer.SetState("won");
else
Engine.PostMessage(playerEntityId, MT_PlayerDefeated, {
"playerId": i,
"skipAlliedVictoryCheck": true
});
}
if (hasWon == won)
cmpPlayer.SetState(won ? "won" : "defeated");
}
// Reveal the map to all players
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
cmpRangeManager.SetLosRevealAll(-1, true);
this.skipAlliedVictoryCheck = false;
};
EndGameManager.prototype.SetAlliedVictory = function(flag)
@ -79,6 +78,9 @@ EndGameManager.prototype.SetAlliedVictory = function(flag)
EndGameManager.prototype.AlliedVictoryCheck = function()
{
if (this.skipAlliedVictoryCheck)
return;
let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
if (!cmpGuiInterface || !cmpPlayerManager)
@ -101,18 +103,12 @@ EndGameManager.prototype.AlliedVictoryCheck = function()
}
if (this.alliedVictory || allies.length == 1)
{
for (let playerID of allies)
{
let cmpPlayer = QueryPlayerIDInterface(playerID);
if (cmpPlayer)
cmpPlayer.SetState("won");
}
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (cmpRangeManager)
cmpRangeManager.SetLosRevealAll(-1, true);
}
else
this.lastManStandingMessage = cmpGuiInterface.AddTimeNotification({
"message": markForTranslation("Last remaining player wins."),
@ -127,14 +123,12 @@ EndGameManager.prototype.OnInitGame = function(msg)
EndGameManager.prototype.OnGlobalDiplomacyChanged = function(msg)
{
if (!msg.skipAlliedVictoryCheck)
this.AlliedVictoryCheck();
this.AlliedVictoryCheck();
};
EndGameManager.prototype.OnGlobalPlayerDefeated = function(msg)
{
if (!msg.skipAlliedVictoryCheck)
this.AlliedVictoryCheck();
this.AlliedVictoryCheck();
};
Engine.RegisterSystemComponentType(IID_EndGameManager, "EndGameManager", EndGameManager);

View file

@ -359,9 +359,62 @@ Player.prototype.GetState = function()
return this.state;
};
Player.prototype.SetState = function(newState)
Player.prototype.SetState = function(newState, resign)
{
if (this.state != "active")
return;
if (newState != "won" && newState != "defeated")
{
warn("Can't change playerstate to " + this.state);
return;
}
this.state = newState;
let won = newState == "won";
// Reveal map to all or only that player
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
cmpRangeManager.SetLosRevealAll(won ? -1 : this.playerID, true);
if (!won)
{
// Reassign all player's entities to Gaia
let entities = cmpRangeManager.GetEntitiesByPlayer(this.playerID);
// The ownership change is done in two steps so that entities don't hit idle
// (and thus possibly look for "enemies" to attack) before nearby allies get
// converted to Gaia as well.
for (let entity of entities)
{
let cmpOwnership = Engine.QueryInterface(entity, IID_Ownership);
cmpOwnership.SetOwnerQuiet(0);
}
// With the real ownership change complete, send OwnershipChanged messages.
for (let entity of entities)
Engine.PostMessage(entity, MT_OwnershipChanged, {
"entity": entity,
"from": this.playerID,
"to": 0
});
}
Engine.BroadcastMessage(won ? MT_PlayerWon : MT_PlayerDefeated, { "playerId": this.playerID });
let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
if (won)
cmpGUIInterface.PushNotification({
"type": "won",
"players": [this.playerID]
});
else
cmpGUIInterface.PushNotification({
"type": "defeat",
"players": [this.playerID],
"resign": resign
});
};
Player.prototype.GetTeam = function()
@ -369,7 +422,7 @@ Player.prototype.GetTeam = function()
return this.team;
};
Player.prototype.SetTeam = function(team, skipAlliedVictoryCheck = false)
Player.prototype.SetTeam = function(team)
{
if (this.teamsLocked)
return;
@ -385,14 +438,13 @@ Player.prototype.SetTeam = function(team, skipAlliedVictoryCheck = false)
if (this.team != cmpPlayer.GetTeam())
continue;
this.SetAlly(i, skipAlliedVictoryCheck);
cmpPlayer.SetAlly(this.playerID, skipAlliedVictoryCheck);
this.SetAlly(i);
cmpPlayer.SetAlly(this.playerID);
}
Engine.BroadcastMessage(MT_DiplomacyChanged, {
"player": this.playerID,
"otherPlayer": null,
"skipAlliedVictoryCheck": skipAlliedVictoryCheck
"otherPlayer": null
});
};
@ -411,18 +463,17 @@ Player.prototype.GetDiplomacy = function()
return this.diplomacy;
};
Player.prototype.SetDiplomacy = function(dipl, skipAlliedVictoryCheck = false)
Player.prototype.SetDiplomacy = function(dipl)
{
this.diplomacy = dipl;
Engine.BroadcastMessage(MT_DiplomacyChanged, {
"player": this.playerID,
"otherPlayer": null,
"skipAlliedVictoryCheck": skipAlliedVictoryCheck
"otherPlayer": null
});
};
Player.prototype.SetDiplomacyIndex = function(idx, value, skipAlliedVictoryCheck = false)
Player.prototype.SetDiplomacyIndex = function(idx, value)
{
let cmpPlayer = QueryPlayerIDInterface(idx);
if (!cmpPlayer)
@ -435,13 +486,12 @@ Player.prototype.SetDiplomacyIndex = function(idx, value, skipAlliedVictoryCheck
Engine.BroadcastMessage(MT_DiplomacyChanged, {
"player": this.playerID,
"otherPlayer": cmpPlayer.GetPlayerID(),
"skipAlliedVictoryCheck": skipAlliedVictoryCheck
"otherPlayer": cmpPlayer.GetPlayerID()
});
// Mutual worsening of relations
if (cmpPlayer.diplomacy[this.playerID] > value)
cmpPlayer.SetDiplomacyIndex(this.playerID, value, skipAlliedVictoryCheck);
cmpPlayer.SetDiplomacyIndex(this.playerID, value);
};
Player.prototype.UpdateSharedLos = function()
@ -520,9 +570,9 @@ Player.prototype.IsAI = function()
return this.isAI;
};
Player.prototype.SetAlly = function(id, skipAlliedVictoryCheck = false)
Player.prototype.SetAlly = function(id)
{
this.SetDiplomacyIndex(id, 1, skipAlliedVictoryCheck);
this.SetDiplomacyIndex(id, 1);
};
/**
@ -558,9 +608,9 @@ Player.prototype.IsExclusiveMutualAlly = function(id)
return this.playerID != id && this.IsMutualAlly(id);
};
Player.prototype.SetEnemy = function(id, skipAlliedVictoryCheck = false)
Player.prototype.SetEnemy = function(id)
{
this.SetDiplomacyIndex(id, -1, skipAlliedVictoryCheck);
this.SetDiplomacyIndex(id, -1);
};
/**
@ -583,9 +633,9 @@ Player.prototype.IsEnemy = function(id)
return this.diplomacy[id] < 0;
};
Player.prototype.SetNeutral = function(id, skipAlliedVictoryCheck = false)
Player.prototype.SetNeutral = function(id)
{
this.SetDiplomacyIndex(id, 0, skipAlliedVictoryCheck);
this.SetDiplomacyIndex(id, 0);
};
/**
@ -649,43 +699,6 @@ Player.prototype.OnGlobalOwnershipChanged = function(msg)
}
};
Player.prototype.OnPlayerDefeated = function(msg)
{
this.state = "defeated";
// Reassign all player's entities to Gaia
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var entities = cmpRangeManager.GetEntitiesByPlayer(this.playerID);
// The ownership change is done in two steps so that entities don't hit idle
// (and thus possibly look for "enemies" to attack) before nearby allies get
// converted to Gaia as well.
for (var entity of entities)
{
var cmpOwnership = Engine.QueryInterface(entity, IID_Ownership);
cmpOwnership.SetOwnerQuiet(0);
}
// With the real ownership change complete, send OwnershipChanged messages.
for (var entity of entities)
Engine.PostMessage(entity, MT_OwnershipChanged, {
"entity": entity,
"from": this.playerID,
"to": 0
});
// Reveal the map for this player.
cmpRangeManager.SetLosRevealAll(this.playerID, true);
// Send a chat message notifying of the player's defeat.
var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
cmpGUIInterface.PushNotification({
"type": "defeat",
"players": [this.playerID],
"resign": !!msg.resign
});
};
Player.prototype.OnResearchFinished = function(msg)
{
if (msg.tech == this.template.SharedLosTech)

View file

@ -23,7 +23,7 @@ PlayerManager.prototype.AddPlayer = function(ent)
newDiplo[i] = -1;
}
newDiplo[id] = 1;
cmpPlayer.SetDiplomacy(newDiplo, true);
cmpPlayer.SetDiplomacy(newDiplo);
return id;
};

View file

@ -1,3 +1,4 @@
Engine.RegisterInterface("EndGameManager");
Engine.RegisterMessageType("PlayerDefeated");
Engine.RegisterMessageType("PlayerWon");
Engine.RegisterMessageType("GameTypeChanged");

View file

@ -48,10 +48,9 @@ function Cheat(input)
}
return;
case "defeatplayer":
var playerEnt = cmpPlayerManager.GetPlayerByID(input.parameter);
if (playerEnt == INVALID_ENTITY)
return;
Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": input.parameter });
cmpPlayer = QueryPlayerIDInterface(input.parameter);
if (cmpPlayer)
cmpPlayer.SetState("defeated");
return;
case "createunits":
var cmpProductionQueue = input.selected.length && Engine.QueryInterface(input.selected[0], IID_ProductionQueue);

View file

@ -414,8 +414,9 @@ var g_Commands = {
"defeat-player": function(player, cmd, data)
{
// Send "OnPlayerDefeated" message to player
Engine.PostMessage(data.playerEnt, MT_PlayerDefeated, { "playerId": player, "resign": !!cmd.resign });
let cmpPlayer = QueryPlayerIDInterface(player);
if (cmpPlayer)
cmpPlayer.SetState("defeated", !!cmd.resign);
},
"garrison": function(player, cmd, data)

View file

@ -123,7 +123,7 @@ function LoadPlayerSettings(settings, newPlayers)
// If diplomacy explicitly defined, use that; otherwise use teams
if (getSetting(playerData, playerDefaults, i, "Diplomacy") !== undefined)
cmpPlayer.SetDiplomacy(getSetting(playerData, playerDefaults, i, "Diplomacy"), true);
cmpPlayer.SetDiplomacy(getSetting(playerData, playerDefaults, i, "Diplomacy"));
else
{
// Init diplomacy
@ -137,7 +137,7 @@ function LoadPlayerSettings(settings, newPlayers)
else
cmpPlayer.SetEnemy(j);
}
cmpPlayer.SetTeam(myTeam === undefined ? -1 : myTeam, true);
cmpPlayer.SetTeam(myTeam === undefined ? -1 : myTeam);
}
// If formations explicitly defined, use that; otherwise use civ defaults