Ticket #1090: loadsave-v4.patch

File loadsave-v4.patch, 18.5 KB (added by mimo, 2 years ago)
  • binaries/data/mods/public/gui/common/common_styles.xml

     
    304304        tooltip_style="pgToolTip"
    305305    />
    306306
     307    <style name="MapPlayerList"
     308        buffer_zone="8"
     309        font="sans-14"
     310        scrollbar="true"
     311        scrollbar_style="ModernScrollBar"
     312        scroll_bottom="false"
     313        textcolor="white"
     314        text_align="left"
     315        text_valign="top"
     316    />
    307317        <!--
    308318    ==========================================
    309319    CIV ICON
  • binaries/data/mods/public/gui/common/functions_utility.js

     
    205205    } catch (e) {
    206206    }
    207207}
     208
     209/**
     210 * Returns a formatted string describing the player assignments.
     211 * Including civs, teams, AI settings and player colors
     212 * which are given in data (array of objects per player).
     213 *
     214 * @returns {string}
     215 */
     216function formatPlayerInfo(data)
     217{
     218    let playerDescriptions = {};
     219    let playerIdx = 0;
     220    for (let playerData of data)
     221    {
     222        ++playerIdx;
     223        let teamIdx = playerData.Team;
     224        let showDefeated = playerData.state && playerData.state == "defeated";
     225        let isAI = playerData.AI && playerData.AI != "";
     226
     227        // Create human-readable player description
     228
     229        let translated;
     230        if (!isAI && !showDefeated)
     231            translated = translateWithContext("replay", "%(playerName)s (%(civ)s)");
     232        else if (!isAI && showDefeated)
     233            translated = translateWithContext("replay", "%(playerName)s (%(civ)s, defeated)");
     234        else if (isAI && !showDefeated)
     235            translated = translateWithContext("replay", "%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s)");
     236        else
     237            translated = translateWithContext("replay", "%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s, defeated)");
     238
     239        translated = sprintf(translated, {
     240            "playerName": '[color="' + rgbToGuiColor(playerData.Color) + '"]' + escapeText(playerData.Name) + "[/color]",
     241            "civ": playerData.Civ,
     242            "AIname": isAI ? translateAIName(playerData.AI) : "",
     243            "AIdifficulty": isAI ? translateAIDifficulty(playerData.AIDiff) : ""
     244        });
     245
     246        // Sort player descriptions by team
     247        if (!playerDescriptions[teamIdx])
     248            playerDescriptions[teamIdx] = [];
     249        playerDescriptions[teamIdx].push(translated);
     250    }
     251
     252    let teams = Object.keys(playerDescriptions);
     253
     254    // If there are no teams, merge all playersDescriptions
     255    if (teams.length == 1)
     256        return playerDescriptions[teams[0]].join("\n") + "\n";
     257
     258    // If there are teams, merge "Team N:" + playerDescriptions
     259    return teams.map(team => {
     260        let teamCaption = (team == -1) ? translate("No Team") : sprintf(translate("Team %(team)s"), { "team": +team + 1 });
     261        return '[font="sans-bold-14"]' + teamCaption + "[/font]:\n" + playerDescriptions[team].join("\n");
     262    }).join("\n\n");
     263}
  • binaries/data/mods/public/gui/page_replaymenu.xml

     
    1010    <include>common/common_sprites.xml</include>
    1111    <include>common/common_styles.xml</include>
    1212
    13     <include>replaymenu/styles.xml</include>
    1413    <include>replaymenu/replay_menu.xml</include>
    1514</page>
  • binaries/data/mods/public/gui/replaymenu/replay_menu.js

     
    346346    const metadata = Engine.GetReplayMetadata(replay.directory);
    347347    const spoiler = Engine.GetGUIObjectByName("showSpoiler").checked;
    348348
    349     var playerDescriptions = {};
    350     var playerIdx = 0;
     349    let data = [];
     350    let playerIdx = 0;
    351351    for (let playerData of replay.attribs.settings.PlayerData)
    352352    {
    353         // Get player info
    354353        ++playerIdx;
    355         let teamIdx = playerData.Team;
    356         let playerColor = playerData.Color ? playerData.Color : g_Settings.PlayerDefaults[playerIdx].Color;
    357         let playerCiv = !playerData.Civ ? translate("Unknown Civilization") : (g_CivData[playerData.Civ] && g_CivData[playerData.Civ].Name ? translate(g_CivData[playerData.Civ].Name) : playerData.Civ);
    358         let showDefeated = spoiler && metadata && metadata.playerStates && metadata.playerStates[playerIdx].state == "defeated";
    359         let isAI = playerData.AI;
    360 
    361         // Create human-readable player description
    362         let playerDetails = {
    363             "playerName": '[color="' + rgbToGuiColor(playerColor) + '"]' + escapeText(playerData.Name) + "[/color]",
    364             "civ": playerCiv,
    365             "AIname": isAI ? translateAIName(playerData.AI) : "",
    366             "AIdifficulty": isAI ? translateAIDifficulty(playerData.AIDiff) : ""
    367         };
    368 
    369         if (!isAI && !showDefeated)
    370             playerDetails = sprintf(translateWithContext("replay", "%(playerName)s (%(civ)s)"), playerDetails);
    371         else if (!isAI && showDefeated)
    372             playerDetails = sprintf(translateWithContext("replay", "%(playerName)s (%(civ)s, defeated)"), playerDetails);
    373         else if (isAI && !showDefeated)
    374             playerDetails = sprintf(translateWithContext("replay", "%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s)"), playerDetails);
    375         else
    376             playerDetails = sprintf(translateWithContext("replay", "%(playerName)s (%(civ)s, %(AIdifficulty)s %(AIname)s, defeated)"), playerDetails);
    377 
    378         // Sort player descriptions by team
    379         if (!playerDescriptions[teamIdx])
    380             playerDescriptions[teamIdx] = [];
    381         playerDescriptions[teamIdx].push(playerDetails);
     354        data.push({
     355            "Team": playerData.Team,
     356            "Name": playerData.Name,
     357            "Civ": !playerData.Civ ? translate("Unknown Civilization") :
     358                (g_CivData[playerData.Civ] && g_CivData[playerData.Civ].Name ? translate(g_CivData[playerData.Civ].Name) : playerData.Civ),
     359            "Color": playerData.Color ? playerData.Color : g_Settings.PlayerDefaults[playerIdx].Color,
     360            "AI": playerData.AI,
     361            "AIDiff": playerData.AIDiff,
     362            "Defeated": spoiler && metadata && metadata.playerStates && metadata.playerStates[playerIdx].state == "defeated"
     363        });
    382364    }
    383365
    384     var teams = Object.keys(playerDescriptions);
    385 
    386     // If there are no teams, merge all playersDescriptions
    387     if (teams.length == 1)
    388         return playerDescriptions[teams[0]].join("\n") + "\n";
    389 
    390     // If there are teams, merge "Team N:" + playerDescriptions
    391     return teams.map(team => {
    392         let teamCaption = (team == -1) ? translate("No Team") : sprintf(translate("Team %(team)s"), { "team": +team + 1 });
    393         return '[font="sans-bold-14"]' + teamCaption + "[/font]:\n" + playerDescriptions[team].join("\n");
    394     }).join("\n");
     366    return formatPlayerInfo(data);
    395367}
  • binaries/data/mods/public/gui/replaymenu/styles.xml

     
    1 <?xml version="1.0" encoding="utf-8"?>
    2 
    3 <styles>
    4     <style name="MapPlayerList"
    5         buffer_zone="8"
    6         font="sans-14"
    7         scrollbar="true"
    8         scrollbar_style="ModernScrollBar"
    9         scroll_bottom="true"
    10         textcolor="white"
    11         text_align="left"
    12         text_valign="top"
    13     />
    14 </styles>
  • binaries/data/mods/public/gui/savedgames/load.js

     
    88    if (!savedGames.length)
    99    {
    1010        gameSelection.list = [translate("No saved games found")];
    11         gameSelection.selected = 0;
     11        gameSelection.selected = -1;
     12        selectionChanged();
    1213        Engine.GetGUIObjectByName("loadGameButton").enabled = false;
    1314        Engine.GetGUIObjectByName("deleteGameButton").enabled = false;
    1415        return;
     
    2627        gameSelection.selected = 0;
    2728    else if (gameSelection.selected >= savedGames.length) // happens when deleting the last saved game
    2829        gameSelection.selected = savedGames.length - 1;
     30    else
     31        selectionChanged();
    2932}
    3033
     34function selectionChanged()
     35{
     36    let gameSelection = Engine.GetGUIObjectByName("gameSelection");
     37    let selectionEmpty = gameSelection.selected == -1;
     38    Engine.GetGUIObjectByName("invalidGame").hidden = !selectionEmpty;
     39    Engine.GetGUIObjectByName("validGame").hidden = selectionEmpty;
     40
     41    if (selectionEmpty)
     42        return;
     43
     44    let metadata = g_SavedGamesMetadata[gameSelection.selected];
     45
     46    Engine.GetGUIObjectByName("savedMapName").caption = translate(metadata.initAttributes.settings.Name);
     47    let mapData = getMapDescriptionAndPreview(metadata.initAttributes.mapType, metadata.initAttributes.map);
     48    setMapPreviewImage("savedInfoPreview", mapData.preview);
     49
     50    Engine.GetGUIObjectByName("savedPlayers").caption = metadata.initAttributes.settings.PlayerData.length - 1;
     51    Engine.GetGUIObjectByName("savedPlayedTime").caption = timeToString(metadata.gui.timeElapsed ? metadata.gui.timeElapsed : 0);
     52    Engine.GetGUIObjectByName("savedMapType").caption = translateMapType(metadata.initAttributes.mapType);
     53    Engine.GetGUIObjectByName("savedMapSize").caption = translateMapSize(metadata.initAttributes.settings.Size);
     54    Engine.GetGUIObjectByName("savedVictory").caption = translateVictoryCondition(metadata.initAttributes.settings.GameType);
     55
     56    let caption = sprintf(translate("Mods: %(mods)s"), { "mods": metadata.mods.join(translate(", ")) });
     57    if (!hasSameMods(metadata, Engine.GetEngineInfo()))
     58        caption = "[color=\"orange\"]" + caption + "[/color]";
     59    Engine.GetGUIObjectByName("savedMods").caption = caption;
     60
     61    Engine.GetGUIObjectByName("savedPlayersNames").caption = getPlayerInfoText(metadata);
     62}
     63
    3164function loadGame()
    3265{
    3366    var gameSelection = Engine.GetGUIObjectByName("gameSelection");
     
    151184    // Run init again to refresh saved game list
    152185    init();
    153186}
     187
     188function getPlayerInfoText(metadata)
     189{
     190    let data = [];
     191    let playerIdx = 0;
     192    for (let playerData of metadata.initAttributes.settings.PlayerData)
     193    {
     194        if (playerData == null || playerData.Name == "gaia")
     195            continue;
     196        ++playerIdx;
     197        data.push({
     198            "Team": playerData.Team,
     199            "Name": playerData.Name,
     200            "Civ": playerData.Civ,
     201            "Color": playerData.Color,
     202            "AI": playerData.AI,
     203            "AIDiff": playerData.AIDiff,
     204            "Defeated": metadata.gui.states && metadata.gui.states[playerIdx] == "defeated"
     205        });
     206    }
     207
     208    return formatPlayerInfo(data);
     209}
  • binaries/data/mods/public/gui/savedgames/load.xml

     
    44
    55    <script file="gui/common/functions_global_object.js" />
    66    <script file="gui/common/functions_utility.js" />
     7    <script file="gui/common/settings.js" />
     8
     9    <script file="gui/common/color.js" />
     10
    711    <script file="gui/common/functions_utility_loadsave.js" />
    812    <script file="gui/savedgames/load.js" />
    913
     
    1014    <!-- Add a translucent black background to fade out the menu page -->
    1115    <object type="image" z="0" sprite="BackgroundTranslucent"/>
    1216
    13     <object type="image" style="ModernDialog" size="50%-300 50%-200 50%+300 50%+200">
     17    <object type="image" style="ModernDialog" size="50%-400 50%-325 50%+400 50%+325">
    1418
    1519        <object type="text" style="TitleText" size="50%-128 -18 50%+128 14">
    1620            <translatableAttribute id="caption">Load Game</translatableAttribute>
    1721        </object>
    1822
    19         <object name="gameSelection"
    20             style="ModernList"
    21             type="list"
    22             size="24 24 100%-24 100%-100">
    23         </object>
     23        <object type="image" size="0 20 550 100%">
     24            <object name="gameSelection" style="ModernList" type="list" size="24 12 100%-24 100%-90">
     25                <action on="SelectionChange">selectionChanged();</action>
     26            </object>
    2427
    25         <object type="button" size="0%+25 100%-60 33%+10 100%-32" style="StoneButton" hotkey="cancel">
    26             <translatableAttribute id="caption">Cancel</translatableAttribute>
    27             <action on="Press">Engine.PopGuiPage();</action>
    28         </object>
     28            <object type="button" size="0%+25 100%-60 33%+10 100%-32" style="StoneButton" hotkey="cancel">
     29                <translatableAttribute id="caption">Cancel</translatableAttribute>
     30                <action on="Press">Engine.PopGuiPage();</action>
     31            </object>
    2932
    30         <object name="deleteGameButton" type="button" size="33%+20 100%-60 66%-15 100%-32" style="StoneButton" hotkey="session.savedgames.delete">
    31             <translatableAttribute id="caption">Delete</translatableAttribute>
    32             <action on="Press">
    33                 if (!this.enabled)
    34                     return;
    35                 if (Engine.HotkeyIsPressed("session.savedgames.noconfirmation"))
    36                     deleteGameWithoutConfirmation();
    37                 else
    38                     deleteGame();
    39             </action>
     33            <object name="deleteGameButton" type="button" size="33%+20 100%-60 66%-15 100%-32" style="StoneButton" hotkey="session.savedgames.delete">
     34                <translatableAttribute id="caption">Delete</translatableAttribute>
     35                <action on="Press">
     36                    if (!this.enabled)
     37                        return;
     38                    if (Engine.HotkeyIsPressed("session.savedgames.noconfirmation"))
     39                        deleteGameWithoutConfirmation();
     40                    else
     41                        deleteGame();
     42                </action>
     43            </object>
     44
     45            <object name="loadGameButton" type="button" style="StoneButton" size="66%-5 100%-60 100%-25 100%-32">
     46                <translatableAttribute id="caption">Load</translatableAttribute>
     47                <action on="Press">loadGame();</action>
     48            </object>
     49
    4050        </object>
    4151
    42         <object name="loadGameButton" type="button" style="StoneButton" size="66%-5 100%-60 100%-25 100%-32">
    43             <translatableAttribute id="caption">Load</translatableAttribute>
    44             <action on="Press">loadGame();</action>
     52        <object name="validGame" type="image" size="550 20 100%-20 100%">
     53            <object name="savedMapName" size="0 0 100% 20" type="text" style="ModernLabelText" />
     54            <object name="savedInfoPreview" size="0 20 220 240"  type="image" sprite="" />
     55
     56            <object size="0 250 45% 270" type="text" style="ModernLabelText" text_align="left">
     57                <translatableAttribute id="caption">Players:</translatableAttribute>
     58            </object>
     59            <object name="savedPlayers" size="45% 250 100%-15 270" type="text" style="ModernLabelText" text_align="left" />
     60            <object size="0 270 45% 290" type="text" style="ModernLabelText" text_align="left">
     61                <translatableAttribute id="caption">Played time:</translatableAttribute>
     62            </object>
     63            <object name="savedPlayedTime" size="45% 270 100%-15 290" type="text" style="ModernLabelText" text_align="left" />
     64            <object size="0 290 45% 310" type="text" style="ModernLabelText" text_align="left">
     65                <translatableAttribute id="caption">Map Type:</translatableAttribute>
     66            </object>
     67            <object name="savedMapType" size="45% 290 100%-15 310" type="text" style="ModernLabelText" text_align="left" />
     68            <object size="0 310 45% 330" type="text" style="ModernLabelText" text_align="left">
     69                <translatableAttribute id="caption">Map Size:</translatableAttribute>
     70            </object>
     71            <object name="savedMapSize" size="45% 310 100%-15 330" type="text" style="ModernLabelText" text_align="left" />
     72            <object size="0 330 45% 350" type="text" style="ModernLabelText" text_align="left">
     73                <translatableAttribute id="caption">Victory:</translatableAttribute>
     74            </object>
     75            <object name="savedVictory" size="45% 330 100%-15 350" type="text" style="ModernLabelText" text_align="left" />
     76
     77            <object size="0 352 100%-15 353" type="image" sprite="ModernWhiteLine" z="25" />
     78
     79            <object name="savedMods" size="0 355 100%-15 395" type="text" style="ModernLabelText" text_align="left" />
     80
     81            <object size="0 397 100%-15 398" type="image" sprite="ModernWhiteLine" z="25" />
     82
     83            <object name="savedPlayersNames" size="0 400 100%-10 100%-32" type="text" style="MapPlayerList" />
    4584        </object>
    4685
     86        <object name="invalidGame" size="550 55 770 155" type="image" sprite="logo" />
    4787    </object>
    4888
    49     </objects>
     89</objects>
  • binaries/data/mods/public/gui/savedgames/save.js

     
    33
    44function selectDescription()
    55{
    6     var gameSelection = Engine.GetGUIObjectByName("gameSelection");
     6    let gameSelection = Engine.GetGUIObjectByName("gameSelection");
    77    if (gameSelection.selected == -1)
    88        return;
    99
    10     var gameID = gameSelection.list_data[gameSelection.selected];
     10    let gameID = gameSelection.list_data[gameSelection.selected];
    1111    Engine.GetGUIObjectByName("deleteGameButton").enabled = true;
    1212    Engine.GetGUIObjectByName("saveGameDesc").caption = g_Descriptions[gameID];
    1313}
     
    1414
    1515function init(data)
    1616{
    17     g_SavedGameData = data && data.savedGameData || undefined;
     17    g_SavedGameData = data && data.savedGameData || {};
     18    let simulationState = Engine.GuiInterfaceCall("GetSimulationState");
     19    g_SavedGameData.timeElapsed = simulationState.timeElapsed;
     20    g_SavedGameData.states = [];
     21    for (let player of simulationState.players)
     22        g_SavedGameData.states.push(player.state);
    1823
    19     var gameSelection = Engine.GetGUIObjectByName("gameSelection");
     24    let gameSelection = Engine.GetGUIObjectByName("gameSelection");
    2025    Engine.GetGUIObjectByName("deleteGameButton").enabled = false;
    2126
    22     var savedGames = Engine.GetSavedGames().sort(sortDecreasingDate);
     27    let savedGames = Engine.GetSavedGames().sort(sortDecreasingDate);
    2328    if (!savedGames.length)
    2429    {
    2530        gameSelection.list = [translate("No saved games found")];
     
    3843
    3944function saveGame()
    4045{
    41     var gameSelection = Engine.GetGUIObjectByName("gameSelection");
    42     var gameLabel = gameSelection.list[gameSelection.selected];
    43     var gameID = gameSelection.list_data[gameSelection.selected];
    44     var desc = Engine.GetGUIObjectByName("saveGameDesc").caption;
    45     var name = gameID || "savegame";
     46    let gameSelection = Engine.GetGUIObjectByName("gameSelection");
     47    let gameLabel = gameSelection.list[gameSelection.selected];
     48    let gameID = gameSelection.list_data[gameSelection.selected];
     49    let desc = Engine.GetGUIObjectByName("saveGameDesc").caption;
     50    let name = gameID || "savegame";
    4651
    4752    if (gameSelection.selected == -1)
    4853    {
     
    7883
    7984function deleteGame()
    8085{
    81     var gameSelection = Engine.GetGUIObjectByName("gameSelection");
    82     var gameLabel = gameSelection.list[gameSelection.selected];
    83     var gameID = gameSelection.list_data[gameSelection.selected];
     86    let gameSelection = Engine.GetGUIObjectByName("gameSelection");
     87    let gameLabel = gameSelection.list[gameSelection.selected];
     88    let gameID = gameSelection.list_data[gameSelection.selected];
    8489
    8590    // Ask for confirmation
    8691    messageBox(