]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_endgame.cpp
when multi game ends go back to PXO if we should
[taylor/freespace2.git] / src / network / multi_endgame.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Network/multi_endgame.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * $Log$
16  * Revision 1.3  2002/06/09 04:41:23  relnev
17  * added copyright header
18  *
19  * Revision 1.2  2002/05/07 03:16:47  theoddone33
20  * The Great Newline Fix
21  *
22  * Revision 1.1.1.1  2002/05/03 03:28:10  root
23  * Initial import.
24  * 
25  * 
26  * 10    8/22/99 1:55p Dave
27  * Cleaned up host/team-captain leaving code.
28  * 
29  * 9     8/22/99 1:19p Dave
30  * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
31  * which d3d cards are detected.
32  * 
33  * 8     4/08/99 1:05p Dave
34  * Fixed some leave game packet problems. Updated builtin mission list for
35  * multiplayer.
36  * 
37  * 7     3/24/99 4:05p Dave
38  * Put in support for assigning the player to a specific squadron with a
39  * specific logo. Preliminary work for doing pos/orient checksumming in
40  * multiplayer to reduce bandwidth.
41  * 
42  * 6     11/19/98 4:57p Dave
43  * Ignore PXO option if IPX is selected.
44  * 
45  * 5     11/19/98 4:19p Dave
46  * Put IPX sockets back in psnet. Consolidated all multiplayer config
47  * files into one.
48  * 
49  * 4     11/19/98 8:03a Dave
50  * Full support for D3-style reliable sockets. Revamped packet lag/loss
51  * system, made it receiver side and at the lowest possible level.
52  * 
53  * 3     11/05/98 5:55p Dave
54  * Big pass at reducing #includes
55  * 
56  * 2     10/07/98 10:53a Dave
57  * Initial checkin.
58  * 
59  * 1     10/07/98 10:50a Dave
60  * 
61  * 36    9/17/98 3:08p Dave
62  * PXO to non-pxo game warning popup. Player icon stuff in create and join
63  * game screens. Upped server count refresh time in PXO to 35 secs (from
64  * 20).
65  * 
66  * 35    9/15/98 7:24p Dave
67  * Minor UI changes. Localized bunch of new text.
68  * 
69  * 34    9/14/98 3:40p Allender
70  * better error checking for invalid number of waves for player wings in a
71  * multiplayer game.  Better popup message in FreeSpace side.
72  * 
73  * 33    9/11/98 5:53p Dave
74  * Final revisions to kick system changes.
75  * 
76  * 32    9/11/98 5:08p Dave
77  * More tweaks to kick notification system.
78  * 
79  * 31    9/11/98 4:14p Dave
80  * Fixed file checksumming of < file_size. Put in more verbose kicking and
81  * PXO stats store reporting.
82  * 
83  * 30    8/07/98 10:15a Allender
84  * changed the way the endgame sequencing timer works so that timer wrap
85  * doesn't hurt.  Also use the obj_set_flags for the COULD_BE_PLAYER flag
86  * 
87  * 29    7/24/98 9:27a Dave
88  * Tidied up endgame sequencing by removing several old flags and
89  * standardizing _all_ endgame stuff with a single function call.
90  * 
91  * 28    7/13/98 5:34p Lawrance
92  * index a localized string in multi_endgame.cpp
93  * 
94  * 27    7/13/98 5:19p Dave
95  * 
96  * 26    6/30/98 4:53p Allender
97  * fixed endgame problems where standalone wasn't properly dropping
98  * everyone out of a game.  Be sure that timestamp for endgame processing
99  * gets reset
100  * 
101  * 25    6/13/98 9:32p Mike
102  * Kill last character in file which caused "Find in Files" to report the
103  * file as "not a text file."
104  * 
105  * 24    6/13/98 6:01p Hoffoss
106  * Externalized all new (or forgot to be added) strings to all the code.
107  * 
108  * 23    6/13/98 3:18p Hoffoss
109  * NOX()ed out a bunch of strings that shouldn't be translated.
110  * 
111  * 22    5/24/98 8:15p Dave
112  * Tweaked pxo some more. 
113  * 
114  * 21    5/21/98 10:09a Dave
115  * Enable DNS checking for PXO and both trackers.
116  * Fixed problem with leaving the mission from the pause state. Fixed
117  * build errors in multimsgs.cpp
118  * 
119  * 20    5/20/98 9:01p Allender
120  * change RELEASE to NDEBUG.  Fix reentryancy problem in process_endgame
121  * for multiplayer
122  * 
123  * 19    5/17/98 11:54p Allender
124  * only clear flying controls when in mission
125  * 
126  * 18    5/17/98 11:34p Allender
127  * deal with resetting player controls better
128  * 
129  * 17    5/17/98 6:32p Dave
130  * Make sure clients/servers aren't kicked out of the debriefing when team
131  * captains leave a game. Fixed chatbox off-by-one error. Fixed image
132  * xfer/pilot info popup stuff.
133  * 
134  * 16    5/15/98 5:15p Dave
135  * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
136  * status for team vs. team. Put in asserts to check for invalid team vs.
137  * team situations.
138  * 
139  * 15    5/15/98 12:09a Dave
140  * New tracker api code. New game tracker code. Finished up first run of
141  * the PXO screen. Fixed a few game server list exceptions.
142  * 
143  * 14    5/14/98 12:40a Dave
144  * Still more additions to the PXO screen. Updated tracker code.
145  * 
146  * 13    5/09/98 7:16p Dave
147  * Put in CD checking. Put in standalone host password. Made pilot into
148  * popup scrollable.
149  * 
150  * 12    5/08/98 5:05p Dave
151  * Go to the join game screen when quitting multiplayer. Fixed mission
152  * text chat bugs. Put mission type symbols on the create game list.
153  * Started updating standalone gui controls.
154  * 
155  * 11    5/07/98 6:26p Dave
156  * Fix strange boundary conditions which arise when players die/respawn
157  * while the game is being ended. Spiff up the chatbox doskey thing a bit.
158  * 
159  * 10    5/07/98 3:29p Jim
160  * Make sure standalone doesn't display a popup when ending a game.
161  * 
162  * 9     5/05/98 5:02p Dave
163  * Fix end-of-campaign sequencing to work right. Make all individual
164  * missions of a campaign replayable.
165  * 
166  * 8     5/04/98 10:39p Dave
167  * Put in endgame sequencing.  Need to check campaign situations.
168  * Realigned ship info on team select screen.
169  * 
170  * 7     5/04/98 1:43p Dave
171  * Fixed up a standalone resetting problem. Fixed multiplayer stats
172  * collection for clients. Make sure all multiplayer ui screens have the
173  * correct palette at all times.
174  * 
175  * 6     5/03/98 7:04p Dave
176  * Make team vs. team work mores smoothly with standalone. Change how host
177  * interacts with standalone for picking missions. Put in a time limit for
178  * ingame join ship select. Fix ingame join ship select screen for Vasudan
179  * ship icons.
180  * 
181  * 5     4/30/98 5:12p Dave
182  * Fixed game polling code for joining clients. Reworked some file xfer
183  * stuff.
184  * 
185  * 4     4/30/98 12:13a Allender
186  * reset control info and afterburner when entering the quit game code.
187  * Prevents odd things from happening while the popup is up.
188  * 
189  * 3     4/28/98 5:10p Dave
190  * Fixed multi_quit_game() client side sequencing problem. Turn off
191  * afterburners when ending multiplayer mission. Begin integration of mt
192  * API from Kevin Bentley.
193  * 
194  * 2     4/23/98 1:28a Dave
195  * Seemingly nailed the current_primary_bank and current_secondary_bank -1
196  * problem. Made sure non-critical button presses are _never_ sent to the
197  * server.
198  * 
199  * 1     4/22/98 5:50p Dave
200  *  
201  * 
202  * $NoKeywords: $
203  */
204
205 #include "multi.h"
206 #include "popup.h"
207 #include "object.h"
208 #include "freespace.h"
209 #include "gamesequence.h"
210 #include "chatbox.h"
211 #include "popupdead.h"
212 #include "multi_endgame.h"
213 #include "multimsgs.h"
214 #include "multiui.h"
215 #include "multiutil.h"
216 #include "multi_pmsg.h"
217 #include "multi_fstracker.h"
218
219
220 // ----------------------------------------------------------------------------------------------------------
221 // Put all functions/data related to leaving a netgame, handling players leaving, handling the server leaving,
222 // and notifying the user of all of these actions, here.
223 //
224
225
226 // ----------------------------------------------------------------------------------------------------------
227 // MULTI ENDGAME DEFINES/VARS
228 //
229
230
231 // set when the server/client has ended the game on some notification or error and is waiting for clients to leave
232 #define MULTI_ENDGAME_SERVER_WAIT                               5.0f
233 int Multi_endgame_server_waiting = 0;
234 float Multi_endgame_server_wait_stamp = -1.0f;
235 int Multi_endgame_client_waiting = 0;
236
237 // error/notification codes (taken from parameters to multi_quit_game(...)
238 int Multi_endgame_notify_code;
239 int Multi_endgame_error_code;
240 int Multi_endgame_wsa_error;
241
242 // for reentrancy problems on standalone
243 int Multi_endgame_processing;
244
245 // ----------------------------------------------------------------------------------------------------------
246 // MULTI ENDGAME FORWARD DECLARATIONS
247 //
248
249 // called when a given netgame is about to end completely
250 void multi_endgame_cleanup();
251
252 // throw up a popup with the given notification code and optional winsock code
253 void multi_endgame_popup(int notify_code,int error_code,int wsa_error = -1);
254
255 // called when server is waiting for clients to disconnect
256 int multi_endgame_server_ok_to_leave();
257
258 // check to see if we need to be warping out (strange transition possibilities)
259 void multi_endgame_check_for_warpout();
260
261
262 // ----------------------------------------------------------------------------------------------------------
263 // MULTI ENDGAME FUNCTIONS
264 //
265
266 // initialize the endgame processor (call when joining/starting a new netgame)
267 void multi_endgame_init()
268 {
269         // set this so that the server/client knows he hasn't tried to end the game
270         Multi_endgame_server_waiting = 0;       
271         Multi_endgame_client_waiting = 0;
272
273         // reset the timestamp used when server is waiting for all other clients to leave.
274         Multi_endgame_server_wait_stamp = -1.0f;
275
276         // initialiaze all endgame notify and error codes
277         Multi_endgame_notify_code = -1;
278         Multi_endgame_error_code = -1;
279         Multi_endgame_wsa_error = -1;
280
281         // for reentrancy problems in to endgame_process
282         Multi_endgame_processing = 0;
283 }
284
285 // process all endgame related events
286 void multi_endgame_process()
287 {
288         if ( Multi_endgame_processing )
289                 return;
290
291         Multi_endgame_processing = 1;
292
293         // check to see if we need to be warping out (strange transition possibilities)
294         multi_endgame_check_for_warpout();
295         
296         // if we're the server of the game
297         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
298                 // if we're not waiting for clients to leave, do nothing
299                 if(!Multi_endgame_server_waiting){
300                         Multi_endgame_processing = 0;
301                         return;
302                 }
303
304                 // if a popup is already active, do nothing             
305                 if(popup_active()){
306                         Multi_endgame_processing = 0;
307                         return;
308                 }
309
310                 // otherwise popup until things are hunky-dory
311                 if(!multi_endgame_server_ok_to_leave()){
312                         if(Game_mode & GM_STANDALONE_SERVER){
313                                 while(!multi_endgame_server_ok_to_leave()){
314                                         // run networking, etc.
315                                         game_set_frametime(-1);
316                                         game_do_state_common(gameseq_get_state());
317                                 }
318                         } else {
319                                 popup_till_condition( multi_endgame_server_ok_to_leave , XSTR("&Cancel",645), XSTR("Waiting for clients to disconnect",646));           
320                         }
321                 }
322
323                 // mark myself as not waiting and get the hell out              
324                 multi_endgame_cleanup();        
325         } else {
326                 // if we're not waiting to leave the game, do nothing
327                 if(!Multi_endgame_client_waiting){
328                         Multi_endgame_processing = 0;
329                         return;
330                 }
331
332                 // otherwise, check to see if there is a popup active
333                 if(popup_active()){
334                         Multi_endgame_processing = 0;
335                         return;
336                 }
337
338                 // if not, then we are good to leave            
339                 multi_endgame_cleanup();
340         }
341
342         Multi_endgame_processing = 0;
343 }
344
345 // if the game has been flagged as ended (ie, its going to be reset)
346 int multi_endgame_ending()
347 {
348         return (Multi_endgame_client_waiting || Multi_endgame_server_waiting);
349 }
350
351 // reentrancy check
352 int Multi_quit_game = 0;
353 // general quit function, with optional notification, error, and winsock error codes
354 int multi_quit_game(int prompt, int notify_code, int err_code, int wsa_error)
355 {
356         int ret_val,quit_already;
357
358         // check for reentrancy
359         if(Multi_quit_game){
360                 return 0;
361         }
362
363         // if we're not connected or have not net-player
364         if((Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_CONNECTED)){
365                 return 1;
366         }
367
368         // reentrancy
369         Multi_quit_game = 1;
370
371         quit_already = 0;
372
373         // reset my control info so that I don't continually do whacky stuff.  This is ugly
374         //player_control_reset_ci( &Player->ci );
375         if ( Game_mode & GM_IN_MISSION ) {
376                 memset(&Player->ci, 0, sizeof(Player->ci) );
377                 Player->ci.afterburner_stop = 1;
378                 physics_read_flying_controls( &Player_obj->orient, &Player_obj->phys_info, &(Player->ci), flFrametime);
379         }
380
381         // CASE 1 - response to a user request
382         // if there is no associated notification or error code, don't override the prompt argument
383         if((err_code == -1) && (notify_code == -1)){
384                 // if we're the server and we're already waiting for clients to leave, don't do anything
385                 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && Multi_endgame_server_waiting){
386                         Multi_quit_game = 0;
387                         return 0;
388                 }
389
390                 // if we're the client and we're already waiting to leave, don't do anythin
391                 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER) && Multi_endgame_client_waiting){
392                         Multi_quit_game = 0;
393                         return 0;
394                 }
395
396                 // see if we should be prompting the host for confirmation
397                 if((prompt==PROMPT_HOST || prompt==PROMPT_ALL) && (Net_player->flags & NETINFO_FLAG_GAME_HOST)){
398                         int p_flags;
399
400                         p_flags = PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG;
401                         if ( Game_mode & GM_IN_MISSION )
402                                 p_flags |= PF_RUN_STATE;
403
404                         ret_val = popup(p_flags,2,POPUP_CANCEL,POPUP_OK,XSTR("Warning - quitting will end the game for all players!",647));
405
406                         // check for host cancel
407                         if((ret_val == 0) || (ret_val == -1)){
408                                 Multi_quit_game = 0;
409                                 return 0;
410                         }
411
412                         // set this so that under certain circumstances, we don't call the popup below us as well
413                         quit_already = 1;
414                 }
415
416                 // see if we should be prompting the client for confirmation
417                 if((prompt==PROMPT_CLIENT || prompt==PROMPT_ALL) && !quit_already){
418                         ret_val = popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG,2,POPUP_NO,POPUP_YES,XSTR("Are you sure you want to quit?",648));
419
420                         // check for host cancel
421                         if((ret_val == 0) || (ret_val == -1)){
422                                 Multi_quit_game = 0;
423                                 return 0;
424                         }
425                 }
426
427                 // if i'm the server of the game, tell all clients that i'm leaving, then wait
428                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
429                         send_netgame_end_error_packet(MULTI_END_NOTIFY_SERVER_LEFT,MULTI_END_ERROR_NONE);
430
431                         // set the waiting flag and the waiting timestamp
432                         Multi_endgame_server_waiting = 1;
433                         Multi_endgame_server_wait_stamp = MULTI_ENDGAME_SERVER_WAIT;
434                 }
435                 // if i'm the client, quit now
436                 else {
437                         multi_endgame_cleanup();
438                 }
439         }
440         // CASE 2 - response to an error code or packet from the server
441         // this is the case where we're being forced to quit the game because of some error or other notification
442         else {                          
443                 // if i'm the server, send a packet to the clients telling them that I'm leaving and why
444                 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !Multi_endgame_server_waiting){
445                         // if we're in the debrief state, mark down that the server has left the game
446                         if(((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) && !(Game_mode & GM_STANDALONE_SERVER)){
447                                 multi_debrief_server_left();
448
449                                 // add a message to the chatbox
450                                 multi_display_chat_msg(XSTR("<Team captains have left>",649),0,0);                              
451                                 
452                                 // set ourselves to be "not quitting"
453                                 Multi_quit_game = 0;
454
455                                 // tell the users, the game has ended
456                                 send_netgame_end_error_packet(notify_code,err_code);                            
457                                 return 0;
458                         }
459
460                         send_netgame_end_error_packet(notify_code,err_code);                    
461
462                         // store the globals 
463                         Multi_endgame_notify_code = notify_code;
464                         Multi_endgame_error_code = err_code;
465                         Multi_endgame_wsa_error = wsa_error;
466
467                         // by setting this, multi_endgame_process() will know to check and see if it is ok for us to leave
468                         Multi_endgame_server_waiting = 1;                               
469                         Multi_endgame_server_wait_stamp = MULTI_ENDGAME_SERVER_WAIT;
470                 }
471                 // if i'm the client, set the error codes and leave the game now
472                 else if(!Multi_endgame_client_waiting){
473                         // if we're in the debrief state, mark down that the server has left the game
474                         if((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
475                                 multi_debrief_server_left();
476
477                                 // add a message to the chatbox
478                                 multi_display_chat_msg(XSTR("<The server has ended the game>",650),0,0);
479
480                                 // shut our reliable socket to the server down
481                                 psnet_rel_close_socket(&Net_player->reliable_socket);
482                                 Net_player->reliable_socket = INVALID_SOCKET;
483
484                                 // remove our do-notworking flag
485                                 Net_player->flags &= ~(NETINFO_FLAG_DO_NETWORKING);
486                                 
487                                 Multi_quit_game = 0;
488                                 return 0;
489                         }
490
491                         Multi_endgame_notify_code = notify_code;
492                         Multi_endgame_error_code = err_code;
493                         Multi_endgame_wsa_error = wsa_error;
494
495                         // by setting this, multi_endgame_process() will know to check and see if it is ok for us to leave
496                         Multi_endgame_client_waiting = 1;                       
497                 }
498         }               
499
500         // unset the reentrancy flag
501         Multi_quit_game = 0;
502
503         return 1;
504 }
505
506
507 // ----------------------------------------------------------------------------------------------------------
508 // MULTI ENDGAME FORWARD DEFINITIONS
509 //
510
511 // called when a given netgame is about to end completely
512 void multi_endgame_cleanup()
513 {
514         int idx;
515
516         send_leave_game_packet();                       
517
518         // flush all outgoing io, force all packets through
519         multi_io_send_buffered_packets();
520                 
521         // mark myself as disconnected
522         if(!(Game_mode & GM_STANDALONE_SERVER)){
523                 Net_player->flags &= ~(NETINFO_FLAG_CONNECTED|NETINFO_FLAG_DO_NETWORKING);
524         }
525                 
526         // this is a semi-hack so that if we're the master and we're quitting, we don't get an assert
527         if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Player_obj != NULL)){
528                 Player_obj->flags &= ~(OF_PLAYER_SHIP);
529                 obj_set_flags( Player_obj, Player_obj->flags | OF_COULD_BE_PLAYER );
530         }
531         
532         // shut my socket down (will also let the server know i've received any notifications/error from him)
533         // psnet_rel_close_socket( &(Net_player->reliable_socket) );
534
535         // 11/18/98 - DB, changed the above to kill all sockets. Its the safest thing to do
536         for(idx=0; idx<MAX_PLAYERS; idx++){
537                 psnet_rel_close_socket(&Net_players[idx].reliable_socket);
538                 Net_players[idx].reliable_socket = INVALID_SOCKET;
539         }
540
541         // set the game quitting flag in our local netgame info - this will _insure_ that even if we miss a packet or
542         // there is some sequencing error, the next time through the multi_do_frame() loop, the game will be ended
543         // Netgame.flags |= (NG_FLAG_QUITTING | NG_FLAG_ENDED);
544
545         // close all open SPX/TCP reliable sockets
546         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
547                 // do it for all players, since we're leaving anyway.
548                 for(idx=0;idx<MAX_PLAYERS;idx++){
549                         // 6/25/98 -- MWA delete all players from the game
550
551                         if ( &Net_players[idx] != Net_player ) {
552                                 delete_player( idx );
553                         }                       
554                 }
555         }       
556
557         // if we're currently in the pause state, pop back into gameplay first
558         if(gameseq_get_state() == GS_STATE_MULTI_PAUSED){
559                 gameseq_pop_state();
560         }
561
562         if(Game_mode & GM_STANDALONE_SERVER){
563                 // multi_standalone_quit_game();                
564                 multi_standalone_reset_all();
565         } else {                
566                 Player->flags |= PLAYER_FLAGS_IS_MULTI;         
567
568                 // if we're in Parallax Online mode, log back in there  
569                 if (Multi_options_g.pxo == 1) {
570                         SDL_assert(Multi_options_g.protocol == NET_TCP);
571                         gameseq_post_event(GS_EVENT_PXO);
572                 } else {
573                         gameseq_post_event(GS_EVENT_MULTI_JOIN_GAME);
574                 }
575
576                 // if we have an error code, bring up the discon popup                                          
577                 if(((Multi_endgame_notify_code != -1) || (Multi_endgame_error_code != -1)) && !(Game_mode & GM_STANDALONE_SERVER)){
578                         multi_endgame_popup(Multi_endgame_notify_code,Multi_endgame_error_code,Multi_endgame_wsa_error);                        
579                 }               
580         }       
581
582         if (MULTI_IS_TRACKER_GAME) {
583                 multi_fs_tracker_logout();
584         }
585
586         /*
587         extern CFILE *obj_stream;
588         if(obj_stream != NULL){
589                 cfclose(obj_stream);
590                 obj_stream = NULL;
591         }
592         */      
593
594         // unload the multiplayer common interface palette
595         multi_common_unload_palette();
596         
597         // reinitialize endgame stuff
598         // multi_endgame_init();
599 }
600
601 // throw up a popup with the given notification code and optional winsock code
602 void multi_endgame_popup(int notify_code,int error_code,int wsa_error)
603 {
604         char err_msg[255];
605         int flags = PF_USE_AFFIRMATIVE_ICON;    
606
607         // if there is a popup already active, just kill it
608         if(popup_active()){
609                 // if there is already a popup active, kill it
610                 popup_kill_any_active();
611
612                 Int3();
613         } else {
614                 // if there is a winsock error code, stick it on the end of the text
615                 if(wsa_error != -1){            
616                         SDL_snprintf(err_msg, SDL_arraysize(err_msg), NOX("WSAERROR : %d\n\n"), wsa_error);
617                         flags |= PF_TITLE_RED;
618                 } else {
619                         SDL_strlcpy(err_msg, "", SDL_arraysize(err_msg));
620                 }
621
622                 // setup the error message string
623                 if(notify_code != MULTI_END_NOTIFY_NONE){
624                         switch(notify_code){
625                         case MULTI_END_NOTIFY_KICKED :
626                                 SDL_strlcat(err_msg,XSTR("You have been kicked",651),SDL_arraysize(err_msg));
627                                 break;
628                         case MULTI_END_NOTIFY_SERVER_LEFT:
629                                 SDL_strlcat(err_msg,XSTR("The server has left the game",652),SDL_arraysize(err_msg));
630                                 break;
631                         case MULTI_END_NOTIFY_FILE_REJECTED:
632                                 SDL_strlcat(err_msg,XSTR("Your mission file has been rejected by the server",653),SDL_arraysize(err_msg));
633                                 break;
634                         case MULTI_END_NOTIFY_EARLY_END:
635                                 SDL_strlcat(err_msg,XSTR("The game has ended while you were ingame joining",654),SDL_arraysize(err_msg));
636                                 break;
637                         case MULTI_END_NOTIFY_INGAME_TIMEOUT:
638                                 SDL_strlcat(err_msg,XSTR("You have waited too long to select a ship",655),SDL_arraysize(err_msg));
639                                 break;
640                         case MULTI_END_NOTIFY_KICKED_BAD_XFER:
641                                 SDL_strlcat(err_msg,XSTR("You were kicked because mission file xfer failed",998),SDL_arraysize(err_msg));
642                                 break;
643                         case MULTI_END_NOTIFY_KICKED_CANT_XFER:
644                                 SDL_strlcat(err_msg,XSTR("You were kicked because you do not have the builtin mission",999),SDL_arraysize(err_msg));
645                                 SDL_strlcat(err_msg, NOX(" "), SDL_arraysize(err_msg));
646                                 SDL_strlcat(err_msg, Game_current_mission_filename, SDL_arraysize(err_msg));
647                                 break;
648                         case MULTI_END_NOTIFY_KICKED_INGAME_ENDED:
649                                 SDL_strlcat(err_msg,XSTR("You were kicked because you were ingame joining a game that has ended",1000),SDL_arraysize(err_msg));
650                                 break;
651                         default : 
652                                 Int3();
653                         }               
654                 } else {        
655                         switch(error_code){
656                         case MULTI_END_ERROR_CONTACT_LOST :
657                                 SDL_strlcat(err_msg,XSTR("Contact with server has been lost",656),SDL_arraysize(err_msg));
658                                 break;
659                         case MULTI_END_ERROR_CONNECT_FAIL :
660                                 SDL_strlcat(err_msg,XSTR("Failed to connect to server on reliable socket",657),SDL_arraysize(err_msg));
661                                 break;
662                         case MULTI_END_ERROR_LOAD_FAIL :
663                                 SDL_strlcat(err_msg,XSTR("Failed to load mission file properly",658),SDL_arraysize(err_msg));
664                                 break;                                          
665                         case MULTI_END_ERROR_INGAME_SHIP :
666                                 SDL_strlcat(err_msg,XSTR("Unable to create ingame join player ship",659),SDL_arraysize(err_msg));
667                                 break;
668                         case MULTI_END_ERROR_INGAME_BOGUS :
669                                 SDL_strlcat(err_msg,XSTR("Recevied bogus packet data while ingame joining",660),SDL_arraysize(err_msg));
670                                 break;
671                         case MULTI_END_ERROR_STRANS_FAIL :
672                                 SDL_strlcat(err_msg,XSTR("Server transfer failed (obsolete)",661),SDL_arraysize(err_msg));
673                                 break;
674                         case MULTI_END_ERROR_SHIP_ASSIGN:
675                                 SDL_strlcat(err_msg,XSTR("Server encountered errors trying to assign players to ships",662),SDL_arraysize(err_msg));
676                                 break;
677                         case MULTI_END_ERROR_HOST_LEFT:
678                                 SDL_strlcat(err_msg,XSTR("Host has left the game, aborting...",663),SDL_arraysize(err_msg));
679                                 break;                  
680                         case MULTI_END_ERROR_XFER_FAIL:
681                                 SDL_strlcat(err_msg,XSTR("There was an error receiving the mission file!",665),SDL_arraysize(err_msg));
682                                 break;
683                         case MULTI_END_ERROR_WAVE_COUNT:
684                                 SDL_strlcat(err_msg,XSTR("The player wings Alpha, Beta, Gamma, and Zeta must have only 1 wave.  One of these wings currently has more than 1 wave.", 987),SDL_arraysize(err_msg));
685                                 break;
686                         case MULTI_END_ERROR_TEAM0_EMPTY:
687                                 SDL_strlcat(err_msg,XSTR("All players from team 1 have left the game", 1466),SDL_arraysize(err_msg));
688                                 break;
689                         case MULTI_END_ERROR_TEAM1_EMPTY:
690                                 SDL_strlcat(err_msg,XSTR("All players from team 2 have left the game", 1467),SDL_arraysize(err_msg));
691                                 break;
692                         case MULTI_END_ERROR_CAPTAIN_LEFT:
693                                 SDL_strlcat(err_msg,XSTR("Team captain(s) have left the game, aborting...",664),SDL_arraysize(err_msg));
694                                 break;
695                         default :
696                                 Int3();
697                         }               
698                 }
699
700                 // show the popup
701                 popup(flags,1,POPUP_OK,err_msg);        
702         }
703 }
704
705 // called when server is waiting for clients to disconnect
706 int multi_endgame_server_ok_to_leave()
707 {
708         int idx;
709         
710         // check to see if our client disconnect timestamp has elapsed
711         if ( Multi_endgame_server_wait_stamp > 0.0f ) {
712                 Multi_endgame_server_wait_stamp -= flFrametime;
713                 if ( Multi_endgame_server_wait_stamp <= 0.0f ) {
714                         return 1;
715                 }
716         }
717                 
718         // check to see if all clients have disconnected
719         for(idx=0;idx<MAX_PLAYERS;idx++){
720                 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
721                         return 0;
722                 }
723         }
724
725         // all conditions passed
726         return 1;
727 }
728
729 // check to see if we need to be warping out (strange transition possibilities)
730 void multi_endgame_check_for_warpout()
731 {
732         int need_to_warpout = 0;
733
734         // if we're not in the process of warping out - do nothing
735         if(!(Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
736                 return;
737         }
738
739         // determine if sufficient warping-out conditions exist
740         if((Game_mode & GM_IN_MISSION) &&                                                                               // if i'm still in the mission
741                 ((Netgame.game_state == NETGAME_STATE_ENDGAME)  ||                              // if the netgame ended
742                  (Netgame.game_state == NETGAME_STATE_DEBRIEF))                                 // if the netgame is now in the debriefing state
743           ) {
744                 need_to_warpout = 1;
745         }
746
747         // if we need to be warping out but are stuck in a dead popup, cancel it
748         if(need_to_warpout && (popupdead_is_active() || (Net_player->flags & NETINFO_FLAG_RESPAWNING) || (Net_player->flags & NETINFO_FLAG_OBSERVER)) ){                
749                 // flush all active pushed state
750                 multi_handle_state_special();
751
752                 // begin the warpout process            
753                 gameseq_post_event(GS_EVENT_DEBRIEF);
754
755                 // if text input mode is active, clear it
756                 multi_msg_text_flush();
757         }       
758 }