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