Index: binaries/data/mods/public/gui/common/functions_utility_loadsave.js =================================================================== --- binaries/data/mods/public/gui/common/functions_utility_loadsave.js +++ binaries/data/mods/public/gui/common/functions_utility_loadsave.js @@ -1,83 +0,0 @@ -function sortDecreasingDate(a, b) -{ - return b.metadata.time - a.metadata.time; -} - -function isCompatibleSavegame(metadata, engineInfo) -{ - return engineInfo && hasSameEngineVersion(metadata, engineInfo) & hasSameMods(metadata.mods, engineInfo.mods); -} - -function generateSavegameDateString(metadata, engineInfo) -{ - return compatibilityColor( - Engine.FormatMillisecondsIntoDateStringLocal(metadata.time * 1000, translate("yyyy-MM-dd HH:mm:ss")), - isCompatibleSavegame(metadata, engineInfo)); -} - -function generateSavegameLabel(metadata, engineInfo) -{ - return sprintf( - metadata.description ? - translate("%(dateString)s %(map)s - %(description)s") : - translate("%(dateString)s %(map)s"), - { - "dateString": generateSavegameDateString(metadata, engineInfo), - "map": metadata.initAttributes.map, - "description": metadata.description || "" - } - ); -} - -/** - * Check the version compatibility between the saved game to be loaded and the engine - */ -function hasSameEngineVersion(metadata, engineInfo) -{ - return metadata.engine_version && metadata.engine_version == engineInfo.engine_version; -} - -function deleteGame() -{ - let gameSelection = Engine.GetGUIObjectByName("gameSelection"); - let gameID = gameSelection.list_data[gameSelection.selected]; - - if (!gameID) - return; - - if (Engine.HotkeyIsPressed("session.savedgames.noconfirmation")) - reallyDeleteGame(gameID); - else - messageBox( - 500, 200, - sprintf(translate("\"%(label)s\""), { - "label": gameSelection.list[gameSelection.selected] - }) + "\n" + translate("Saved game will be permanently deleted, are you sure?"), - translate("DELETE"), - [translate("No"), translate("Yes")], - [null, function(){ reallyDeleteGame(gameID); }] - ); -} - -function reallyDeleteGame(gameID) -{ - if (!Engine.DeleteSavedGame(gameID)) - error("Could not delete saved game: " + gameID); - - // Run init again to refresh saved game list - init(); -} - -function deleteTooltip() -{ - let tooltip = colorizeHotkey( - translate("Delete the selected entry using %(hotkey)s."), - "session.savedgames.delete"); - - if (tooltip) - tooltip += colorizeHotkey( - "\n" + translate("Hold %(hotkey)s to delete without confirmation."), - "session.savedgames.noconfirmation"); - - return tooltip; -} Index: binaries/data/mods/public/gui/loadgame/SavegameWriter.js =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/loadgame/SavegameWriter.js @@ -0,0 +1,52 @@ +/** + * This class obtains the current simulation state to be saved along the savegame, + * asks the user whether to overwrite a savegame and performs the saving. + */ +class SavegameWriter +{ + constructor(data) + { + this.savedGameData = data && data.savedGameData || {}; + let simulationState = Engine.GuiInterfaceCall("GetSimulationState"); + this.savedGameData.timeElapsed = simulationState.timeElapsed; + this.savedGameData.states = simulationState.players.map(pState => pState.state); + } + + getSavedGameData() + { + return this.savedGameData; + } + + saveGame() + { + let gameSelection = Engine.GetGUIObjectByName("gameSelection"); + let gameLabel = gameSelection.list[gameSelection.selected]; + let gameID = gameSelection.list_data[gameSelection.selected]; + let desc = Engine.GetGUIObjectByName("saveGameDesc").caption; + let name = gameID || "savegame"; + + if (!gameID) + { + this.reallySaveGame(name, desc, true); + return; + } + + messageBox( + 500, 200, + sprintf(translate("\"%(label)s\""), { "label": gameLabel }) + "\n" + + translate("Saved game will be permanently overwritten, are you sure?"), + translate("OVERWRITE SAVE"), + [translate("No"), translate("Yes")], + [null, () => { this.reallySaveGame(name, desc, false); }]); + } + + reallySaveGame(name, desc, nameIsPrefix) + { + if (nameIsPrefix) + Engine.SaveGamePrefix(name, desc, this.savedGameData); + else + Engine.SaveGame(name, desc, this.savedGameData); + + Engine.PopGuiPage(); + } +} Index: binaries/data/mods/public/gui/loadgame/functions_utility_loadsave.js =================================================================== --- binaries/data/mods/public/gui/loadgame/functions_utility_loadsave.js +++ binaries/data/mods/public/gui/loadgame/functions_utility_loadsave.js @@ -64,8 +64,7 @@ if (!Engine.DeleteSavedGame(gameID)) error("Could not delete saved game: " + gameID); - // Run init again to refresh saved game list - init(); + updateSavegameList(); } function deleteTooltip() Index: binaries/data/mods/public/gui/loadgame/load.js =================================================================== --- binaries/data/mods/public/gui/loadgame/load.js +++ binaries/data/mods/public/gui/loadgame/load.js @@ -1,3 +1,5 @@ +var g_SavegameWriter; + var g_SavedGamesMetadata = []; /** @@ -5,7 +7,29 @@ */ const g_CivData = loadCivData(false, false); -function init() +function init(data) +{ + let save = Engine.IsGameStarted(); + if (save) + g_SavegameWriter = new SavegameWriter(data); + + let confirmButton = Engine.GetGUIObjectByName("confirmButton"); + confirmButton.caption = save ? translate("Save") : translate("Load"); + confirmButton.onPress = save ? () => { g_SavegameWriter.saveGame(); } : loadGame; + Engine.GetGUIObjectByName("title").caption = save ? translate("Save Game") : translate("Load Game") + Engine.GetGUIObjectByName("saveGameDesc").hidden = !save; + + updateSavegameList(); + + // Select the most recent savegame to be loaded, or no savegame to be overwritten + let gameSelection = Engine.GetGUIObjectByName("gameSelection"); + if (!save && gameSelection.list.length) + gameSelection.selected = 0; + else + selectionChanged(); +} + +function updateSavegameList() { let savedGames = Engine.GetSavedGames(); @@ -17,6 +41,10 @@ let gameSelection = Engine.GetGUIObjectByName("gameSelection"); gameSelection.enabled = !!savedGames.length; + gameSelection.onSelectionChange = selectionChanged; + gameSelection.onSelectionColumnChange = updateSavegameList; + gameSelection.onMouseLeftDoubleClickItem = loadGame; + Engine.GetGUIObjectByName("gameSelectionFeedback").hidden = !!savedGames.length; let selectedGameId = gameSelection.list_data[gameSelection.selected]; @@ -87,9 +115,6 @@ gameSelection.selected = selectedGameIndex; else if (gameSelection.selected >= g_SavedGamesMetadata.length) // happens when deleting the last saved game gameSelection.selected = g_SavedGamesMetadata.length - 1; - else if (gameSelection.selected == -1 && g_SavedGamesMetadata.length) - gameSelection.selected = 0; - selectionChanged(); Engine.GetGUIObjectByName("deleteGameButton").tooltip = deleteTooltip(); } @@ -99,7 +124,7 @@ let metadata = g_SavedGamesMetadata[Engine.GetGUIObjectByName("gameSelection").selected]; Engine.GetGUIObjectByName("invalidGame").hidden = !!metadata; Engine.GetGUIObjectByName("validGame").hidden = !metadata; - Engine.GetGUIObjectByName("loadGameButton").enabled = !!metadata; + Engine.GetGUIObjectByName("confirmButton").enabled = !!metadata || Engine.IsGameStarted(); Engine.GetGUIObjectByName("deleteGameButton").enabled = !!metadata; if (!metadata) @@ -170,8 +195,7 @@ message, translate("Warning"), [translate("No"), translate("Yes")], - [init, function(){ reallyLoadGame(gameId); }] - ); + [undefined, () => { reallyLoadGame(gameId); }]); } function reallyLoadGame(gameId) @@ -179,10 +203,7 @@ let metadata = Engine.StartSavedGame(gameId); if (!metadata) { - // Probably the file wasn't found - // Show error and refresh saved game list error("Could not load saved game: " + gameId); - init(); return; } Index: binaries/data/mods/public/gui/loadgame/load.xml =================================================================== --- binaries/data/mods/public/gui/loadgame/load.xml +++ binaries/data/mods/public/gui/loadgame/load.xml @@ -10,9 +10,7 @@ - - Load Game - + - selectionChanged(); - init(); - loadGame(); - Date / Time @@ -49,6 +43,10 @@ No saved games found. + + saveGame(); + + Cancel Engine.PopGuiPage(); @@ -59,16 +57,12 @@ deleteGame(); - - Load - loadGame(); - - + - init(); + updateSavegameList(); @@ -79,7 +73,7 @@ - + Players: Index: binaries/data/mods/public/gui/page_savegame.xml =================================================================== --- binaries/data/mods/public/gui/page_savegame.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - common/modern/setup.xml - common/modern/styles.xml - common/modern/sprites.xml - - common/setup.xml - common/sprites.xml - common/styles.xml - - savegame/save.xml - Index: binaries/data/mods/public/gui/savegame/save.js =================================================================== --- binaries/data/mods/public/gui/savegame/save.js +++ binaries/data/mods/public/gui/savegame/save.js @@ -1,84 +0,0 @@ -var g_Descriptions; -var g_SavedGameData; - -function selectDescription() -{ - let gameSelection = Engine.GetGUIObjectByName("gameSelection"); - let gameID = gameSelection.list_data[gameSelection.selected]; - Engine.GetGUIObjectByName("deleteGameButton").enabled = !!gameID; - - if (!gameID) - return; - - Engine.GetGUIObjectByName("saveGameDesc").caption = g_Descriptions[gameID]; -} - -function init(data) -{ - g_SavedGameData = data && data.savedGameData || {}; - let simulationState = Engine.GuiInterfaceCall("GetSimulationState"); - g_SavedGameData.timeElapsed = simulationState.timeElapsed; - g_SavedGameData.states = simulationState.players.map(pState => pState.state); - - let savedGames = Engine.GetSavedGames().sort(sortDecreasingDate); - - let gameSelection = Engine.GetGUIObjectByName("gameSelection"); - gameSelection.enabled = savedGames.length != 0; - - if (!savedGames.length) - { - gameSelection.list = [translate("No saved games found")]; - gameSelection.selected = -1; - return; - } - - g_Descriptions = {}; - for (let game of savedGames) - g_Descriptions[game.id] = game.metadata.description || ""; - - let engineInfo = Engine.GetEngineInfo(); - gameSelection.list = savedGames.map(game => generateSavegameLabel(game.metadata, engineInfo)); - gameSelection.list_data = savedGames.map(game => game.id); - gameSelection.selected = Math.min(gameSelection.selected, gameSelection.list.length - 1); - - Engine.GetGUIObjectByName("deleteGameButton").tooltip = deleteTooltip(); -} - -function saveGame() -{ - let gameSelection = Engine.GetGUIObjectByName("gameSelection"); - let gameLabel = gameSelection.list[gameSelection.selected]; - let gameID = gameSelection.list_data[gameSelection.selected]; - let desc = Engine.GetGUIObjectByName("saveGameDesc").caption; - let name = gameID || "savegame"; - - if (!gameID) - { - reallySaveGame(name, desc, true); - return; - } - - messageBox( - 500, 200, - sprintf(translate("\"%(label)s\""), { "label": gameLabel }) + "\n" + - translate("Saved game will be permanently overwritten, are you sure?"), - translate("OVERWRITE SAVE"), - [translate("No"), translate("Yes")], - [null, function(){ reallySaveGame(name, desc, false); }] - ); -} - -function reallySaveGame(name, desc, nameIsPrefix) -{ - if (nameIsPrefix) - Engine.SaveGamePrefix(name, desc, g_SavedGameData); - else - Engine.SaveGame(name, desc, g_SavedGameData); - - closeSave(); -} - -function closeSave() -{ - Engine.PopGuiPage(); -} Index: binaries/data/mods/public/gui/savegame/save.xml =================================================================== --- binaries/data/mods/public/gui/savegame/save.xml +++ binaries/data/mods/public/gui/savegame/save.xml @@ -1,52 +0,0 @@ - - - - -