2 * $Logfile: /Freespace2/code/Popup/PopupDead.cpp $
7 * C module for the death popup
10 * Revision 1.2 2002/05/07 03:16:51 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:10 root
17 * 14 9/14/99 4:35a Dave
18 * Argh. Added all kinds of code to handle potential crashes in debriefing
21 * 13 9/14/99 12:51a Jefff
22 * sm3-09 no skip hack.
24 * 12 9/11/99 1:09a Mikek
25 * Removed semi-bogus Int3() in popupdead code which seemed to get tripped
28 * 11 9/10/99 6:49p Jefff
29 * changed skip popup to normal type popup
31 * 10 9/09/99 7:17p Jefff
33 * 9 9/07/99 4:44p Jefff
34 * fixed double counting of mission failures
36 * 8 9/07/99 1:54p Jefff
37 * skip mission cleanup
39 * 7 9/06/99 9:46p Jefff
40 * skip mission support
42 * 6 8/11/99 5:47p Jefff
43 * fixed button bitmap loading
45 * 5 7/24/99 1:54p Dave
46 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
49 * 4 6/01/99 3:52p Dave
50 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
51 * dead popup, pxo find player popup, pxo private room popup.
53 * 3 10/13/98 9:29a Dave
54 * Started neatening up freespace.h. Many variables renamed and
55 * reorganized. Added AlphaColors.[h,cpp]
57 * 2 10/07/98 10:53a Dave
60 * 1 10/07/98 10:51a Dave
62 * 11 6/09/98 10:31a Hoffoss
63 * Created index numbers for all xstr() references. Any new xstr() stuff
64 * added from here on out should be added to the end if the list. The
65 * current list count can be found in FreeSpace.cpp (search for
68 * 10 5/17/98 1:43a Dave
69 * Eradicated chatbox problems. Remove speed match for observers. Put in
70 * help screens for PXO. Fix messaging and end mission privelges. Fixed
71 * team select screen bugs. Misc UI fixes.
73 * 9 5/01/98 4:24p Lawrance
74 * Change "Main Hall" to "Flight Deck"
76 * 8 4/22/98 4:59p Allender
77 * new multiplayer dead popup. big changes to the comm menu system for
78 * team vs. team. Start of debriefing stuff for team vs. team Make form
79 * on my wing work with individual ships who have high priority orders
81 * 7 3/12/98 4:02p Lawrance
82 * Cleanup how pause works, fix couple pause-related bugs.
84 * 6 3/05/98 12:35p Lawrance
85 * Fix bug where two options could be highlighted at once.
87 * 5 2/22/98 4:30p John
88 * More string externalization classification
90 * 4 2/22/98 2:48p John
91 * More String Externalization Classification
93 * 3 2/22/98 12:19p John
94 * Externalized some strings
96 * 2 2/10/98 11:20p Lawrance
97 * Implement separate dead popup system
99 * 1 2/10/98 6:02p Lawrance
105 #define POPUPDEAD_NUM_CHOICES 3 // normal
106 #define POPUPDEAD_NUM_CHOICES_RA 4 // red alert
107 #define POPUPDEAD_NUM_CHOICES_SKIP 3 // skip mission menu
109 #define POPUPDEAD_NUM_CHOICES_MAX 4
114 #include "freespace.h"
116 #include "keycontrol.h"
119 #include "multiutil.h"
120 #include "popupdead.h"
121 #include "alphacolors.h"
122 #include "gamesequence.h"
125 UI_WINDOW Popupdead_window;
126 UI_BUTTON Popupdead_buttons[POPUPDEAD_NUM_CHOICES_MAX]; // actual lit buttons
127 UI_BUTTON Popupdead_button_regions[POPUPDEAD_NUM_CHOICES_MAX]; // fake buttons used for mouse detection over text
129 int Popupdead_region_coords[GR_NUM_RESOLUTIONS][POPUPDEAD_NUM_CHOICES_MAX][4] =
132 {464, 389, 497, 403}, // upper right pixel of text, lower right pixel of button (for tiny popup)
133 {464, 413, 497, 427},
134 {464, 435, 497, 446},
135 {464, 457, 497, 466},
138 {745, 627, 809, 664},
139 {745, 663, 809, 700}, // upper right pixel of text, lower right pixel of button (for tiny popup)
140 {745, 699, 809, 736},
141 {745, 735, 809, 772},
145 int Popupdead_button_coords[GR_NUM_RESOLUTIONS][POPUPDEAD_NUM_CHOICES_MAX][2] =
148 {478, 387}, // upper left pixel (tiny popup)
154 {760, 620}, // upper left pixel (tiny popup)
161 char *Popupdead_background_filename[GR_NUM_RESOLUTIONS] = {
162 "PopDeath", // GR_640
163 "2_PopDeath" // GR-1024
166 int Popupdead_background_coords[GR_NUM_RESOLUTIONS][2] =
176 char *Popupdead_button_filenames[GR_NUM_RESOLUTIONS][POPUPDEAD_NUM_CHOICES_MAX] =
179 "PopD_00", // first choice
180 "PopD_01", // second choice
181 "PopD_02", // third choice
182 "PopD_03", // fourth choice
185 "2_PopD_00", // first choice
186 "2_PopD_01", // second choice
187 "2_PopD_02", // third choice
188 "2_PopD_03", // fourth choice
192 int Popupdead_skip_message_y[GR_NUM_RESOLUTIONS] = {
198 static char *Popupdead_button_text[POPUPDEAD_NUM_CHOICES_MAX];
200 // multiplayer specifics to help with return values since they can vary
201 #define POPUPDEAD_OBS_ONLY 1
202 #define POPUPDEAD_OBS_QUIT 2
203 #define POPUPDEAD_RESPAWN_ONLY 3
204 #define POPUPDEAD_RESPAWN_QUIT 4
206 int Popupdead_default_choice; // What the default choice is (ie activated when Enter pressed)
207 int Popupdead_active = 0; // A dead popup is active
208 int Popupdead_choice; // Index for choice picked (-1 if none picked)
209 int Popupdead_num_choices; // number of buttons
210 int Popupdead_multi_type; // what kind of popup is active for muliplayer
211 int Popupdead_skip_active = 0; // The skip-misison popup is active
212 int Popupdead_skip_already_shown = 0;
214 // Initialize the dead popup data
215 void popupdead_start()
220 if ( Popupdead_active ) {
225 // increment number of deaths
226 Player->failures_this_session++;
229 // create base window
230 Popupdead_window.create(Popupdead_background_coords[gr_screen.res][0], Popupdead_background_coords[gr_screen.res][1], 1, 1, 0);
231 Popupdead_window.set_foreground_bmap(Popupdead_background_filename[gr_screen.res]);
233 Popupdead_num_choices = 0;
234 Popupdead_multi_type = -1;
236 if ( Game_mode & GM_NORMAL ) {
237 // also do a campaign check here?
238 if (0) { //((Player->show_skip_popup) && (!Popupdead_skip_already_shown) && (Game_mode & GM_CAMPAIGN_MODE) && (Game_mode & GM_NORMAL) && (Player->failures_this_session >= PLAYER_MISSION_FAILURE_LIMIT)) {
239 // init the special preliminary death popup that gives the skip option
240 Popupdead_button_text[0] = XSTR( "Do Not Skip This Mission", 1473);
241 Popupdead_button_text[1] = XSTR( "Advance To The Next Mission", 1474);
242 Popupdead_button_text[2] = XSTR( "Don't Show Me This Again", 1475);
243 Popupdead_num_choices = POPUPDEAD_NUM_CHOICES_SKIP;
244 Popupdead_skip_active = 1;
245 } else if(The_mission.red_alert) {
246 // We can't staticly declare these because they are externalized
247 Popupdead_button_text[0] = XSTR( "Quick Start Mission", 105);
248 Popupdead_button_text[1] = XSTR( "Return To Flight Deck", 106);
249 Popupdead_button_text[2] = XSTR( "Return To Briefing", 107);
250 Popupdead_button_text[3] = XSTR( "Replay previous mission", 1432);
251 Popupdead_num_choices = POPUPDEAD_NUM_CHOICES_RA;
253 Popupdead_button_text[0] = XSTR( "Quick Start Mission", 105);
254 Popupdead_button_text[1] = XSTR( "Return To Flight Deck", 106);
255 Popupdead_button_text[2] = XSTR( "Return To Briefing", 107);
256 Popupdead_num_choices = POPUPDEAD_NUM_CHOICES;
259 // in multiplayer, we have different choices depending on respawn mode, etc.
261 // if the player has run out of respawns and must either quit and become an observer
262 if(Net_player->flags & NETINFO_FLAG_LIMBO){
264 // the master should not be able to quit the game
265 if( ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (multi_num_players() > 1)) || (Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN) ) {
266 Popupdead_button_text[0] = XSTR( "Observer Mode", 108);
267 Popupdead_num_choices = 1;
268 Popupdead_multi_type = POPUPDEAD_OBS_ONLY;
270 Popupdead_button_text[0] = XSTR( "Observer Mode", 108);
271 Popupdead_button_text[1] = XSTR( "Return To Flight Deck", 106);
272 Popupdead_num_choices = 2;
273 Popupdead_multi_type = POPUPDEAD_OBS_QUIT;
276 // the master of the game should not be allowed to quit
277 if ( ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (multi_num_players() > 1)) || (Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN) ) {
278 Popupdead_button_text[0] = XSTR( "Respawn", 109);
279 Popupdead_num_choices = 1;
280 Popupdead_multi_type = POPUPDEAD_RESPAWN_ONLY;
282 Popupdead_button_text[0] = XSTR( "Respawn", 109);
283 Popupdead_button_text[1] = XSTR( "Return To Flight Deck", 106);
284 Popupdead_num_choices = 2;
285 Popupdead_multi_type = POPUPDEAD_RESPAWN_QUIT;
291 for (i=0; i < Popupdead_num_choices; i++) {
292 b = &Popupdead_buttons[i];
293 b->create(&Popupdead_window, "", Popupdead_button_coords[gr_screen.res][i][0], Popupdead_button_coords[gr_screen.res][i][1], 30, 20, 0, 1);
294 b->set_bmaps(Popupdead_button_filenames[gr_screen.res][i], 3, 0);
295 b->set_highlight_action(common_play_highlight_sound);
297 // create invisible buttons to detect mouse presses... can't use mask since button region is dynamically sized
299 gr_get_string_size(&w, &h, Popupdead_button_text[i]);
300 lx = Popupdead_region_coords[gr_screen.res][i][0] - w;
301 b = &Popupdead_button_regions[i];
302 b->create(&Popupdead_window, "", lx, Popupdead_region_coords[gr_screen.res][i][1], Popupdead_region_coords[gr_screen.res][i][2]-lx, Popupdead_region_coords[gr_screen.res][i][3]-Popupdead_region_coords[gr_screen.res][i][1], 0, 1);
306 Popupdead_default_choice = 0;
307 Popupdead_choice = -1;
308 Popupdead_active = 1;
311 // maybe play a sound when key up/down is pressed to switch default choice
312 void popupdead_play_default_change_sound()
317 // only play if mouse not currently highlighting a choice
318 for ( i = 0; i < Popupdead_num_choices; i++ ) {
319 br = &Popupdead_button_regions[i];
320 b = &Popupdead_buttons[i];
321 if ( br->button_down() ) {
326 if ( br->button_hilighted() && !b->button_down() ) {
331 if ( b->button_hilighted() ) {
337 gamesnd_play_iface(SND_USER_SELECT);
341 // do any key processing here
342 // exit: -1 => nothing was done
343 // >=0 => a choice was selected
344 int popupdead_process_keys(int k)
355 return Popupdead_default_choice; // select the current default choice
359 if (Popupdead_skip_active) {
360 return 0; // 0 mimics a "do not skip"
362 return 1; // do nothing here for now - 1 mimics a "return to flight deck"
369 popupdead_play_default_change_sound();
370 Popupdead_default_choice++;
371 if ( Popupdead_default_choice >= Popupdead_num_choices ) {
372 Popupdead_default_choice=0;
378 case KEY_SHIFTED+KEY_TAB:
379 popupdead_play_default_change_sound();
380 Popupdead_default_choice--;
381 if ( Popupdead_default_choice < 0 ) {
382 Popupdead_default_choice=Popupdead_num_choices-1;
387 game_process_pause_key();
394 // read the dead key set
395 masked_k = k & ~KEY_CTRLED; // take out CTRL modifier only
396 process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set);
397 button_info_do(&Player->bi); // call functions based on status of button_info bit vectors
403 // see if any popup buttons have been pressed
404 // exit: -1 => no buttons pressed
405 // >=0 => button index that was pressed
406 int popupdead_check_buttons()
411 for ( i = 0; i < Popupdead_num_choices; i++ ) {
412 b = &Popupdead_button_regions[i];
413 if ( b->pressed() ) {
417 b = &Popupdead_buttons[i];
418 if ( b->pressed() ) {
426 // See if any of the button should change appearance based on mouse position
427 void popupdead_force_draw_buttons()
429 int i,mouse_is_highlighting=0;
432 for ( i = 0; i < Popupdead_num_choices; i++ ) {
433 br = &Popupdead_button_regions[i];
434 b = &Popupdead_buttons[i];
435 if ( br->button_down() ) {
437 mouse_is_highlighting=1;
441 if ( (b->button_hilighted()) || (br->button_hilighted() && !b->button_down()) ) {
442 Popupdead_default_choice=i;
443 mouse_is_highlighting=1;
448 // Only if mouse is not highlighting an option, let the default choice be drawn highlighted
449 if ( (!mouse_is_highlighting) && (Popupdead_num_choices>1) ) {
450 for ( i = 0; i < Popupdead_num_choices; i++ ) {
451 b = &Popupdead_buttons[i];
452 // highlight the default choice
453 if ( i == Popupdead_default_choice ) {
460 // Draw the button text nicely formatted in the popup
461 void popupdead_draw_button_text()
465 gr_set_color_fast(&Color_bright_blue);
467 for ( i=0; i < Popupdead_num_choices; i++ ) {
468 gr_get_string_size(&w, &h, Popupdead_button_text[i]);
469 sx = Popupdead_region_coords[gr_screen.res][i][0]-w;
470 sy = Popupdead_region_coords[gr_screen.res][i][1]+4;
471 gr_string(sx, sy, Popupdead_button_text[i]);
475 // reinits the death popup
476 // used for skip popup to death popup transition
477 void popupdead_restart() {
478 Popupdead_skip_already_shown = 1;
479 Popupdead_skip_active = 0;
480 Popupdead_active = 0;
481 Player->failures_this_session--; // hacky correction for a double count when calling popupdead_start() twice
485 // do the "skip mission" version of the death popup
486 int popupdead_skip_do_frame()
488 int k = Popupdead_window.process();
491 int choice = popupdead_process_keys(k);
493 choice = popupdead_check_buttons();
496 // take appropriate options
499 // try this mission again, so proceed to normal death popup
500 gamesnd_play_iface(SND_USER_SELECT);
505 mission_campaign_skip_to_next();
507 gamesnd_play_iface(SND_USER_SELECT);
510 // dont show this again
511 Player->show_skip_popup = 0;
513 gamesnd_play_iface(SND_USER_SELECT);
519 Popupdead_window.draw();
520 popupdead_force_draw_buttons();
521 popupdead_draw_button_text();
523 // render skip mission message
524 gr_set_color_fast(&Color_bright_white);
525 gr_string(0x8000, Popupdead_skip_message_y[gr_screen.res], XSTR("You have failed this mission five times.", 1470));
526 gr_string(0x8000, Popupdead_skip_message_y[gr_screen.res] + gr_get_font_height(), XSTR("If you like, you may advance to the next mission.", 1471));
532 // Called once per frame to run the dead popup
533 int popupdead_do_frame(float frametime)
538 if (Popupdead_skip_active) {
539 // do the skip mission popup, and thats all
540 if (popupdead_skip_do_frame() == 1) {
541 return 2; // fake the "go to briefing" choice
543 return -1; // fake no choice
547 if ( !Popupdead_active ) {
551 // dont let dude skip 3-09. hack.
552 if(Game_mode & GM_CAMPAIGN_MODE){
553 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
554 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
555 Popupdead_skip_already_shown = 1;
560 // maybe show skip mission popup
561 if ((!Popupdead_skip_already_shown) && (Player->show_skip_popup) && (Game_mode & GM_NORMAL) && (Game_mode & GM_CAMPAIGN_MODE) && (Player->failures_this_session >= PLAYER_MISSION_FAILURE_LIMIT)) {
562 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
563 XSTR("Advance To The Next Mission", 1474),
564 XSTR("Don't Show Me This Again", 1475),
565 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
566 switch (popup_choice) {
568 // stay on this mission, so proceed to normal death popup
569 // in other words, do nothing.
573 Popupdead_active = 0;
574 mission_campaign_skip_to_next();
575 gameseq_post_event(GS_EVENT_START_GAME);
578 // dont show this again
579 Player->show_skip_popup = 0;
583 Popupdead_skip_already_shown = 1;
587 k = Popupdead_window.process();
589 choice = popupdead_process_keys(k);
591 // do something different for single/multiplayer
592 if ( Game_mode & GM_NORMAL ) {
593 Popupdead_choice=choice;
595 Assert( Popupdead_multi_type != -1 );
596 switch ( Popupdead_multi_type ) {
598 case POPUPDEAD_OBS_ONLY:
599 case POPUPDEAD_OBS_QUIT:
600 Popupdead_choice = POPUPDEAD_DO_OBSERVER;
601 if ( (Popupdead_multi_type == POPUPDEAD_OBS_QUIT) && (choice == 1) )
602 Popupdead_choice = POPUPDEAD_DO_MAIN_HALL;
605 case POPUPDEAD_RESPAWN_ONLY:
606 case POPUPDEAD_RESPAWN_QUIT:
607 Popupdead_choice = POPUPDEAD_DO_RESPAWN;
608 if ( (Popupdead_multi_type == POPUPDEAD_RESPAWN_QUIT) && (choice == 1) )
609 Popupdead_choice = POPUPDEAD_DO_MAIN_HALL;
619 choice = popupdead_check_buttons();
621 // do something different for single/multiplayer
622 if ( Game_mode & GM_NORMAL ) {
623 Popupdead_choice=choice;
625 Assert( Popupdead_multi_type != -1 );
626 switch ( Popupdead_multi_type ) {
628 case POPUPDEAD_OBS_ONLY:
629 case POPUPDEAD_OBS_QUIT:
630 Popupdead_choice = POPUPDEAD_DO_OBSERVER;
631 if ( (Popupdead_multi_type == POPUPDEAD_OBS_QUIT) && (choice == 1) )
632 Popupdead_choice = POPUPDEAD_DO_MAIN_HALL;
635 case POPUPDEAD_RESPAWN_ONLY:
636 case POPUPDEAD_RESPAWN_QUIT:
637 Popupdead_choice = POPUPDEAD_DO_RESPAWN;
638 if ( (Popupdead_multi_type == POPUPDEAD_RESPAWN_QUIT) && (choice == 1) )
639 Popupdead_choice = POPUPDEAD_DO_MAIN_HALL;
649 Popupdead_window.draw();
650 popupdead_force_draw_buttons();
651 popupdead_draw_button_text();
653 return Popupdead_choice;
656 // Close down the dead popup
657 void popupdead_close()
659 if ( !Popupdead_active ) {
663 gamesnd_play_iface(SND_POPUP_DISAPPEAR);
664 Popupdead_window.destroy();
667 Popupdead_active = 0;
668 Popupdead_skip_active = 0;
669 Popupdead_skip_already_shown = 0;
672 // Is there a dead popup active?
673 int popupdead_is_active()
675 return Popupdead_active;