]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_pause.cpp
handle for connections and ping updates
[taylor/freespace2.git] / src / network / multi_pause.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_pause.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * $Log$
16  * Revision 1.4  2002/06/09 04:41:23  relnev
17  * added copyright header
18  *
19  * Revision 1.3  2002/05/26 20:22:48  theoddone33
20  * Most of network/ works
21  *
22  * Revision 1.2  2002/05/07 03:16:47  theoddone33
23  * The Great Newline Fix
24  *
25  * Revision 1.1.1.1  2002/05/03 03:28:10  root
26  * Initial import.
27  *  
28  * 
29  * 7     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  * 6     8/04/99 3:33p Jefff
34  * fixed hi-res text
35  * 
36  * 5     7/29/99 10:47p Dave
37  * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
38  * 
39  * 4     11/05/98 5:55p Dave
40  * Big pass at reducing #includes
41  * 
42  * 3     10/13/98 9:29a Dave
43  * Started neatening up freespace.h. Many variables renamed and
44  * reorganized. Added AlphaColors.[h,cpp]
45  * 
46  * 2     10/07/98 10:53a Dave
47  * Initial checkin.
48  * 
49  * 1     10/07/98 10:50a Dave
50  * 
51  * 15    9/17/98 3:08p Dave
52  * PXO to non-pxo game warning popup. Player icon stuff in create and join
53  * game screens. Upped server count refresh time in PXO to 35 secs (from
54  * 20).
55  * 
56  * 14    7/24/98 9:27a Dave
57  * Tidied up endgame sequencing by removing several old flags and
58  * standardizing _all_ endgame stuff with a single function call.
59  * 
60  * 13    6/13/98 3:19p Hoffoss
61  * NOX()ed out a bunch of strings that shouldn't be translated.
62  * 
63  * 12    5/20/98 2:24a Dave
64  * Fixed server side voice muting. Tweaked multi debrief/endgame
65  * sequencing a bit. Much friendlier for stats tossing/accepting now.
66  * 
67  * 11    5/19/98 8:35p Dave
68  * Revamp PXO channel listing system. Send campaign goals/events to
69  * clients for evaluation. Made lock button pressable on all screens. 
70  * 
71  * 10    5/10/98 7:06p Dave
72  * Fix endgame sequencing ESC key. Changed how host options warning popups
73  * are done. Fixed pause/message scrollback/options screen problems in mp.
74  * Make sure observer HUD doesn't try to lock weapons.
75  * 
76  * 9     5/08/98 5:05p Dave
77  * Go to the join game screen when quitting multiplayer. Fixed mission
78  * text chat bugs. Put mission type symbols on the create game list.
79  * Started updating standalone gui controls.
80  * 
81  * 8     5/07/98 6:26p Dave
82  * Fix strange boundary conditions which arise when players die/respawn
83  * while the game is being ended. Spiff up the chatbox doskey thing a bit.
84  * 
85  * 7     5/04/98 10:39p Dave
86  * Put in endgame sequencing.  Need to check campaign situations.
87  * Realigned ship info on team select screen.
88  * 
89  * 6     5/03/98 7:04p Dave
90  * Make team vs. team work mores smoothly with standalone. Change how host
91  * interacts with standalone for picking missions. Put in a time limit for
92  * ingame join ship select. Fix ingame join ship select screen for Vasudan
93  * ship icons.
94  * 
95  * 5     4/27/98 6:02p Dave
96  * Modify how missile scoring works. Fixed a team select ui bug. Speed up
97  * multi_lag system. Put in new main hall.
98  * 
99  * 4     4/22/98 5:53p Dave
100  * Large reworking of endgame sequencing. Updated multi host options
101  * screen for new artwork. Put in checks for host or team captains leaving
102  * midgame.
103  * 
104  * 3     4/16/98 1:55p Dave
105  * Removed unneeded SDL_assert when processing chat packets. Fixed standalone
106  * sequencing bugs. Laid groundwork for join screen server status
107  * icons/text.
108  * 
109  * 2     4/14/98 5:06p Dave
110  * Don't load or send invalid pilot pics. Fixed chatbox graphic errors.
111  * Made chatbox display team icons in a team vs. team game. Fixed up pause
112  * and endgame sequencing issues.
113  * 
114  * 1     4/14/98 12:18p Dave
115  *
116  * 
117  * $NoKeywords: $
118  */
119
120 #ifndef PLAT_UNIX
121 #include <windows.h>
122 #endif
123 #include "chatbox.h"
124 #include "ui.h"
125 #include "freespace.h"
126 #include "key.h"
127 #include "popup.h"
128 #include "gamesequence.h"
129 #include "stand_server.h"
130 #include "gamesnd.h"
131 #include "multiutil.h"
132 #include "multiui.h"
133 #include "multimsgs.h"
134 #include "multi_pause.h"
135 #include "multi_endgame.h"
136 #include "multi_pmsg.h"
137 #include "multi.h"
138 #include "alphacolors.h"
139 #include "timer.h"
140
141 // ----------------------------------------------------------------------------------
142 // PAUSE DEFINES/VARS
143 //
144
145 // state of the game (paused or not) on _my_ machine. Obviously this is important for the server
146 // call multi_pause_reset() to reinitialize
147 int Multi_pause_status = 0;
148
149 // who paused the game
150 net_player *Multi_pause_pauser = NULL;
151
152 // timestamp for eating keypresses for a while after 
153 float Multi_pause_eat = -1.0f;
154
155 // pause ui screen stuff
156 #define MULTI_PAUSED_NUM_BUTTONS                3
157
158 // button defs
159 #define MP_SCROLL_UP                                    0
160 #define MP_SCROLL_DOWN                          1
161 #define MP_EXIT_MISSION                         2
162
163 // where to place the pauser's callsign
164 int Mp_callsign_coords[GR_NUM_RESOLUTIONS][2] = {
165         { // GR_640
166                 110, 132
167         },
168         { // GR_1024
169                 171, 218
170         }
171 };
172
173 ui_button_info Multi_paused_buttons[GR_NUM_RESOLUTIONS][MULTI_PAUSED_NUM_BUTTONS] = {
174         { // GR_640
175                 ui_button_info("PB00",          519,    212,    -1,     -1,     0),
176                 ui_button_info("PB01",          519,    252,    -1,     -1,     1),
177                 ui_button_info("PB02",          488,    321,    -1,     -1,     2),
178         },
179         { // GR_1024
180                 ui_button_info("2_PB00",                831,    339,    -1,     -1,     0),
181                 ui_button_info("2_PB01",                831,    403,    -1,     -1,     1),
182                 ui_button_info("2_PB02",                781,    514,    -1,     -1,     2),
183         }
184 };
185
186 // text
187 #define MULTI_PAUSED_NUM_TEXT                           3
188 UI_XSTR Multi_paused_text[GR_NUM_RESOLUTIONS][MULTI_PAUSED_NUM_BUTTONS] = {
189         { // GR_640
190                 { "Exit",                               1059,   493,    297,    UI_XSTR_COLOR_PINK,     -1, &Multi_paused_buttons[0][MP_EXIT_MISSION].button },
191                 { "Mission",                    1063,   482,    306,    UI_XSTR_COLOR_PINK,     -1, &Multi_paused_buttons[0][MP_EXIT_MISSION].button },
192                 { "Mission Paused",     1440,   107,    356,    UI_XSTR_COLOR_PINK,     -1, NULL },
193         },
194         { // GR_1024
195                 { "Exit",                               1059,   787,    478,    UI_XSTR_COLOR_PINK,     -1, &Multi_paused_buttons[1][MP_EXIT_MISSION].button },
196                 { "Mission",                    1063,   778,    490,    UI_XSTR_COLOR_PINK,     -1, &Multi_paused_buttons[1][MP_EXIT_MISSION].button },
197                 { "Mission Paused",     1440,   171,    567,    UI_XSTR_COLOR_PINK,     -1, NULL },
198         }
199 };
200
201
202 UI_WINDOW *Multi_paused_window;
203 int Multi_paused_screen_id;                                                                                                     // backed up screen data
204
205 void multi_pause_check_buttons();
206 void multi_pause_button_pressed(int n);
207
208 // (server) evaluate a pause request from the given player (should call for himself as well)
209 void multi_pause_server_eval_request(net_player *pl, int pause);
210
211 // if this player can unpause
212 int multi_pause_can_unpause(net_player *p);
213
214 // render the callsign of the guy who paused
215 void multi_pause_render_callsign();
216
217
218 // ----------------------------------------------------------------------------------
219 // PAUSE FUNCTIONS
220 //
221
222 // re-initializes the pause system. call before entering the mission to reset
223 void multi_pause_reset()
224 {
225         // set the pause status to 0
226         Multi_pause_status = 0;
227
228         // null out the pause pointer
229         Multi_pause_pauser = NULL;
230
231         // eat keys timestamp
232         Multi_pause_eat = -1.0f;
233 }
234
235 // (client) call when receiving a packet indicating we should pause
236 void multi_pause_pause()
237 {
238         int idx;
239
240         // if we're already paused, don't do anything
241         if(Multi_pause_status){
242                 return;
243         }
244
245         // sanity check
246         SDL_assert(!Multi_pause_status);
247
248         // mark the game as being paused
249         Multi_pause_status = 1;
250
251         // if we're not already in the pause state
252         if(gameseq_get_state() != GS_STATE_MULTI_PAUSED){
253                 // jump into the paused state 
254                 gameseq_post_event(GS_EVENT_MULTI_PAUSE);
255
256                 // mark the netgame state
257                 Netgame.game_state = NETGAME_STATE_PAUSED;                                      
258         }
259
260         // if we're the server of the game, send a packet which will pause the clients in the game now
261         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
262                 for(idx=0;idx<MAX_PLAYERS;idx++){
263                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
264                                 send_client_update_packet(&Net_players[idx]);
265                         }
266                 }
267         }
268 }
269
270 // (client) call when receiving a packet indicating we should unpause
271 void multi_pause_unpause()
272 {
273         int idx;
274
275         // if we're already unpaused, don't do anything
276         if(!Multi_pause_status){
277                 return;
278         }
279
280         // sanity check
281         SDL_assert(Multi_pause_status);
282
283         // mark the game as being unpaused
284         Multi_pause_status = 0;
285
286         // pop us out of any necessary states (including the pause state !!)
287         multi_handle_state_special();
288         
289         // mark the netgame state
290         Netgame.game_state = NETGAME_STATE_IN_MISSION;                  
291
292         // if we're the server of the game, send a packet which will unpause the clients in the game now
293         // if we're the server of the game, send a packet which will pause the clients in the game now
294         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
295                 for(idx=0;idx<MAX_PLAYERS;idx++){
296                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
297                                 send_client_update_packet(&Net_players[idx]);
298                         }
299                 }
300         }
301 }
302
303 // send a request to pause or unpause a game (all players should use this function)
304 void multi_pause_request(int pause)
305 {
306         // if i'm the server, run it through the eval function right now
307         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
308                 multi_pause_server_eval_request(Net_player,pause);
309         } 
310         // otherwise, send a reliable request packet to the server
311         else {
312                 send_multi_pause_packet(pause);         
313         }
314 }
315
316 // (server) evaluate a pause request from the given player (should call for himself as well)
317 void multi_pause_server_eval_request(net_player *pl, int pause)
318 {
319         int cur_state;
320         
321         // if this is a pause request and we're already in the pause state, do nothing
322         if(pause && Multi_pause_status){
323                 return;
324         }
325
326         // if this is an unpause request and we're already unpaused, do nothing
327         if(!pause && !Multi_pause_status){
328                 return;
329         }
330
331         // get the current state (don't allow pausing from certain states
332         cur_state = gameseq_get_state();
333         if((cur_state == GS_STATE_DEBRIEF) || (cur_state == GS_STATE_MULTI_MISSION_SYNC) || (cur_state == GS_STATE_BRIEFING) ||
334                 (cur_state == GS_STATE_STANDALONE_POSTGAME) || (cur_state == GS_STATE_MULTI_STD_WAIT) || (cur_state == GS_STATE_WEAPON_SELECT) ||
335                 (cur_state == GS_STATE_TEAM_SELECT) || (cur_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
336                 return;
337         }
338         
339         // if this is a pause request
340         if(pause){
341                 // record who the pauser is
342                 Multi_pause_pauser = pl;
343
344                 // pause the game
345                 multi_pause_pause();            
346         }
347         // if this is an unpause request
348         else {
349                 // if this guy is allowed to unpause the game, do so
350                 if(multi_pause_can_unpause(pl)){
351                         // unmark the "pauser"
352                         Multi_pause_pauser = NULL;
353
354                         // unpause the game
355                         multi_pause_unpause();                  
356                 }
357         }       
358 }
359
360 // if this player can unpause
361 int multi_pause_can_unpause(net_player *p)
362 {                               
363         if(!(p->flags & NETINFO_FLAG_GAME_HOST) && (p != Multi_pause_pauser)){
364                 return 0;
365         }
366
367         return 1;
368 }
369
370 // if we still want to eat keys 
371 int multi_pause_eat_keys()
372 {
373         // if the eat timestamp is negative, don't eat keys
374         if(Multi_pause_eat < 0.0f){
375                 return 0;
376         } 
377
378         // if less than 1 second has passed, continue eating keys
379         if((f2fl(timer_get_fixed_seconds()) - Multi_pause_eat) < 1.0f){
380                 nprintf(("Network","PAUSE EATING KEYS\n"));
381
382                 control_config_clear_used_status();
383                 key_flush();
384
385                 return 1;
386         }
387
388         // otherwise, disable the timestamp
389         Multi_pause_eat = -1.0f;
390
391         return 0;
392 }
393
394
395 // ----------------------------------------------------------------------------------
396 // PAUSE UI FUNCTIONS
397 //
398
399 void multi_pause_init(UI_WINDOW *Ui_window)
400 {
401         int i;  
402
403         // standalone shouldn't be doing any freespace interface stuff
404         if (Game_mode & GM_STANDALONE_SERVER){
405                 std_debug_set_standalone_state_string("Multi paused do");
406         } 
407         // everyone else should be doing UI stuff
408         else {
409                 // switch off the text messaging system if it is active
410                 multi_msg_text_flush();                         
411
412                 // assign the local reference to the ui window
413                 Multi_paused_window = Ui_window;
414                 
415                 for (i=0; i<MULTI_PAUSED_NUM_BUTTONS; i++) {
416                         // create the button
417                         Multi_paused_buttons[gr_screen.res][i].button.create(Multi_paused_window, "", Multi_paused_buttons[gr_screen.res][i].x, Multi_paused_buttons[gr_screen.res][i].y, 1, 1, 0, 1);
418
419                         // set the highlight action
420                         Multi_paused_buttons[gr_screen.res][i].button.set_highlight_action(common_play_highlight_sound);
421
422                         // set the ani
423                         Multi_paused_buttons[gr_screen.res][i].button.set_bmaps(Multi_paused_buttons[gr_screen.res][i].filename);
424
425                         // set the hotspot
426                         Multi_paused_buttons[gr_screen.res][i].button.link_hotspot(Multi_paused_buttons[gr_screen.res][i].hotspot);
427                 }       
428
429                 // add text
430                 for(i=0; i<MULTI_PAUSED_NUM_TEXT; i++){
431                         Multi_paused_window->add_XSTR(&Multi_paused_text[gr_screen.res][i]);
432                 }
433                 
434                 // close any instances of a chatbox
435                 chatbox_close();
436
437                 // intiialize our custom chatbox
438                 chatbox_create(CHATBOX_FLAG_MULTI_PAUSED);              
439         }
440
441         // reset timestamps
442         multi_reset_timestamps();
443 }
444
445 void multi_pause_do()
446 {
447         int k;
448         
449         // make sure we don't enter this state unless we're in the mission itself       
450         Netgame.game_state = NETGAME_STATE_PAUSED;
451
452         // server of the game should periodically be sending pause packets for good measure
453         if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {               
454         }
455
456         if (!(Game_mode & GM_STANDALONE_SERVER)) {
457                 // if we're inside of popup code right now, don't process the window
458                 if(!popup_active()){
459                         // process chatbox and window stuff
460                         k = chatbox_process();
461                         k = Multi_paused_window->process(k);    
462                 
463                         switch (k) {
464                         case SDLK_ESCAPE:
465                         case SDLK_PAUSE:
466                                 multi_pause_request(0);
467                                 break;
468                         }
469                 }
470
471                 // check for any button presses
472                 multi_pause_check_buttons();
473
474                 // render the callsign of the guy who paused
475                 multi_pause_render_callsign();
476                                 
477                 // render the chatbox
478                 chatbox_render();
479                 
480                 // draw tooltips
481                 // Multi_paused_window->draw_tooltip();
482                 Multi_paused_window->draw();
483
484                 // display the voice status indicator
485                 multi_common_voice_display_status();
486         }
487         // standalone pretty much does nothing here
488         else {
489                 SDL_Delay(1);
490         }
491 }
492
493 void multi_pause_close()
494 {
495         // set the standalonest
496         if (Game_mode & GM_STANDALONE_SERVER) {
497                 std_debug_set_standalone_state_string("Game play");
498         } else {
499                 // free the screen up
500                 gr_free_screen(Multi_paused_screen_id);
501         }
502
503         // eat keys timestamp
504         Multi_pause_eat = f2fl(timer_get_fixed_seconds());
505         
506         // reset timestamps
507         multi_reset_timestamps();
508
509         // clear out control config and keypress info
510         control_config_clear_used_status();
511         key_flush();
512 }
513
514 void multi_pause_check_buttons()
515 {
516         int idx;
517
518         // process any pause buttons which may have been pressed
519         for (idx=0; idx<MULTI_PAUSED_NUM_BUTTONS; idx++){
520                 if (Multi_paused_buttons[gr_screen.res][idx].button.pressed()){
521                         multi_pause_button_pressed(idx);
522                 }
523         }
524 }
525
526 void multi_pause_button_pressed(int n)
527 {
528         switch (n) {
529         // the scroll up button
530         case MP_SCROLL_UP :
531                 chatbox_scroll_up();
532                 break;
533
534         // the scroll down button
535         case MP_SCROLL_DOWN :
536                 chatbox_scroll_down();
537                 break;
538
539         // the exit mission
540         case MP_EXIT_MISSION :
541                 multi_quit_game(PROMPT_ALL);
542                 break;
543         }
544 }
545
546 // render the callsign of the guy who paused
547 void multi_pause_render_callsign()
548 {
549         char pause_str[100];
550
551         // write out the callsign of the player who paused the game     
552         if((Multi_pause_pauser != NULL) && (Multi_pause_pauser->player != NULL)){
553                 memset(pause_str,0,100);
554                 SDL_strlcpy(pause_str, Multi_pause_pauser->player->callsign, SDL_arraysize(pause_str));
555
556                 // blit it
557                 gr_set_color_fast(&Color_bright);
558                 gr_string(Mp_callsign_coords[gr_screen.res][0], Mp_callsign_coords[gr_screen.res][1], pause_str);
559         }       
560 }