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