SessionMessageBox class, refs #5387.
Decouples events from event handling, removes implicit-pause duplication per messagebox and allows mods to modify message box values. Differential Revision: https://code.wildfiregames.com/D2398 Comments By: Stan, Freagarach This was SVN commit r23114.
This commit is contained in:
parent
3617689230
commit
bc6da5e3f2
@ -115,8 +115,7 @@ MenuButtons.prototype.Summary = class
|
|||||||
},
|
},
|
||||||
"selectedData": this.selectedData
|
"selectedData": this.selectedData
|
||||||
},
|
},
|
||||||
data =>
|
data => {
|
||||||
{
|
|
||||||
this.selectedData = data.summarySelectedData;
|
this.selectedData = data.summarySelectedData;
|
||||||
this.pauseControl.implicitResume();
|
this.pauseControl.implicitResume();
|
||||||
});
|
});
|
||||||
@ -225,23 +224,7 @@ MenuButtons.prototype.Resign = class
|
|||||||
|
|
||||||
onPress()
|
onPress()
|
||||||
{
|
{
|
||||||
closeOpenDialogs();
|
(new ResignConfirmation()).display();
|
||||||
this.pauseControl.implicitPause();
|
|
||||||
|
|
||||||
messageBox(
|
|
||||||
400, 200,
|
|
||||||
translate("Are you sure you want to resign?"),
|
|
||||||
translate("Confirmation"),
|
|
||||||
[translate("No"), translate("Yes")],
|
|
||||||
[
|
|
||||||
resumeGame,
|
|
||||||
() => {
|
|
||||||
Engine.PostNetworkCommand({
|
|
||||||
"type": "resign"
|
|
||||||
});
|
|
||||||
resumeGame();
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -257,50 +240,11 @@ MenuButtons.prototype.Exit = class
|
|||||||
|
|
||||||
onPress()
|
onPress()
|
||||||
{
|
{
|
||||||
closeOpenDialogs();
|
for (let name in QuitConfirmationMenu.prototype)
|
||||||
this.pauseControl.implicitPause();
|
{
|
||||||
|
let quitConfirmation = new QuitConfirmationMenu.prototype[name]();
|
||||||
let messageType = g_IsNetworked && g_IsController ? "host" :
|
if (quitConfirmation.enabled())
|
||||||
(g_IsNetworked && !g_IsObserver ? "client" : "singleplayer");
|
quitConfirmation.display();
|
||||||
|
}
|
||||||
messageBox(
|
|
||||||
400, 200,
|
|
||||||
this.Confirmation[messageType].caption(),
|
|
||||||
translate("Confirmation"),
|
|
||||||
[translate("No"), translate("Yes")],
|
|
||||||
this.Confirmation[messageType].buttons());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
MenuButtons.prototype.Exit.prototype.Confirmation = {
|
|
||||||
"host": {
|
|
||||||
"caption": () => translate("Are you sure you want to quit? Leaving will disconnect all other players."),
|
|
||||||
"buttons": () => [resumeGame, endGame]
|
|
||||||
},
|
|
||||||
"client": {
|
|
||||||
"caption": () => translate("Are you sure you want to quit?"),
|
|
||||||
"buttons": () => [
|
|
||||||
resumeGame,
|
|
||||||
() => {
|
|
||||||
messageBox(
|
|
||||||
400, 200,
|
|
||||||
translate("Do you want to resign or will you return soon?"),
|
|
||||||
translate("Confirmation"),
|
|
||||||
[translate("I will return"), translate("I resign")],
|
|
||||||
[
|
|
||||||
endGame,
|
|
||||||
() => {
|
|
||||||
Engine.PostNetworkCommand({
|
|
||||||
"type": "resign"
|
|
||||||
});
|
|
||||||
resumeGame();
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"singleplayer": {
|
|
||||||
"caption": () => translate("Are you sure you want to quit?"),
|
|
||||||
"buttons": () => [resumeGame, endGame]
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
40
binaries/data/mods/public/gui/session/SessionMessageBox.js
Normal file
40
binaries/data/mods/public/gui/session/SessionMessageBox.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* This is the same as a regular MessageBox, but it pauses if it is
|
||||||
|
* a singleplayer game, until the player answered the dialog.
|
||||||
|
*/
|
||||||
|
class SessionMessageBox
|
||||||
|
{
|
||||||
|
display()
|
||||||
|
{
|
||||||
|
this.onPageOpening();
|
||||||
|
|
||||||
|
Engine.PushGuiPage(
|
||||||
|
"page_msgbox.xml",
|
||||||
|
{
|
||||||
|
"width": this.Width,
|
||||||
|
"height": this.Height,
|
||||||
|
"title": this.Title,
|
||||||
|
"message": this.Caption,
|
||||||
|
"buttonCaptions": this.Buttons ? this.Buttons.map(button => button.caption) : undefined,
|
||||||
|
},
|
||||||
|
this.onPageClosed.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
onPageOpening()
|
||||||
|
{
|
||||||
|
closeOpenDialogs();
|
||||||
|
g_PauseControl.implicitPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
onPageClosed(buttonId)
|
||||||
|
{
|
||||||
|
if (this.Buttons && this.Buttons[buttonId].onPress)
|
||||||
|
this.Buttons[buttonId].onPress.call(this);
|
||||||
|
|
||||||
|
if (Engine.IsGameStarted())
|
||||||
|
resumeGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionMessageBox.prototype.Width = 400;
|
||||||
|
SessionMessageBox.prototype.Height = 200;
|
@ -23,10 +23,7 @@ class TimeWarp
|
|||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
messageBox(
|
(new TimeWarpMessageBox()).display();
|
||||||
500, 250,
|
|
||||||
translate(this.Description),
|
|
||||||
translate(this.Title));
|
|
||||||
|
|
||||||
Engine.EnableTimeWarpRecording(enabled ? this.NumberTurns : 0);
|
Engine.EnableTimeWarpRecording(enabled ? this.NumberTurns : 0);
|
||||||
}
|
}
|
||||||
@ -60,7 +57,11 @@ TimeWarp.prototype.NumberTurns = 10;
|
|||||||
*/
|
*/
|
||||||
TimeWarp.prototype.FastForwardSpeed = 20;
|
TimeWarp.prototype.FastForwardSpeed = 20;
|
||||||
|
|
||||||
TimeWarp.prototype.Title = markForTranslation("Time warp mode");
|
class TimeWarpMessageBox extends SessionMessageBox
|
||||||
|
{
|
||||||
TimeWarp.prototype.Description = markForTranslation(
|
}
|
||||||
|
TimeWarpMessageBox.prototype.Width = 500;
|
||||||
|
TimeWarpMessageBox.prototype.Height = 250;
|
||||||
|
TimeWarpMessageBox.prototype.Title = translate("Time warp mode");
|
||||||
|
TimeWarpMessageBox.prototype.Caption = translate(
|
||||||
"Note: time warp mode is a developer option, and not intended for use over long periods of time. Using it incorrectly may cause the game to run out of memory or crash.");
|
"Note: time warp mode is a developer option, and not intended for use over long periods of time. Using it incorrectly may cause the game to run out of memory or crash.");
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
class DeleteSelectionConfirmation extends SessionMessageBox
|
||||||
|
{
|
||||||
|
constructor(deleteSelection)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.deleteSelection = deleteSelection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteSelectionConfirmation.prototype.Title = translate("Delete");
|
||||||
|
DeleteSelectionConfirmation.prototype.Caption = translate("Destroy everything currently selected?");
|
||||||
|
DeleteSelectionConfirmation.prototype.Buttons = [
|
||||||
|
{
|
||||||
|
"caption": translate("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": translate("Yes"),
|
||||||
|
"onPress": function() { this.deleteSelection(); }
|
||||||
|
}
|
||||||
|
];
|
@ -0,0 +1,51 @@
|
|||||||
|
class OutOfSyncNetwork extends SessionMessageBox
|
||||||
|
{
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
registerNetworkOutOfSyncHandler(this.onNetworkOutOfSync.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message object is constructed in CNetClientTurnManager::OnSyncError.
|
||||||
|
*/
|
||||||
|
onNetworkOutOfSync(msg)
|
||||||
|
{
|
||||||
|
let txt = [
|
||||||
|
sprintf(translate("Out-Of-Sync error on turn %(turn)s."), {
|
||||||
|
"turn": msg.turn
|
||||||
|
}),
|
||||||
|
|
||||||
|
sprintf(translateWithContext("Out-Of-Sync", "Players: %(players)s"), {
|
||||||
|
"players": msg.players.join(translateWithContext("Separator for a list of players", ", "))
|
||||||
|
}),
|
||||||
|
|
||||||
|
msg.hash == msg.expectedHash ?
|
||||||
|
translateWithContext("Out-Of-Sync", "Your game state is identical to the hosts game state.") :
|
||||||
|
translateWithContext("Out-Of-Sync", "Your game state differs from the hosts game state."),
|
||||||
|
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
if (msg.turn > 1 && g_GameAttributes.settings.PlayerData.some(pData => pData && pData.AI))
|
||||||
|
txt.push(translateWithContext("Out-Of-Sync", "Rejoining Multiplayer games with AIs is not supported yet!"));
|
||||||
|
else
|
||||||
|
txt.push(
|
||||||
|
translateWithContext("Out-Of-Sync", "Ensure all players use the same mods."),
|
||||||
|
translateWithContext("Out-Of-Sync", 'Click on "Report a Bug" in the main menu to help fix this.'),
|
||||||
|
sprintf(translateWithContext("Out-Of-Sync", "Replay saved to %(filepath)s"), {
|
||||||
|
"filepath": escapeText(msg.path_replay)
|
||||||
|
}),
|
||||||
|
sprintf(translateWithContext("Out-Of-Sync", "Dumping current state to %(filepath)s"), {
|
||||||
|
"filepath": escapeText(msg.path_oos_dump)
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.Caption = txt.join("\n");
|
||||||
|
this.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutOfSyncNetwork.prototype.Width = 600;
|
||||||
|
OutOfSyncNetwork.prototype.Height = 280;
|
||||||
|
|
||||||
|
OutOfSyncNetwork.prototype.Title = translate("Out of Sync");
|
@ -0,0 +1,29 @@
|
|||||||
|
class OutOfSyncReplay extends SessionMessageBox
|
||||||
|
{
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
Engine.GetGUIObjectByName("session").onReplayOutOfSync = this.onReplayOutOfSync.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onReplayOutOfSync(turn, hash, expectedHash)
|
||||||
|
{
|
||||||
|
this.Caption = sprintf(this.Captions.join("\n"), {
|
||||||
|
"turn": turn,
|
||||||
|
"hash": hash,
|
||||||
|
"expectedHash": expectedHash
|
||||||
|
});
|
||||||
|
this.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutOfSyncReplay.prototype.Width = 500;
|
||||||
|
OutOfSyncReplay.prototype.Height = 140;
|
||||||
|
|
||||||
|
OutOfSyncReplay.prototype.Title = translate("Out of Sync");
|
||||||
|
|
||||||
|
OutOfSyncReplay.prototype.Captions = [
|
||||||
|
translate("Out-Of-Sync error on turn %(turn)s."),
|
||||||
|
// Translation: This is shown if replay is out of sync
|
||||||
|
translate("Out-Of-Sync", "The current game state is different from the original game state.")
|
||||||
|
];
|
@ -0,0 +1,20 @@
|
|||||||
|
class QuitConfirmation extends SessionMessageBox
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QuitConfirmation.prototype.Title =
|
||||||
|
translate("Confirmation");
|
||||||
|
|
||||||
|
QuitConfirmation.prototype.Caption =
|
||||||
|
translate("Are you sure you want to quit?");
|
||||||
|
|
||||||
|
QuitConfirmation.prototype.Buttons =
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"caption": translate("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": translate("Yes"),
|
||||||
|
"onPress": endGame
|
||||||
|
}
|
||||||
|
];
|
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* This class will spawn a dialog asking to exit the game in case the user was an assigned player who has been defeated.
|
||||||
|
*/
|
||||||
|
class QuitConfirmationDefeat extends QuitConfirmation
|
||||||
|
{
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
if (Engine.IsAtlasRunning())
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.confirmHandler = undefined;
|
||||||
|
registerPlayersFinishedHandler(this.onPlayersFinished.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlayersFinished(players, won)
|
||||||
|
{
|
||||||
|
if (players.indexOf(Engine.GetPlayerID()) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Defer simulation result until
|
||||||
|
// 1. the loading screen finished for all networked clients (g_IsNetworkedActive)
|
||||||
|
// 2. all messages modifying g_Players victory state were processed (next turn)
|
||||||
|
this.confirmHandler = this.confirmExit.bind(this, won);
|
||||||
|
registerSimulationUpdateHandler(this.confirmHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmExit(won)
|
||||||
|
{
|
||||||
|
if (g_IsNetworked && !g_IsNetworkedActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unregisterSimulationUpdateHandler(this.confirmHandler);
|
||||||
|
|
||||||
|
// Don't ask for exit if other humans are still playing.
|
||||||
|
let askExit = !Engine.HasNetServer() || g_Players.every((player, i) =>
|
||||||
|
i == 0 ||
|
||||||
|
player.state != "active" ||
|
||||||
|
g_GameAttributes.settings.PlayerData[i].AI != "");
|
||||||
|
|
||||||
|
this.Title = won ? this.TitleVictory : this.TitleDefeated;
|
||||||
|
|
||||||
|
this.Caption =
|
||||||
|
g_PlayerStateMessages[won ? "won" : "defeated"] +
|
||||||
|
(askExit ? "\n" + this.Question : "");
|
||||||
|
|
||||||
|
this.Buttons = askExit ? super.Buttons : undefined;
|
||||||
|
|
||||||
|
this.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QuitConfirmationDefeat.prototype.TitleVictory = translate("VICTORIOUS!");
|
||||||
|
QuitConfirmationDefeat.prototype.TitleDefeated = translate("DEFEATED!");
|
||||||
|
|
||||||
|
QuitConfirmationDefeat.prototype.Question = translate("Do you want to quit?");
|
@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* The class that is enabled() will be triggered when the user clicks on the Exit menu button.
|
||||||
|
*/
|
||||||
|
class QuitConfirmationMenu
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In singleplayer mode, replaymode and for observers in multiplayermatches that
|
||||||
|
* aren't the host, exit the match instantly.
|
||||||
|
*/
|
||||||
|
QuitConfirmationMenu.prototype.Singleplayer = class extends QuitConfirmation
|
||||||
|
{
|
||||||
|
enabled()
|
||||||
|
{
|
||||||
|
return !g_IsNetworked || (!g_IsController && g_IsObserver);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the current player is the host of a networked match, have the player
|
||||||
|
* confirm intent to end the game for the remote players as well.
|
||||||
|
*/
|
||||||
|
QuitConfirmationMenu.prototype.MultiplayerHost = class extends QuitConfirmation
|
||||||
|
{
|
||||||
|
enabled()
|
||||||
|
{
|
||||||
|
return g_IsNetworked && g_IsController;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QuitConfirmationMenu.prototype.MultiplayerHost.prototype.Caption =
|
||||||
|
translate("Are you sure you want to quit? Leaving will disconnect all other players.");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active players that aren't the host will be asked if they want to resign before leaving.
|
||||||
|
*/
|
||||||
|
QuitConfirmationMenu.prototype.MultiplayerClient = class extends QuitConfirmation
|
||||||
|
{
|
||||||
|
enabled()
|
||||||
|
{
|
||||||
|
return g_IsNetworked && !g_IsController && !g_IsObserver;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QuitConfirmationMenu.prototype.MultiplayerClient.prototype.Buttons =
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"caption": translate("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": translate("Yes"),
|
||||||
|
"onPress": () => {
|
||||||
|
(new ReturnQuestion()).display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
class ReturnQuestion extends SessionMessageBox
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnQuestion.prototype.Title = translate("Confirmation");
|
||||||
|
ReturnQuestion.prototype.Caption = translate("Do you want to resign or will you return soon?");
|
||||||
|
ReturnQuestion.prototype.Buttons = [
|
||||||
|
{
|
||||||
|
"caption": translate("I will return"),
|
||||||
|
"onPress": endGame
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": translate("I resign"),
|
||||||
|
"onPress": () => {
|
||||||
|
Engine.PostNetworkCommand({
|
||||||
|
"type": "resign"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* This class is concerned with opening a message box if the game is in replaymode and that replay ended.
|
||||||
|
*/
|
||||||
|
class QuitConfirmationReplay extends SessionMessageBox
|
||||||
|
{
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
Engine.GetGUIObjectByName("session").onReplayFinished = this.display.bind(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QuitConfirmationReplay.prototype.Title =
|
||||||
|
translateWithContext("replayFinished", "Confirmation");
|
||||||
|
|
||||||
|
QuitConfirmationReplay.prototype.Caption =
|
||||||
|
translateWithContext("replayFinished", "The replay has finished. Do you want to quit?");
|
||||||
|
|
||||||
|
QuitConfirmationReplay.prototype.Buttons =
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"caption": translateWithContext("replayFinished", "No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": translateWithContext("replayFinished", "Yes"),
|
||||||
|
"onPress": endGame
|
||||||
|
}
|
||||||
|
];
|
@ -0,0 +1,19 @@
|
|||||||
|
class ResignConfirmation extends SessionMessageBox
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ResignConfirmation.prototype.Title = translate("Confirmation");
|
||||||
|
ResignConfirmation.prototype.Caption = translate("Are you sure you want to resign?");
|
||||||
|
ResignConfirmation.prototype.Buttons = [
|
||||||
|
{
|
||||||
|
"caption": translate("No")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": translate("Yes"),
|
||||||
|
"onPress": () => {
|
||||||
|
Engine.PostNetworkCommand({
|
||||||
|
"type": "resign"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
@ -23,6 +23,11 @@ var g_PlayerAssignmentsChangeHandlers = new Set();
|
|||||||
*/
|
*/
|
||||||
var g_CeasefireEndedHandlers = new Set();
|
var g_CeasefireEndedHandlers = new Set();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These handlers are fired if the server informed the players that the networked game is out of sync.
|
||||||
|
*/
|
||||||
|
var g_NetworkOutOfSyncHandlers = new Set();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle all netmessage types that can occur.
|
* Handle all netmessage types that can occur.
|
||||||
*/
|
*/
|
||||||
@ -34,7 +39,8 @@ var g_NetMessageTypes = {
|
|||||||
addNetworkWarning(msg);
|
addNetworkWarning(msg);
|
||||||
},
|
},
|
||||||
"out-of-sync": msg => {
|
"out-of-sync": msg => {
|
||||||
onNetworkOutOfSync(msg);
|
for (let handler of g_NetworkOutOfSyncHandlers)
|
||||||
|
handler(msg);
|
||||||
},
|
},
|
||||||
"players": msg => {
|
"players": msg => {
|
||||||
handlePlayerAssignmentsMessage(msg);
|
handlePlayerAssignmentsMessage(msg);
|
||||||
@ -302,6 +308,11 @@ function registerCeasefireEndedHandler(handler)
|
|||||||
g_CeasefireEndedHandlers.add(handler);
|
g_CeasefireEndedHandlers.add(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function registerNetworkOutOfSyncHandler(handler)
|
||||||
|
{
|
||||||
|
g_NetworkOutOfSyncHandlers.add(handler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all known cheat commands.
|
* Loads all known cheat commands.
|
||||||
*/
|
*/
|
||||||
@ -516,58 +527,6 @@ function handleClientsLoadingMessage(guids)
|
|||||||
loadingClientsText.caption = guids.map(guid => colorizePlayernameByGUID(guid)).join(translateWithContext("Separator for a list of client loading messages", ", "));
|
loadingClientsText.caption = guids.map(guid => colorizePlayernameByGUID(guid)).join(translateWithContext("Separator for a list of client loading messages", ", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onNetworkOutOfSync(msg)
|
|
||||||
{
|
|
||||||
let txt = [
|
|
||||||
sprintf(translate("Out-Of-Sync error on turn %(turn)s."), {
|
|
||||||
"turn": msg.turn
|
|
||||||
}),
|
|
||||||
|
|
||||||
sprintf(translateWithContext("Out-Of-Sync", "Players: %(players)s"), {
|
|
||||||
"players": msg.players.join(translateWithContext("Separator for a list of players", ", "))
|
|
||||||
}),
|
|
||||||
|
|
||||||
msg.hash == msg.expectedHash ?
|
|
||||||
translateWithContext("Out-Of-Sync", "Your game state is identical to the hosts game state.") :
|
|
||||||
translateWithContext("Out-Of-Sync", "Your game state differs from the hosts game state."),
|
|
||||||
|
|
||||||
""
|
|
||||||
];
|
|
||||||
|
|
||||||
if (msg.turn > 1 && g_GameAttributes.settings.PlayerData.some(pData => pData && pData.AI))
|
|
||||||
txt.push(translateWithContext("Out-Of-Sync", "Rejoining Multiplayer games with AIs is not supported yet!"));
|
|
||||||
else
|
|
||||||
txt.push(
|
|
||||||
translateWithContext("Out-Of-Sync", "Ensure all players use the same mods."),
|
|
||||||
translateWithContext("Out-Of-Sync", 'Click on "Report a Bug" in the main menu to help fix this.'),
|
|
||||||
sprintf(translateWithContext("Out-Of-Sync", "Replay saved to %(filepath)s"), {
|
|
||||||
"filepath": escapeText(msg.path_replay)
|
|
||||||
}),
|
|
||||||
sprintf(translateWithContext("Out-Of-Sync", "Dumping current state to %(filepath)s"), {
|
|
||||||
"filepath": escapeText(msg.path_oos_dump)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
messageBox(
|
|
||||||
600, 280,
|
|
||||||
txt.join("\n"),
|
|
||||||
translate("Out of Sync")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onReplayOutOfSync(turn, hash, expectedHash)
|
|
||||||
{
|
|
||||||
messageBox(
|
|
||||||
500, 140,
|
|
||||||
sprintf(translate("Out-Of-Sync error on turn %(turn)s."), {
|
|
||||||
"turn": turn
|
|
||||||
}) + "\n" +
|
|
||||||
// Translation: This is shown if replay is out of sync
|
|
||||||
translateWithContext("Out-Of-Sync", "The current game state is different from the original game state."),
|
|
||||||
translate("Out of Sync")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePlayerAssignmentsMessage(message)
|
function handlePlayerAssignmentsMessage(message)
|
||||||
{
|
{
|
||||||
for (let guid in g_PlayerAssignments)
|
for (let guid in g_PlayerAssignments)
|
||||||
|
@ -18,10 +18,14 @@ var g_GameSpeedControl;
|
|||||||
var g_Menu;
|
var g_Menu;
|
||||||
var g_MiniMapPanel;
|
var g_MiniMapPanel;
|
||||||
var g_ObjectivesDialog;
|
var g_ObjectivesDialog;
|
||||||
|
var g_OutOfSyncNetwork;
|
||||||
|
var g_OutOfSyncReplay;
|
||||||
var g_PanelEntityManager;
|
var g_PanelEntityManager;
|
||||||
var g_PauseControl;
|
var g_PauseControl;
|
||||||
var g_PauseOverlay;
|
var g_PauseOverlay;
|
||||||
var g_PlayerViewControl;
|
var g_PlayerViewControl;
|
||||||
|
var g_QuitConfirmationDefeat;
|
||||||
|
var g_QuitConfirmationReplay;
|
||||||
var g_RangeOverlayManager;
|
var g_RangeOverlayManager;
|
||||||
var g_ResearchProgress;
|
var g_ResearchProgress;
|
||||||
var g_TradeDialog;
|
var g_TradeDialog;
|
||||||
@ -68,11 +72,6 @@ var g_IsObserver = false;
|
|||||||
*/
|
*/
|
||||||
var g_HasRejoined = false;
|
var g_HasRejoined = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a message box asking the user to leave if "won" or "defeated".
|
|
||||||
*/
|
|
||||||
var g_ConfirmExit = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The playerID selected in the change perspective tool.
|
* The playerID selected in the change perspective tool.
|
||||||
*/
|
*/
|
||||||
@ -263,11 +262,11 @@ function init(initData, hotloadData)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_DiplomacyColors = new DiplomacyColors();
|
g_DiplomacyColors = new DiplomacyColors();
|
||||||
|
|
||||||
g_PlayerViewControl = new PlayerViewControl();
|
g_PlayerViewControl = new PlayerViewControl();
|
||||||
g_PlayerViewControl.registerViewedPlayerChangeHandler(g_DiplomacyColors.updateDisplayedPlayerColors.bind(g_DiplomacyColors));
|
g_PlayerViewControl.registerViewedPlayerChangeHandler(g_DiplomacyColors.updateDisplayedPlayerColors.bind(g_DiplomacyColors));
|
||||||
g_DiplomacyColors.registerDiplomacyColorsChangeHandler(g_PlayerViewControl.rebuild.bind(g_PlayerViewControl));
|
g_DiplomacyColors.registerDiplomacyColorsChangeHandler(g_PlayerViewControl.rebuild.bind(g_PlayerViewControl));
|
||||||
g_DiplomacyColors.registerDiplomacyColorsChangeHandler(updateGUIObjects);
|
g_DiplomacyColors.registerDiplomacyColorsChangeHandler(updateGUIObjects);
|
||||||
|
g_PauseControl = new PauseControl();
|
||||||
g_PlayerViewControl.registerPreViewedPlayerChangeHandler(removeStatusBarDisplay);
|
g_PlayerViewControl.registerPreViewedPlayerChangeHandler(removeStatusBarDisplay);
|
||||||
g_PlayerViewControl.registerViewedPlayerChangeHandler(resetTemplates);
|
g_PlayerViewControl.registerViewedPlayerChangeHandler(resetTemplates);
|
||||||
|
|
||||||
@ -275,12 +274,15 @@ function init(initData, hotloadData)
|
|||||||
g_DeveloperOverlay = new DeveloperOverlay(g_PlayerViewControl, g_Selection);
|
g_DeveloperOverlay = new DeveloperOverlay(g_PlayerViewControl, g_Selection);
|
||||||
g_DiplomacyDialog = new DiplomacyDialog(g_PlayerViewControl, g_DiplomacyColors);
|
g_DiplomacyDialog = new DiplomacyDialog(g_PlayerViewControl, g_DiplomacyColors);
|
||||||
g_GameSpeedControl = new GameSpeedControl(g_PlayerViewControl);
|
g_GameSpeedControl = new GameSpeedControl(g_PlayerViewControl);
|
||||||
|
g_Menu = new Menu(g_PauseControl, g_PlayerViewControl, g_Chat);
|
||||||
g_MiniMapPanel = new MiniMapPanel(g_PlayerViewControl, g_DiplomacyColors, g_WorkerTypes);
|
g_MiniMapPanel = new MiniMapPanel(g_PlayerViewControl, g_DiplomacyColors, g_WorkerTypes);
|
||||||
g_ObjectivesDialog = new ObjectivesDialog(g_PlayerViewControl);
|
g_ObjectivesDialog = new ObjectivesDialog(g_PlayerViewControl);
|
||||||
|
g_OutOfSyncNetwork = new OutOfSyncNetwork();
|
||||||
|
g_OutOfSyncReplay = new OutOfSyncReplay();
|
||||||
g_PanelEntityManager = new PanelEntityManager(g_PlayerViewControl, g_Selection, g_PanelEntityOrder);
|
g_PanelEntityManager = new PanelEntityManager(g_PlayerViewControl, g_Selection, g_PanelEntityOrder);
|
||||||
g_PauseControl = new PauseControl();
|
|
||||||
g_PauseOverlay = new PauseOverlay(g_PauseControl);
|
g_PauseOverlay = new PauseOverlay(g_PauseControl);
|
||||||
g_Menu = new Menu(g_PauseControl, g_PlayerViewControl, g_Chat);
|
g_QuitConfirmationDefeat = new QuitConfirmationDefeat();
|
||||||
|
g_QuitConfirmationReplay = new QuitConfirmationReplay();
|
||||||
g_RangeOverlayManager = new RangeOverlayManager(g_Selection);
|
g_RangeOverlayManager = new RangeOverlayManager(g_Selection);
|
||||||
g_ResearchProgress = new ResearchProgress(g_PlayerViewControl, g_Selection);
|
g_ResearchProgress = new ResearchProgress(g_PlayerViewControl, g_Selection);
|
||||||
g_TradeDialog = new TradeDialog(g_PlayerViewControl);
|
g_TradeDialog = new TradeDialog(g_PlayerViewControl);
|
||||||
@ -479,8 +481,6 @@ function playersFinished(players, victoryString, won)
|
|||||||
global.music.states.VICTORY :
|
global.music.states.VICTORY :
|
||||||
global.music.states.DEFEAT
|
global.music.states.DEFEAT
|
||||||
);
|
);
|
||||||
|
|
||||||
g_ConfirmExit = won ? "won" : "defeated";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resumeGame()
|
function resumeGame()
|
||||||
@ -625,42 +625,6 @@ function onSimulationUpdate()
|
|||||||
updateCinemaPath();
|
updateCinemaPath();
|
||||||
handleNotifications();
|
handleNotifications();
|
||||||
updateGUIObjects();
|
updateGUIObjects();
|
||||||
|
|
||||||
if (g_ConfirmExit)
|
|
||||||
confirmExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't show the message box before all playerstate changes are processed.
|
|
||||||
*/
|
|
||||||
function confirmExit()
|
|
||||||
{
|
|
||||||
if (g_IsNetworked && !g_IsNetworkedActive)
|
|
||||||
return;
|
|
||||||
|
|
||||||
closeOpenDialogs();
|
|
||||||
g_PauseControl.implicitPause();
|
|
||||||
|
|
||||||
// Don't ask for exit if other humans are still playing
|
|
||||||
let askExit = !Engine.HasNetServer() || g_Players.every((player, i) =>
|
|
||||||
i == 0 ||
|
|
||||||
player.state != "active" ||
|
|
||||||
g_GameAttributes.settings.PlayerData[i].AI != "");
|
|
||||||
|
|
||||||
let subject = g_PlayerStateMessages[g_ConfirmExit];
|
|
||||||
if (askExit)
|
|
||||||
subject += "\n" + translate("Do you want to quit?");
|
|
||||||
|
|
||||||
messageBox(
|
|
||||||
400, 200,
|
|
||||||
subject,
|
|
||||||
g_ConfirmExit == "won" ?
|
|
||||||
translate("VICTORIOUS!") :
|
|
||||||
translate("DEFEATED!"),
|
|
||||||
askExit ? [translate("No"), translate("Yes")] : [translate("OK")],
|
|
||||||
askExit ? [resumeGame, endGame] : [resumeGame]);
|
|
||||||
|
|
||||||
g_ConfirmExit = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleGUI()
|
function toggleGUI()
|
||||||
@ -702,18 +666,6 @@ function updateGUIObjects()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onReplayFinished()
|
|
||||||
{
|
|
||||||
closeOpenDialogs();
|
|
||||||
g_PauseControl.implicitPause();
|
|
||||||
|
|
||||||
messageBox(400, 200,
|
|
||||||
translateWithContext("replayFinished", "The replay has finished. Do you want to quit?"),
|
|
||||||
translateWithContext("replayFinished", "Confirmation"),
|
|
||||||
[translateWithContext("replayFinished", "No"), translateWithContext("replayFinished", "Yes")],
|
|
||||||
[resumeGame, endGame]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateGroups()
|
function updateGroups()
|
||||||
{
|
{
|
||||||
g_Groups.update();
|
g_Groups.update();
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<script directory="gui/session/diplomacy/playercontrols/"/>
|
<script directory="gui/session/diplomacy/playercontrols/"/>
|
||||||
<script directory="gui/session/lobby/"/>
|
<script directory="gui/session/lobby/"/>
|
||||||
<script directory="gui/session/lobby/LobbyRatingReport/"/>
|
<script directory="gui/session/lobby/LobbyRatingReport/"/>
|
||||||
|
<script directory="gui/session/message_box/"/>
|
||||||
<script directory="gui/session/minimap/"/>
|
<script directory="gui/session/minimap/"/>
|
||||||
<script directory="gui/session/top_panel/"/>
|
<script directory="gui/session/top_panel/"/>
|
||||||
<script directory="gui/session/top_panel/IconButtons/"/>
|
<script directory="gui/session/top_panel/IconButtons/"/>
|
||||||
@ -30,14 +31,6 @@
|
|||||||
onSimulationUpdate();
|
onSimulationUpdate();
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
<action on="ReplayFinished">
|
|
||||||
onReplayFinished();
|
|
||||||
</action>
|
|
||||||
|
|
||||||
<action on="ReplayOutOfSync">
|
|
||||||
onReplayOutOfSync(arguments[0], arguments[1], arguments[2]);
|
|
||||||
</action>
|
|
||||||
|
|
||||||
<!-- Hotkeys won't work properly unless outside menu -->
|
<!-- Hotkeys won't work properly unless outside menu -->
|
||||||
<include directory="gui/session/hotkeys/"/>
|
<include directory="gui/session/hotkeys/"/>
|
||||||
|
|
||||||
|
@ -1082,22 +1082,7 @@ var g_EntityCommands =
|
|||||||
if (Engine.HotkeyIsPressed("session.noconfirmation"))
|
if (Engine.HotkeyIsPressed("session.noconfirmation"))
|
||||||
deleteSelection();
|
deleteSelection();
|
||||||
else
|
else
|
||||||
{
|
(new DeleteSelectionConfirmation(deleteSelection)).display();
|
||||||
closeOpenDialogs();
|
|
||||||
g_PauseControl.implicitPause();
|
|
||||||
messageBox(
|
|
||||||
400, 200,
|
|
||||||
translate("Destroy everything currently selected?"),
|
|
||||||
translate("Delete"),
|
|
||||||
[translate("No"), translate("Yes")],
|
|
||||||
[
|
|
||||||
resumeGame,
|
|
||||||
() => {
|
|
||||||
deleteSelection();
|
|
||||||
resumeGame();
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user