Ticket #2373: resignation_v3.patch

File resignation_v3.patch, 16.7 KB (added by Michael, 10 years ago)

Works for at least two players.

  • binaries/data/mods/public/gui/common/functions_global_object.js

     
    2222{
    2323    if (btnCode !== undefined && g_messageBoxBtnFunctions[btnCode])
    2424    {
    25         if (g_messageBoxCallbackArgs[btnCode])
    26             g_messageBoxBtnFunctions[btnCode](g_messageBoxCallbackArgs[btnCode]);
     25        // cache the vales to make it possible to call a messageBox from a callback function.
     26        var callbackFunction = g_messageBoxBtnFunctions[btnCode];
     27        var callbackArgs = g_messageBoxCallbackArgs[btnCode]
     28        g_messageBoxBtnFunctions  = [];
     29        g_messageBoxCallbackArgs = [];
     30
     31        if (callbackArgs !== undefined)
     32            callbackFunction(callbackArgs);
    2733        else
    28             g_messageBoxBtnFunctions[btnCode]();
     34            callbackFunction();
     35           
     36        return;
    2937    }
    30 
    3138    g_messageBoxBtnFunctions  = [];
    3239    g_messageBoxCallbackArgs = [];
    3340}
  • binaries/data/mods/public/gui/session/menu.js

     
    147147    closeOpenDialogs();
    148148    pauseGame();
    149149    var btCaptions = ["Yes", "No"];
    150     var btCode = [leaveGame, resumeGame];
     150    var btCode = [g_IsNetworked && !g_GameEnded ? networkReturnQuestion : prepareLeaveGame, resumeGame];
    151151    messageBox(400, 200, "Are you sure you want to quit?", "Confirmation", 0, btCaptions, btCode);
    152152}
    153153
     154function networkReturnQuestion()
     155{
     156    var btCaptions = ["Yes, I will return", "No, I resign"];
     157    var btCode = [prepareLeaveGame, prepareLeaveGame];
     158    var btArgs = [true, false];
     159    messageBox(400, 200, "You are exiting the game, will you return soon?", "Confirmation", 0, btCaptions, btCode, btArgs);
     160}
    154161
    155162function openDeleteDialog(selection)
    156163{
  • binaries/data/mods/public/gui/session/messages.js

     
    207207        {
    208208            if (! message.hosts[host])
    209209            {
     210                // cache values
     211                var removedPlayerID = g_PlayerAssignments[host].player;
     212                var removedPlayerName = g_PlayerAssignments[host].name;
     213                var removedPlayerState = g_Players[removedPlayerID].state;
    210214                // Tell the user about the disconnection
    211215                addChatMessage({ "type": "disconnect", "guid": host });
    212216
    213217                // Update the cached player data, so we can display the disconnection status
    214218                updatePlayerDataRemove(g_Players, host);
     219
     220                if (removedPlayerState != "active")
     221                    return;
     222                // start timer and show timeout message
     223                Engine.PostNetworkCommand({
     224                    "type": "start-player-timeout",
     225                    "playerID": removedPlayerID,
     226                    "playerName": removedPlayerName,
     227                    "rejoinTimeLimit": REJOIN_TIME_LIMIT
     228                });
    215229            }
    216230        }
    217231
     
    225239
    226240                // Tell the user about the connection
    227241                addChatMessage({ "type": "connect", "guid": host }, message.hosts);
     242           
     243                if (g_Players[message.hosts[host].player].state != "active")
     244                    return;
     245                // stop timer and show timeout message
     246                Engine.PostNetworkCommand({
     247                    "type": "stop-player-timeout",
     248                    "playerID": message.hosts[host].player,
     249                });
    228250            }
    229251        }
    230252
  • binaries/data/mods/public/gui/session/session.js

     
    11// Network Mode
    22var g_IsNetworked = false;
     3const REJOIN_TIME_LIMIT = 15; // rejoin time limit in seconds
     4const TIME_UNTIL_ENGINE_ENDS_GAME = 5000; // time in ms until the engine quits the game (in MP with resign)
    35
    46// Is this user in control of game settings (i.e. is a network server, or offline player)
    57var g_IsController;
     
    3739// Whether the player has lost/won and reached the end of their game
    3840var g_GameEnded = false;
    3941
     42// true, if prepareLeaveGame() was called
     43var g_leaveGameInProcess = false;
     44
    4045var g_Disconnected = false; // Lost connection to server
    4146
    4247// Holds player states from the last tick
     
    234239    Engine.SubmitUserReport("profile", 3, JSON.stringify(data));
    235240}
    236241
    237 function resignGame()
     242/**
     243 * let's a player resign
     244 * leaveGameAfterResign: if true, game is quit, after resign
     245 */
     246function resignGame(leaveGameAfterResign)
    238247{
    239248    var simState = GetSimState();
    240249
     
    248257        "playerId": Engine.GetPlayerID()
    249258    });
    250259
    251     global.music.setState(global.music.states.DEFEAT);
    252     resumeGame();
     260    // resume to the game, if the resign button was used
     261    if (!leaveGameAfterResign)
     262    {
     263        global.music.setState(global.music.states.DEFEAT);
     264        resumeGame();
     265    }
    253266}
    254267
    255 function leaveGame()
     268/**
     269 * prepare to leave the game
     270 * willRejoin: can be set to true, in case of network game, if the player just has to reboot or restart the game
     271 */
     272function prepareLeaveGame(willRejoin)
    256273{
    257274    var extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState");
    258275    var playerState = extendedSimState.players[Engine.GetPlayerID()];
    259276    var mapSettings = Engine.GetMapSettings();
    260277    var gameResult;
     278    var timeUntilEngineEndsGame = 1;
    261279
    262280    if (g_Disconnected)
    263281    {
     
    274292    else // "active"
    275293    {
    276294        gameResult = "You have abandoned the game.";
    277 
    278         // Tell other players that we have given up and been defeated
    279         Engine.PostNetworkCommand({
    280             "type": "defeat-player",
    281             "playerId": Engine.GetPlayerID()
    282         });
    283 
    284295        global.music.setState(global.music.states.DEFEAT);
     296       
     297        // resign, if player click on "No, I resign"
     298        if (!willRejoin)
     299        {
     300            gameResult = "You have been defeated...";
     301            resignGame(true);
     302            timeUntilEngineEndsGame = TIME_UNTIL_ENGINE_ENDS_GAME; // give engine some time to deliver the network message (before the client disconnects...)
     303        }
    285304    }
     305    g_leaveGameInProcess = true;
     306    setTimeout(function() { leaveGame({"gameResult": gameResult, "extendedSimState": extendedSimState, "mapSettings": mapSettings}); }, timeUntilEngineEndsGame);
     307}
    286308
     309/**
     310 * leaves the game; is needed to give network messages time to reach their destination
     311 * data: must contain gameResult, extendedSimState and mapSettings
     312 */
     313function leaveGame(data)
     314{
    287315    stopAmbient();
    288316    Engine.EndGame();
    289317
     
    291319        Engine.SendUnregisterGame();
    292320
    293321    Engine.SwitchGuiPage("page_summary.xml", {
    294                             "gameResult"  : gameResult,
    295                             "timeElapsed" : extendedSimState.timeElapsed,
    296                             "playerStates": extendedSimState.players,
     322                            "gameResult"  : data.gameResult,
     323                            "timeElapsed" : data.extendedSimState.timeElapsed,
     324                            "playerStates": data.extendedSimState.players,
    297325                            "players": g_Players,
    298                             "mapSettings": mapSettings
     326                            "mapSettings": data.mapSettings
    299327                         });
    300328}
    301329
     
    427455        var btCode = [null];
    428456        var message = "Press OK to continue";
    429457    }
    430     else
     458    else if (!g_leaveGameInProcess)
    431459    {
    432460        var btCaptions = ["Yes", "No"];
    433         var btCode = [leaveGame, null];
     461        var btCode = [prepareLeaveGame, null];
    434462        var message = "Do you want to quit?";
    435463    }
     464    else
     465    {
     466        var btCaptions = ["Ok"];
     467        var btCode = [null];
     468        var message = "You have been defeated. Game will exit now.";
     469    }
    436470
    437471    if (playerState.state == "defeated")
    438472    {
  • binaries/data/mods/public/gui/session/session.xml

     
    3939    <!--
    4040        <action on="Press"><![CDATA[
    4141            messageBox(400, 200, "Do you really want to quit?", "Confirmation", 0,
    42                 ["Yes", "No!"], [leaveGame, null]);
     42                ["Yes", "No!"], [prepareLeaveGame, null]);
    4343        ]]></action>
    4444    -->
    4545
     
    776776        z="40"
    777777    >
    778778        <object size="4 36 100%-4 50%+20">
     779       
     780            <!-- Manual button -->
     781            <object type="button"
     782                name="manualButton"
     783                style="StoneButtonFancy"
     784                size="0 0 100% 28"
     785                tooltip_style="sessionToolTip"
     786            >
     787                Manual
     788                <action on="Press">openManual();</action>
     789            </object>
     790           
     791            <!-- Chat button -->
     792            <object type="button"
     793                name="chatButton"
     794                style="StoneButtonFancy"
     795                size="0 32 100% 60"
     796                tooltip_style="sessionToolTip"
     797            >
     798                Chat
     799                <action on="Press">chatMenuButton();</action>
     800            </object>
    779801
    780         <!-- Settings button -->
    781         <object type="button"
    782             name="settingsButton"
    783             style="StoneButtonFancy"
    784             size="0 0 100% 28"
    785             tooltip_style="sessionToolTip"
    786         >
    787             Settings
    788             <action on="Press">settingsMenuButton();</action>
    789         </object>
     802            <!-- Save game button -->
     803            <object type="button"
     804                name="saveGameButton"
     805                style="StoneButtonFancy"
     806                size="0 64 100% 92"
     807                tooltip_style="sessionToolTip"
     808            >
     809                Save
     810                <action on="Press">
     811                openSave();
     812                </action>
     813            </object>
     814           
     815            <!-- Settings button -->
     816            <object type="button"
     817                name="settingsButton"
     818                style="StoneButtonFancy"
     819                size="0 96 100% 124"
     820                tooltip_style="sessionToolTip"
     821            >
     822                Settings
     823                <action on="Press">settingsMenuButton();</action>
     824            </object>
    790825
    791 
    792         <!-- Save game button -->
    793         <object type="button"
    794             name="saveGameButton"
    795             style="StoneButtonFancy"
    796             size="0 32 100% 60"
    797             tooltip_style="sessionToolTip"
    798         >
    799             Save
    800             <action on="Press">
    801             openSave();
    802             </action>
     826            <!-- Pause / Resume Button -->
     827            <object type="button"
     828                name="pauseButton"
     829                style="StoneButtonFancy"
     830                size="0 128 100% 156"
     831                tooltip_style="sessionToolTip"
     832            >
     833                <object name="pauseButtonText" type="text" style="CenteredButtonText" ghost="true">Pause</object>
     834                <action on="Press">togglePause();</action>
     835            </object>
     836           
     837            <!-- Resign button -->
     838            <object type="button"
     839                name="menuResignButton"
     840                style="StoneButtonFancy"
     841                size="0 160 100% 188"
     842                tooltip_style="sessionToolTip"
     843            >
     844                Resign
     845                <action on="Press">resignMenuButton();</action>
     846            </object>
     847           
     848            <!-- Exit button -->
     849            <object type="button"
     850                name="menuExitButton"
     851                style="StoneButtonFancy"
     852                size="0 192 100% 220"
     853                tooltip_style="sessionToolTip"
     854            >
     855                Exit
     856                <action on="Press">exitMenuButton();</action>
     857            </object>
    803858        </object>
    804 
    805         <!-- Chat button -->
    806         <object type="button"
    807             name="chatButton"
    808             style="StoneButtonFancy"
    809             size="0 64 100% 92"
    810             tooltip_style="sessionToolTip"
    811         >
    812             Chat
    813             <action on="Press">chatMenuButton();</action>
    814         </object>
    815 
    816         <!-- Resign button -->
    817         <object type="button"
    818             name="menuResignButton"
    819             style="StoneButtonFancy"
    820             size="0 96 100% 124"
    821             tooltip_style="sessionToolTip"
    822         >
    823             Resign
    824             <action on="Press">resignMenuButton();</action>
    825         </object>
    826 
    827         <!-- Exit button -->
    828         <object type="button"
    829             name="menuExitButton"
    830             style="StoneButtonFancy"
    831             size="0 128 100% 156"
    832             tooltip_style="sessionToolTip"
    833         >
    834             Exit
    835             <action on="Press">exitMenuButton();</action>
    836         </object>
    837 
    838         <!-- Pause / Resume Button -->
    839         <object type="button"
    840             name="pauseButton"
    841             style="StoneButtonFancy"
    842             size="0 160 100% 188"
    843             tooltip_style="sessionToolTip"
    844         >
    845             <object name="pauseButtonText" type="text" style="CenteredButtonText" ghost="true">Pause</object>
    846             <action on="Press">togglePause();</action>
    847         </object>
    848 
    849         <!-- Manual button -->
    850         <object type="button"
    851             name="manualButton"
    852             style="StoneButtonFancy"
    853             size="0 192 100% 220"
    854             tooltip_style="sessionToolTip"
    855         >
    856             Manual
    857             <action on="Press">openManual();</action>
    858         </object>
    859         </object>
    860859    </object>
    861860
    862861    <!-- In-progress research -->
     
    13541353        tooltip_style="sessionToolTip"
    13551354    >
    13561355        <object size="0 0 100% 100%" type="text" style="CenteredButtonText" name="disconnectedExitButtonText" ghost="true">Exit</object>
    1357         <action on="Press">leaveGame()</action>
     1356        <action on="Press">prepareLeaveGame()</action>
    13581357    </object>
    13591358
    13601359    </object>
  • binaries/data/mods/public/simulation/components/EndGameManager.js

     
    1919    // Allied victory means allied players can win if victory conditions are met for each of them
    2020    // Would be false for a "last man standing" game (when diplomacy is fully implemented)
    2121    this.alliedVictory = true;
     22   
     23    // is used to store IDs of timer for auto timeout in multiplayer game
     24    // uses as indices the playerID of the player, which times out.
     25    this.autoPlayerTimeout = [];
    2226};
    2327
    2428EndGameManager.prototype.SetGameType = function(newGameType)
     
    3236    return this.gameType == type;
    3337};
    3438
     39/**
     40 * starts the timeout counter, if a player leaves a multiplayer game
     41 * playerID: ID of the player which left
     42 * playerName: name of the player which left
     43 * timeout: time in ms until the is timed out
     44 */
     45EndGameManager.prototype.startPlayerTimeout = function(playerID, playerName, timeout)
     46{
     47    // check, if the player is active
     48    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     49    var playerEntityId = cmpPlayerManager.GetPlayerByID(playerID);
     50    var cmpPlayer =  Engine.QueryInterface(playerEntityId, IID_Player);
     51
     52    if (!cmpPlayer || cmpPlayer.GetState() != "active")
     53        return;
     54    // query some stuff
     55    var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     56    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     57    if (!cmpGuiInterface || !cmpTimer || !cmpPlayerManager)
     58        return;
     59       
     60    // get players to send the message
     61    var players = [];
     62    for (var i = 1; i < cmpPlayerManager.GetNumPlayers(); i++)
     63            players.push(i);   
     64
     65    // add timers
     66    var textTimerID = cmpGuiInterface.AddTimeNotification({
     67        "message": playerName + " will be auto-resigned in %T",
     68        "players": players,
     69        "time": timeout
     70    });     
     71    var timerID = cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_EndGameManager, "MarkPlayerAsAutoResigned", timeout, playerID);
     72    // save timer IDs
     73    this.autoPlayerTimeout[playerID] = [textTimerID, timerID];
     74};
     75
     76/**
     77 * stops the timeout of a player, if he rejoins
     78 * playerID: ID of the player which rejoined
     79 */
     80EndGameManager.prototype.stopPlayerTimeout = function(playerID)
     81{
     82    if (!this.autoPlayerTimeout[playerID]) // no timeout for player running
     83        return;
     84    var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     85    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     86    if (!cmpGuiInterface || !cmpTimer)
     87        return;
     88   
     89    // delete the timers
     90    var timerIDs = this.autoPlayerTimeout[playerID];
     91    cmpGuiInterface.DeleteTimeNotification(timerIDs[0]);
     92    cmpTimer.CancelTimer(timerIDs[1]);
     93    delete this.autoPlayerTimeout[playerID];
     94};
     95
     96
     97/**
     98 * marks an player as auto resigned after an timeout. (is called by startPlayerTimeout normally)
     99 * playerID: player ID of the player to mark as auto resigned
     100 */
     101EndGameManager.prototype.MarkPlayerAsAutoResigned = function(playerID)
     102{
     103    var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     104    if (!cmpPlayerMan)
     105        return;
     106
     107    var playerEnt = cmpPlayerMan.GetPlayerByID(playerID);
     108    if (playerEnt == INVALID_ENTITY)
     109        return;
     110
     111    // send OnPlayerDefeated message
     112    Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": playerID } );
     113};
     114
    35115EndGameManager.prototype.MarkPlayerAsWon = function(playerID)
    36116{
    37117    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    321321        Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": player } );
    322322        break;
    323323
     324    case "start-player-timeout":
     325        var cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager);
     326        if (!cmpEndGameManager)
     327            return;
     328        cmpEndGameManager.startPlayerTimeout(cmd.playerID, cmd.playerName, cmd.rejoinTimeLimit * 1000);
     329        break;
     330       
     331    case "stop-player-timeout":
     332        var cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager);
     333        if (!cmpEndGameManager)
     334            return;
     335        cmpEndGameManager.stopPlayerTimeout(cmd.playerID);
     336        break;
     337       
    324338    case "garrison":
    325339        // Verify that the building can be controlled by the player or is mutualAlly
    326340        if (CanControlUnitOrIsAlly(cmd.target, player, controlAllUnits))