2 * $Logfile: /Freespace2/code/Popup/PopupDead.cpp $
7 * C module for the death popup
10 * Revision 1.1 2002/05/03 03:28:10 root
14 * 14 9/14/99 4:35a Dave
15 * Argh. Added all kinds of code to handle potential crashes in debriefing
18 * 13 9/14/99 12:51a Jefff
19 * sm3-09 no skip hack.
21 * 12 9/11/99 1:09a Mikek
22 * Removed semi-bogus Int3() in popupdead code which seemed to get tripped
25 * 11 9/10/99 6:49p Jefff
26 * changed skip popup to normal type popup
28 * 10 9/09/99 7:17p Jefff
30 * 9 9/07/99 4:44p Jefff
31 * fixed double counting of mission failures
33 * 8 9/07/99 1:54p Jefff
34 * skip mission cleanup
36 * 7 9/06/99 9:46p Jefff
37 * skip mission support
39 * 6 8/11/99 5:47p Jefff
40 * fixed button bitmap loading
42 * 5 7/24/99 1:54p Dave
43 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
46 * 4 6/01/99 3:52p Dave
47 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
48 * dead popup, pxo find player popup, pxo private room popup.
50 * 3 10/13/98 9:29a Dave
51 * Started neatening up freespace.h. Many variables renamed and
52 * reorganized. Added AlphaColors.[h,cpp]
54 * 2 10/07/98 10:53a Dave
57 * 1 10/07/98 10:51a Dave
59 * 11 6/09/98 10:31a Hoffoss
60 * Created index numbers for all xstr() references. Any new xstr() stuff
61 * added from here on out should be added to the end if the list. The
62 * current list count can be found in FreeSpace.cpp (search for
65 * 10 5/17/98 1:43a Dave
66 * Eradicated chatbox problems. Remove speed match for observers. Put in
67 * help screens for PXO. Fix messaging and end mission privelges. Fixed
68 * team select screen bugs. Misc UI fixes.
70 * 9 5/01/98 4:24p Lawrance
71 * Change "Main Hall" to "Flight Deck"
73 * 8 4/22/98 4:59p Allender
74 * new multiplayer dead popup. big changes to the comm menu system for
75 * team vs. team. Start of debriefing stuff for team vs. team Make form
76 * on my wing work with individual ships who have high priority orders
78 * 7 3/12/98 4:02p Lawrance
79 * Cleanup how pause works, fix couple pause-related bugs.
81 * 6 3/05/98 12:35p Lawrance
82 * Fix bug where two options could be highlighted at once.
84 * 5 2/22/98 4:30p John
85 * More string externalization classification
87 * 4 2/22/98 2:48p John
88 * More String Externalization Classification
90 * 3 2/22/98 12:19p John
91 * Externalized some strings
93 * 2 2/10/98 11:20p Lawrance
94 * Implement separate dead popup system
96 * 1 2/10/98 6:02p Lawrance
102 #define POPUPDEAD_NUM_CHOICES 3 // normal
103 #define POPUPDEAD_NUM_CHOICES_RA 4 // red alert
104 #define POPUPDEAD_NUM_CHOICES_SKIP 3 // skip mission menu
106 #define POPUPDEAD_NUM_CHOICES_MAX 4
111 #include "freespace.h"
113 #include "keycontrol.h"
116 #include "multiutil.h"
117 #include "popupdead.h"
118 #include "alphacolors.h"
119 #include "gamesequence.h"
122 UI_WINDOW Popupdead_window;
123 UI_BUTTON Popupdead_buttons[POPUPDEAD_NUM_CHOICES_MAX]; // actual lit buttons
124 UI_BUTTON Popupdead_button_regions[POPUPDEAD_NUM_CHOICES_MAX]; // fake buttons used for mouse detection over text
126 int Popupdead_region_coords[GR_NUM_RESOLUTIONS][POPUPDEAD_NUM_CHOICES_MAX][4] =
129 {464, 389, 497, 403}, // upper right pixel of text, lower right pixel of button (for tiny popup)
130 {464, 413, 497, 427},
131 {464, 435, 497, 446},
132 {464, 457, 497, 466},
135 {745, 627, 809, 664},
136 {745, 663, 809, 700}, // upper right pixel of text, lower right pixel of button (for tiny popup)
137 {745, 699, 809, 736},
138 {745, 735, 809, 772},
142 int Popupdead_button_coords[GR_NUM_RESOLUTIONS][POPUPDEAD_NUM_CHOICES_MAX][2] =
145 {478, 387}, // upper left pixel (tiny popup)
151 {760, 620}, // upper left pixel (tiny popup)
158 char *Popupdead_background_filename[GR_NUM_RESOLUTIONS] = {
159 "PopDeath", // GR_640
160 "2_PopDeath" // GR-1024
163 int Popupdead_background_coords[GR_NUM_RESOLUTIONS][2] =
173 char *Popupdead_button_filenames[GR_NUM_RESOLUTIONS][POPUPDEAD_NUM_CHOICES_MAX] =
176 "PopD_00", // first choice
177 "PopD_01", // second choice
178 "PopD_02", // third choice
179 "PopD_03", // fourth choice
182 "2_PopD_00", // first choice
183 "2_PopD_01", // second choice
184 "2_PopD_02", // third choice
185 "2_PopD_03", // fourth choice
189 int Popupdead_skip_message_y[GR_NUM_RESOLUTIONS] = {
195 static char *Popupdead_button_text[POPUPDEAD_NUM_CHOICES_MAX];
197 // multiplayer specifics to help with return values since they can vary
198 #define POPUPDEAD_OBS_ONLY 1
199 #define POPUPDEAD_OBS_QUIT 2
200 #define POPUPDEAD_RESPAWN_ONLY 3
201 #define POPUPDEAD_RESPAWN_QUIT 4
203 int Popupdead_default_choice; // What the default choice is (ie activated when Enter pressed)
204 int Popupdead_active = 0; // A dead popup is active
205 int Popupdead_choice; // Index for choice picked (-1 if none picked)
206 int Popupdead_num_choices; // number of buttons
207 int Popupdead_multi_type; // what kind of popup is active for muliplayer
208 int Popupdead_skip_active = 0; // The skip-misison popup is active
209 int Popupdead_skip_already_shown = 0;
211 // Initialize the dead popup data
212 void popupdead_start()
217 if ( Popupdead_active ) {
222 // increment number of deaths
223 Player->failures_this_session++;
226 // create base window
227 Popupdead_window.create(Popupdead_background_coords[gr_screen.res][0], Popupdead_background_coords[gr_screen.res][1], 1, 1, 0);
228 Popupdead_window.set_foreground_bmap(Popupdead_background_filename[gr_screen.res]);
230 Popupdead_num_choices = 0;
231 Popupdead_multi_type = -1;
233 if ( Game_mode & GM_NORMAL ) {
234 // also do a campaign check here?
235 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)) {
236 // init the special preliminary death popup that gives the skip option
237 Popupdead_button_text[0] = XSTR( "Do Not Skip This Mission", 1473);
238 Popupdead_button_text[1] = XSTR( "Advance To The Next Mission", 1474);
239 Popupdead_button_text[2] = XSTR( "Don't Show Me This Again", 1475);
240 Popupdead_num_choices = POPUPDEAD_NUM_CHOICES_SKIP;
241 Popupdead_skip_active = 1;
242 } else if(The_mission.red_alert) {
243 // We can't staticly declare these because they are externalized
244 Popupdead_button_text[0] = XSTR( "Quick Start Mission", 105);
245 Popupdead_button_text[1] = XSTR( "Return To Flight Deck", 106);
246 Popupdead_button_text[2] = XSTR( "Return To Briefing", 107);
247 Popupdead_button_text[3] = XSTR( "Replay previous mission", 1432);
248 Popupdead_num_choices = POPUPDEAD_NUM_CHOICES_RA;
250 Popupdead_button_text[0] = XSTR( "Quick Start Mission", 105);
251 Popupdead_button_text[1] = XSTR( "Return To Flight Deck", 106);
252 Popupdead_button_text[2] = XSTR( "Return To Briefing", 107);
253 Popupdead_num_choices = POPUPDEAD_NUM_CHOICES;
256 // in multiplayer, we have different choices depending on respawn mode, etc.
258 // if the player has run out of respawns and must either quit and become an observer
259 if(Net_player->flags & NETINFO_FLAG_LIMBO){
261 // the master should not be able to quit the game
262 if( ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (multi_num_players() > 1)) || (Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN) ) {
263 Popupdead_button_text[0] = XSTR( "Observer Mode", 108);
264 Popupdead_num_choices = 1;
265 Popupdead_multi_type = POPUPDEAD_OBS_ONLY;
267 Popupdead_button_text[0] = XSTR( "Observer Mode", 108);
268 Popupdead_button_text[1] = XSTR( "Return To Flight Deck", 106);
269 Popupdead_num_choices = 2;
270 Popupdead_multi_type = POPUPDEAD_OBS_QUIT;
273 // the master of the game should not be allowed to quit
274 if ( ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (multi_num_players() > 1)) || (Net_player->flags & NETINFO_FLAG_TEAM_CAPTAIN) ) {
275 Popupdead_button_text[0] = XSTR( "Respawn", 109);
276 Popupdead_num_choices = 1;
277 Popupdead_multi_type = POPUPDEAD_RESPAWN_ONLY;
279 Popupdead_button_text[0] = XSTR( "Respawn", 109);
280 Popupdead_button_text[1] = XSTR( "Return To Flight Deck", 106);
281 Popupdead_num_choices = 2;
282 Popupdead_multi_type = POPUPDEAD_RESPAWN_QUIT;
288 for (i=0; i < Popupdead_num_choices; i++) {
289 b = &Popupdead_buttons[i];
290 b->create(&Popupdead_window, "", Popupdead_button_coords[gr_screen.res][i][0], Popupdead_button_coords[gr_screen.res][i][1], 30, 20, 0, 1);
291 b->set_bmaps(Popupdead_button_filenames[gr_screen.res][i], 3, 0);
292 b->set_highlight_action(common_play_highlight_sound);
294 // create invisible buttons to detect mouse presses... can't use mask since button region is dynamically sized
296 gr_get_string_size(&w, &h, Popupdead_button_text[i]);
297 lx = Popupdead_region_coords[gr_screen.res][i][0] - w;
298 b = &Popupdead_button_regions[i];
299 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);
303 Popupdead_default_choice = 0;
304 Popupdead_choice = -1;
305 Popupdead_active = 1;
308 // maybe play a sound when key up/down is pressed to switch default choice
309 void popupdead_play_default_change_sound()
314 // only play if mouse not currently highlighting a choice
315 for ( i = 0; i < Popupdead_num_choices; i++ ) {
316 br = &Popupdead_button_regions[i];
317 b = &Popupdead_buttons[i];
318 if ( br->button_down() ) {
323 if ( br->button_hilighted() && !b->button_down() ) {
328 if ( b->button_hilighted() ) {
334 gamesnd_play_iface(SND_USER_SELECT);
338 // do any key processing here
339 // exit: -1 => nothing was done
340 // >=0 => a choice was selected
341 int popupdead_process_keys(int k)
352 return Popupdead_default_choice; // select the current default choice
356 if (Popupdead_skip_active) {
357 return 0; // 0 mimics a "do not skip"
359 return 1; // do nothing here for now - 1 mimics a "return to flight deck"
366 popupdead_play_default_change_sound();
367 Popupdead_default_choice++;
368 if ( Popupdead_default_choice >= Popupdead_num_choices ) {
369 Popupdead_default_choice=0;
375 case KEY_SHIFTED+KEY_TAB:
376 popupdead_play_default_change_sound();
377 Popupdead_default_choice--;
378 if ( Popupdead_default_choice < 0 ) {
379 Popupdead_default_choice=Popupdead_num_choices-1;
384 game_process_pause_key();
391 // read the dead key set
392 masked_k = k & ~KEY_CTRLED; // take out CTRL modifier only
393 process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set);
394 button_info_do(&Player->bi); // call functions based on status of button_info bit vectors
400 // see if any popup buttons have been pressed
401 // exit: -1 => no buttons pressed
402 // >=0 => button index that was pressed
403 int popupdead_check_buttons()
408 for ( i = 0; i < Popupdead_num_choices; i++ ) {
409 b = &Popupdead_button_regions[i];
410 if ( b->pressed() ) {
414 b = &Popupdead_buttons[i];
415 if ( b->pressed() ) {
423 // See if any of the button should change appearance based on mouse position
424 void popupdead_force_draw_buttons()
426 int i,mouse_is_highlighting=0;
429 for ( i = 0; i < Popupdead_num_choices; i++ ) {
430 br = &Popupdead_button_regions[i];
431 b = &Popupdead_buttons[i];
432 if ( br->button_down() ) {
434 mouse_is_highlighting=1;
438 if ( (b->button_hilighted()) || (br->button_hilighted() && !b->button_down()) ) {
439 Popupdead_default_choice=i;
440 mouse_is_highlighting=1;
445 // Only if mouse is not highlighting an option, let the default choice be drawn highlighted
446 if ( (!mouse_is_highlighting) && (Popupdead_num_choices>1) ) {
447 for ( i = 0; i < Popupdead_num_choices; i++ ) {
448 b = &Popupdead_buttons[i];
449 // highlight the default choice
450 if ( i == Popupdead_default_choice ) {
457 // Draw the button text nicely formatted in the popup
458 void popupdead_draw_button_text()
462 gr_set_color_fast(&Color_bright_blue);
464 for ( i=0; i < Popupdead_num_choices; i++ ) {
465 gr_get_string_size(&w, &h, Popupdead_button_text[i]);
466 sx = Popupdead_region_coords[gr_screen.res][i][0]-w;
467 sy = Popupdead_region_coords[gr_screen.res][i][1]+4;
468 gr_string(sx, sy, Popupdead_button_text[i]);
472 // reinits the death popup
473 // used for skip popup to death popup transition
474 void popupdead_restart() {
475 Popupdead_skip_already_shown = 1;
476 Popupdead_skip_active = 0;
477 Popupdead_active = 0;
478 Player->failures_this_session--; // hacky correction for a double count when calling popupdead_start() twice
482 // do the "skip mission" version of the death popup
483 int popupdead_skip_do_frame()
485 int k = Popupdead_window.process();
488 int choice = popupdead_process_keys(k);
490 choice = popupdead_check_buttons();
493 // take appropriate options
496 // try this mission again, so proceed to normal death popup
497 gamesnd_play_iface(SND_USER_SELECT);
502 mission_campaign_skip_to_next();
504 gamesnd_play_iface(SND_USER_SELECT);
507 // dont show this again
508 Player->show_skip_popup = 0;
510 gamesnd_play_iface(SND_USER_SELECT);
516 Popupdead_window.draw();
517 popupdead_force_draw_buttons();
518 popupdead_draw_button_text();
520 // render skip mission message
521 gr_set_color_fast(&Color_bright_white);
522 gr_string(0x8000, Popupdead_skip_message_y[gr_screen.res], XSTR("You have failed this mission five times.", 1470));
523 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));
529 // Called once per frame to run the dead popup
530 int popupdead_do_frame(float frametime)
535 if (Popupdead_skip_active) {
536 // do the skip mission popup, and thats all
537 if (popupdead_skip_do_frame() == 1) {
538 return 2; // fake the "go to briefing" choice
540 return -1; // fake no choice
544 if ( !Popupdead_active ) {
548 // dont let dude skip 3-09. hack.
549 if(Game_mode & GM_CAMPAIGN_MODE){
550 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
551 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
552 Popupdead_skip_already_shown = 1;
557 // maybe show skip mission popup
558 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)) {
559 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
560 XSTR("Advance To The Next Mission", 1474),
561 XSTR("Don't Show Me This Again", 1475),
562 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
563 switch (popup_choice) {
565 // stay on this mission, so proceed to normal death popup
566 // in other words, do nothing.
570 Popupdead_active = 0;
571 mission_campaign_skip_to_next();
572 gameseq_post_event(GS_EVENT_START_GAME);
575 // dont show this again
576 Player->show_skip_popup = 0;
580 Popupdead_skip_already_shown = 1;
584 k = Popupdead_window.process();
586 choice = popupdead_process_keys(k);
588 // do something different for single/multiplayer
589 if ( Game_mode & GM_NORMAL ) {
590 Popupdead_choice=choice;
592 Assert( Popupdead_multi_type != -1 );
593 switch ( Popupdead_multi_type ) {
595 case POPUPDEAD_OBS_ONLY:
596 case POPUPDEAD_OBS_QUIT:
597 Popupdead_choice = POPUPDEAD_DO_OBSERVER;
598 if ( (Popupdead_multi_type == POPUPDEAD_OBS_QUIT) && (choice == 1) )
599 Popupdead_choice = POPUPDEAD_DO_MAIN_HALL;
602 case POPUPDEAD_RESPAWN_ONLY:
603 case POPUPDEAD_RESPAWN_QUIT:
604 Popupdead_choice = POPUPDEAD_DO_RESPAWN;
605 if ( (Popupdead_multi_type == POPUPDEAD_RESPAWN_QUIT) && (choice == 1) )
606 Popupdead_choice = POPUPDEAD_DO_MAIN_HALL;
616 choice = popupdead_check_buttons();
618 // do something different for single/multiplayer
619 if ( Game_mode & GM_NORMAL ) {
620 Popupdead_choice=choice;
622 Assert( Popupdead_multi_type != -1 );
623 switch ( Popupdead_multi_type ) {
625 case POPUPDEAD_OBS_ONLY:
626 case POPUPDEAD_OBS_QUIT:
627 Popupdead_choice = POPUPDEAD_DO_OBSERVER;
628 if ( (Popupdead_multi_type == POPUPDEAD_OBS_QUIT) && (choice == 1) )
629 Popupdead_choice = POPUPDEAD_DO_MAIN_HALL;
632 case POPUPDEAD_RESPAWN_ONLY:
633 case POPUPDEAD_RESPAWN_QUIT:
634 Popupdead_choice = POPUPDEAD_DO_RESPAWN;
635 if ( (Popupdead_multi_type == POPUPDEAD_RESPAWN_QUIT) && (choice == 1) )
636 Popupdead_choice = POPUPDEAD_DO_MAIN_HALL;
646 Popupdead_window.draw();
647 popupdead_force_draw_buttons();
648 popupdead_draw_button_text();
650 return Popupdead_choice;
653 // Close down the dead popup
654 void popupdead_close()
656 if ( !Popupdead_active ) {
660 gamesnd_play_iface(SND_POPUP_DISAPPEAR);
661 Popupdead_window.destroy();
664 Popupdead_active = 0;
665 Popupdead_skip_active = 0;
666 Popupdead_skip_already_shown = 0;
669 // Is there a dead popup active?
670 int popupdead_is_active()
672 return Popupdead_active;