]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_pause.cpp
clean up Windows #include's and use winsock2
[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 #include "chatbox.h"
121 #include "ui.h"
122 #include "freespace.h"
123 #include "key.h"
124 #include "popup.h"
125 #include "gamesequence.h"
126 #include "stand_server.h"
127 #include "gamesnd.h"
128 #include "multiutil.h"
129 #include "multiui.h"
130 #include "multimsgs.h"
131 #include "multi_pause.h"
132 #include "multi_endgame.h"
133 #include "multi_pmsg.h"
134 #include "multi.h"
135 #include "alphacolors.h"
136 #include "timer.h"
137
138 // ----------------------------------------------------------------------------------
139 // PAUSE DEFINES/VARS
140 //
141
142 // state of the game (paused or not) on _my_ machine. Obviously this is important for the server
143 // call multi_pause_reset() to reinitialize
144 int Multi_pause_status = 0;
145
146 // who paused the game
147 net_player *Multi_pause_pauser = NULL;
148
149 // timestamp for eating keypresses for a while after 
150 float Multi_pause_eat = -1.0f;
151
152 // pause ui screen stuff
153 #define MULTI_PAUSED_NUM_BUTTONS                3
154
155 // button defs
156 #define MP_SCROLL_UP                                    0
157 #define MP_SCROLL_DOWN                          1
158 #define MP_EXIT_MISSION                         2
159
160 // where to place the pauser's callsign
161 int Mp_callsign_coords[GR_NUM_RESOLUTIONS][2] = {
162         { // GR_640
163                 110, 132
164         },
165         { // GR_1024
166                 171, 218
167         }
168 };
169
170 ui_button_info Multi_paused_buttons[GR_NUM_RESOLUTIONS][MULTI_PAUSED_NUM_BUTTONS] = {
171         { // GR_640
172                 ui_button_info("PB00",          519,    212,    -1,     -1,     0),
173                 ui_button_info("PB01",          519,    252,    -1,     -1,     1),
174                 ui_button_info("PB02",          488,    321,    -1,     -1,     2),
175         },
176         { // GR_1024
177                 ui_button_info("2_PB00",                831,    339,    -1,     -1,     0),
178                 ui_button_info("2_PB01",                831,    403,    -1,     -1,     1),
179                 ui_button_info("2_PB02",                781,    514,    -1,     -1,     2),
180         }
181 };
182
183 // text
184 #define MULTI_PAUSED_NUM_TEXT                           3
185 UI_XSTR Multi_paused_text[GR_NUM_RESOLUTIONS][MULTI_PAUSED_NUM_BUTTONS] = {
186         { // GR_640
187                 { "Exit",                               1059,   493,    297,    UI_XSTR_COLOR_PINK,     -1, &Multi_paused_buttons[0][MP_EXIT_MISSION].button },
188                 { "Mission",                    1063,   482,    306,    UI_XSTR_COLOR_PINK,     -1, &Multi_paused_buttons[0][MP_EXIT_MISSION].button },
189                 { "Mission Paused",     1440,   107,    356,    UI_XSTR_COLOR_PINK,     -1, NULL },
190         },
191         { // GR_1024
192                 { "Exit",                               1059,   787,    478,    UI_XSTR_COLOR_PINK,     -1, &Multi_paused_buttons[1][MP_EXIT_MISSION].button },
193                 { "Mission",                    1063,   778,    490,    UI_XSTR_COLOR_PINK,     -1, &Multi_paused_buttons[1][MP_EXIT_MISSION].button },
194                 { "Mission Paused",     1440,   171,    567,    UI_XSTR_COLOR_PINK,     -1, NULL },
195         }
196 };
197
198
199 UI_WINDOW *Multi_paused_window;
200 int Multi_paused_screen_id;                                                                                                     // backed up screen data
201
202 void multi_pause_check_buttons();
203 void multi_pause_button_pressed(int n);
204
205 // (server) evaluate a pause request from the given player (should call for himself as well)
206 void multi_pause_server_eval_request(net_player *pl, int pause);
207
208 // if this player can unpause
209 int multi_pause_can_unpause(net_player *p);
210
211 // render the callsign of the guy who paused
212 void multi_pause_render_callsign();
213
214
215 // ----------------------------------------------------------------------------------
216 // PAUSE FUNCTIONS
217 //
218
219 // re-initializes the pause system. call before entering the mission to reset
220 void multi_pause_reset()
221 {
222         // set the pause status to 0
223         Multi_pause_status = 0;
224
225         // null out the pause pointer
226         Multi_pause_pauser = NULL;
227
228         // eat keys timestamp
229         Multi_pause_eat = -1.0f;
230 }
231
232 // (client) call when receiving a packet indicating we should pause
233 void multi_pause_pause()
234 {
235         int idx;
236
237         // if we're already paused, don't do anything
238         if(Multi_pause_status){
239                 return;
240         }
241
242         // sanity check
243         SDL_assert(!Multi_pause_status);
244
245         // mark the game as being paused
246         Multi_pause_status = 1;
247
248         // if we're not already in the pause state
249         if(gameseq_get_state() != GS_STATE_MULTI_PAUSED){
250                 // jump into the paused state 
251                 gameseq_post_event(GS_EVENT_MULTI_PAUSE);
252
253                 // mark the netgame state
254                 Netgame.game_state = NETGAME_STATE_PAUSED;                                      
255         }
256
257         // if we're the server of the game, send a packet which will pause the clients in the game now
258         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
259                 for(idx=0;idx<MAX_PLAYERS;idx++){
260                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
261                                 send_client_update_packet(&Net_players[idx]);
262                         }
263                 }
264         }
265 }
266
267 // (client) call when receiving a packet indicating we should unpause
268 void multi_pause_unpause()
269 {
270         int idx;
271
272         // if we're already unpaused, don't do anything
273         if(!Multi_pause_status){
274                 return;
275         }
276
277         // sanity check
278         SDL_assert(Multi_pause_status);
279
280         // mark the game as being unpaused
281         Multi_pause_status = 0;
282
283         // pop us out of any necessary states (including the pause state !!)
284         multi_handle_state_special();
285         
286         // mark the netgame state
287         Netgame.game_state = NETGAME_STATE_IN_MISSION;                  
288
289         // if we're the server of the game, send a packet which will unpause the clients in the game now
290         // if we're the server of the game, send a packet which will pause the clients in the game now
291         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
292                 for(idx=0;idx<MAX_PLAYERS;idx++){
293                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
294                                 send_client_update_packet(&Net_players[idx]);
295                         }
296                 }
297         }
298 }
299
300 // send a request to pause or unpause a game (all players should use this function)
301 void multi_pause_request(int pause)
302 {
303         // if i'm the server, run it through the eval function right now
304         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
305                 multi_pause_server_eval_request(Net_player,pause);
306         } 
307         // otherwise, send a reliable request packet to the server
308         else {
309                 send_multi_pause_packet(pause);         
310         }
311 }
312
313 // (server) evaluate a pause request from the given player (should call for himself as well)
314 void multi_pause_server_eval_request(net_player *pl, int pause)
315 {
316         int cur_state;
317         
318         // if this is a pause request and we're already in the pause state, do nothing
319         if(pause && Multi_pause_status){
320                 return;
321         }
322
323         // if this is an unpause request and we're already unpaused, do nothing
324         if(!pause && !Multi_pause_status){
325                 return;
326         }
327
328         // get the current state (don't allow pausing from certain states
329         cur_state = gameseq_get_state();
330         if((cur_state == GS_STATE_DEBRIEF) || (cur_state == GS_STATE_MULTI_MISSION_SYNC) || (cur_state == GS_STATE_BRIEFING) ||
331                 (cur_state == GS_STATE_STANDALONE_POSTGAME) || (cur_state == GS_STATE_MULTI_STD_WAIT) || (cur_state == GS_STATE_WEAPON_SELECT) ||
332                 (cur_state == GS_STATE_TEAM_SELECT) || (cur_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
333                 return;
334         }
335         
336         // if this is a pause request
337         if(pause){
338                 // record who the pauser is
339                 Multi_pause_pauser = pl;
340
341                 // pause the game
342                 multi_pause_pause();            
343         }
344         // if this is an unpause request
345         else {
346                 // if this guy is allowed to unpause the game, do so
347                 if(multi_pause_can_unpause(pl)){
348                         // unmark the "pauser"
349                         Multi_pause_pauser = NULL;
350
351                         // unpause the game
352                         multi_pause_unpause();                  
353                 }
354         }       
355 }
356
357 // if this player can unpause
358 int multi_pause_can_unpause(net_player *p)
359 {                               
360         if(!(p->flags & NETINFO_FLAG_GAME_HOST) && (p != Multi_pause_pauser)){
361                 return 0;
362         }
363
364         return 1;
365 }
366
367 // if we still want to eat keys 
368 int multi_pause_eat_keys()
369 {
370         // if the eat timestamp is negative, don't eat keys
371         if(Multi_pause_eat < 0.0f){
372                 return 0;
373         } 
374
375         // if less than 1 second has passed, continue eating keys
376         if((f2fl(timer_get_fixed_seconds()) - Multi_pause_eat) < 1.0f){
377                 nprintf(("Network","PAUSE EATING KEYS\n"));
378
379                 control_config_clear_used_status();
380                 key_flush();
381
382                 return 1;
383         }
384
385         // otherwise, disable the timestamp
386         Multi_pause_eat = -1.0f;
387
388         return 0;
389 }
390
391
392 // ----------------------------------------------------------------------------------
393 // PAUSE UI FUNCTIONS
394 //
395
396 void multi_pause_init(UI_WINDOW *Ui_window)
397 {
398         int i;  
399
400         // standalone shouldn't be doing any freespace interface stuff
401         if (Game_mode & GM_STANDALONE_SERVER){
402                 std_debug_set_standalone_state_string("Multi paused do");
403         } 
404         // everyone else should be doing UI stuff
405         else {
406                 // switch off the text messaging system if it is active
407                 multi_msg_text_flush();                         
408
409                 // assign the local reference to the ui window
410                 Multi_paused_window = Ui_window;
411                 
412                 for (i=0; i<MULTI_PAUSED_NUM_BUTTONS; i++) {
413                         // create the button
414                         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);
415
416                         // set the highlight action
417                         Multi_paused_buttons[gr_screen.res][i].button.set_highlight_action(common_play_highlight_sound);
418
419                         // set the ani
420                         Multi_paused_buttons[gr_screen.res][i].button.set_bmaps(Multi_paused_buttons[gr_screen.res][i].filename);
421
422                         // set the hotspot
423                         Multi_paused_buttons[gr_screen.res][i].button.link_hotspot(Multi_paused_buttons[gr_screen.res][i].hotspot);
424                 }       
425
426                 // add text
427                 for(i=0; i<MULTI_PAUSED_NUM_TEXT; i++){
428                         Multi_paused_window->add_XSTR(&Multi_paused_text[gr_screen.res][i]);
429                 }
430                 
431                 // close any instances of a chatbox
432                 chatbox_close();
433
434                 // intiialize our custom chatbox
435                 chatbox_create(CHATBOX_FLAG_MULTI_PAUSED);              
436         }
437
438         // reset timestamps
439         multi_reset_timestamps();
440 }
441
442 void multi_pause_do()
443 {
444         int k;
445         
446         // make sure we don't enter this state unless we're in the mission itself       
447         Netgame.game_state = NETGAME_STATE_PAUSED;
448
449         // server of the game should periodically be sending pause packets for good measure
450         if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {               
451         }
452
453         if (!(Game_mode & GM_STANDALONE_SERVER)) {
454                 // if we're inside of popup code right now, don't process the window
455                 if(!popup_active()){
456                         // process chatbox and window stuff
457                         k = chatbox_process();
458                         k = Multi_paused_window->process(k);    
459                 
460                         switch (k) {
461                         case SDLK_ESCAPE:
462                         case SDLK_PAUSE:
463                                 multi_pause_request(0);
464                                 break;
465                         }
466                 }
467
468                 // check for any button presses
469                 multi_pause_check_buttons();
470
471                 // render the callsign of the guy who paused
472                 multi_pause_render_callsign();
473                                 
474                 // render the chatbox
475                 chatbox_render();
476                 
477                 // draw tooltips
478                 // Multi_paused_window->draw_tooltip();
479                 Multi_paused_window->draw();
480
481                 // display the voice status indicator
482                 multi_common_voice_display_status();
483         }
484         // standalone pretty much does nothing here
485         else {
486                 SDL_Delay(1);
487         }
488 }
489
490 void multi_pause_close()
491 {
492         // set the standalonest
493         if (Game_mode & GM_STANDALONE_SERVER) {
494                 std_debug_set_standalone_state_string("Game play");
495         } else {
496                 // free the screen up
497                 gr_free_screen(Multi_paused_screen_id);
498         }
499
500         // eat keys timestamp
501         Multi_pause_eat = f2fl(timer_get_fixed_seconds());
502         
503         // reset timestamps
504         multi_reset_timestamps();
505
506         // clear out control config and keypress info
507         control_config_clear_used_status();
508         key_flush();
509 }
510
511 void multi_pause_check_buttons()
512 {
513         int idx;
514
515         // process any pause buttons which may have been pressed
516         for (idx=0; idx<MULTI_PAUSED_NUM_BUTTONS; idx++){
517                 if (Multi_paused_buttons[gr_screen.res][idx].button.pressed()){
518                         multi_pause_button_pressed(idx);
519                 }
520         }
521 }
522
523 void multi_pause_button_pressed(int n)
524 {
525         switch (n) {
526         // the scroll up button
527         case MP_SCROLL_UP :
528                 chatbox_scroll_up();
529                 break;
530
531         // the scroll down button
532         case MP_SCROLL_DOWN :
533                 chatbox_scroll_down();
534                 break;
535
536         // the exit mission
537         case MP_EXIT_MISSION :
538                 multi_quit_game(PROMPT_ALL);
539                 break;
540         }
541 }
542
543 // render the callsign of the guy who paused
544 void multi_pause_render_callsign()
545 {
546         char pause_str[100];
547
548         // write out the callsign of the player who paused the game     
549         if((Multi_pause_pauser != NULL) && (Multi_pause_pauser->player != NULL)){
550                 memset(pause_str,0,100);
551                 SDL_strlcpy(pause_str, Multi_pause_pauser->player->callsign, SDL_arraysize(pause_str));
552
553                 // blit it
554                 gr_set_color_fast(&Color_bright);
555                 gr_string(Mp_callsign_coords[gr_screen.res][0], Mp_callsign_coords[gr_screen.res][1], pause_str);
556         }       
557 }