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