2 * $Logfile: /Freespace2/code/MissionUI/MissionDebrief.cpp $
7 * C module for running the debriefing
10 * Revision 1.4 2002/06/02 04:26:34 relnev
13 * Revision 1.3 2002/05/26 22:06:17 relnev
14 * makefile: disable stand_gui for now.
16 * rest: staticize some globals
18 * Revision 1.2 2002/05/07 03:16:46 theoddone33
19 * The Great Newline Fix
21 * Revision 1.1.1.1 2002/05/03 03:28:10 root
25 * 57 10/29/99 10:40p Jefff
26 * hack to make german medal names display without actually changing them
28 * 56 10/13/99 3:26p Jefff
29 * fixed unnumbered XSTRs
31 * 55 10/06/99 10:28a Jefff
34 * 54 9/30/99 5:57p Jefff
35 * show upsell at end of campaign in OEM builds
37 * 53 9/15/99 3:42a Jefff
40 * 52 9/14/99 4:35a Dave
41 * Argh. Added all kinds of code to handle potential crashes in debriefing
44 * 51 9/14/99 3:26a Dave
45 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
46 * respawn-too-early problem. Made a few crash points safe.
48 * 50 9/14/99 12:51a Jefff
50 * 49 9/13/99 6:01p Jefff
51 * fixed wrong promotion voice mapping for sm1-08
53 * 48 9/13/99 11:15a Jefff
54 * clear out award text bug fixed
56 * 47 9/13/99 12:17p Andsager
57 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
60 * 46 9/07/99 9:35p Jefff
61 * fixed bug where award text was not getting cleared properly between
64 * 45 9/07/99 6:56p Jefff
65 * a few adjustments to loop detection
67 * 44 9/07/99 1:54p Jefff
68 * skip mission cleanup
70 * 43 9/06/99 9:45p Jefff
71 * skip mission support
73 * 42 9/06/99 6:38p Dave
74 * Improved CD detection code.
76 * 41 9/03/99 1:32a Dave
77 * CD checking by act. Added support to play 2 cutscenes in a row
78 * seamlessly. Fixed super low level cfile bug related to files in the
79 * root directory of a CD. Added cheat code to set campaign mission # in
82 * 40 9/02/99 3:45p Jefff
83 * forgot to remove some debug code. doh.
85 * 39 9/02/99 3:41p Jefff
86 * changed badge voice handling to be similar to promotion voice handling
88 * 38 9/01/99 4:41p Jefff
89 * fixed stoopid text color bug
91 * 37 8/31/99 11:54a Jefff
92 * minor debrief music tweak
94 * 36 8/27/99 9:57a Dave
95 * Enabled standard cheat codes. Allow player to continue in a campaing
96 * after using cheat codes.
98 * 35 8/27/99 12:04a Dave
99 * Campaign loop screen.
101 * 34 8/26/99 8:49p Jefff
102 * Updated medals screen and about everything that ever touches medals in
103 * one way or another. Sheesh.
105 * 33 8/20/99 4:20p Jefff
106 * hack for choosing the correct promotion voice
108 * 32 8/16/99 4:05p Dave
109 * Big honking checkin.
111 * 31 8/16/99 9:49a Jefff
112 * mission title length fix in multi
114 * 30 8/11/99 5:33p Jefff
115 * added 3rd debrief music track
117 * 29 8/10/99 7:28p Jefff
118 * shuffled some text around
120 * 28 8/04/99 5:36p Andsager
121 * Show upsell screens at end of demo campaign before returning to main
124 * 27 8/04/99 2:07p Jefff
125 * mission title no longer overwrites popup
127 * 26 8/02/99 5:37p Jefff
129 * 25 8/02/99 4:52p Jefff
130 * negative feedback sound when recommendations button pressed and
133 * 24 7/21/99 6:21p Jefff
134 * added hotkeys to the "you cannot accept" popup
136 * 23 6/15/99 12:04p Anoop
137 * Added a warning for running out of debrief text lines.
139 * 22 6/09/99 2:17p Dave
140 * Fixed up pleasewait bitmap rendering.
142 * 21 6/01/99 6:07p Dave
143 * New loading/pause/please wait bar.
145 * 20 5/22/99 6:05p Dave
146 * Fixed a few localization # problems.
148 * 19 5/22/99 5:35p Dave
149 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
151 * 18 3/20/99 3:47p Andsager
152 * Fix crash with no mission loop description.
154 * 17 2/23/99 2:29p Dave
155 * First run of oldschool dogfight mode.
157 * 16 2/21/99 6:01p Dave
158 * Fixed standalone WSS packets.
160 * 15 2/11/99 3:08p Dave
161 * PXO refresh button. Very preliminary squad war support.
163 * 14 1/30/99 5:08p Dave
164 * More new hi-res stuff.Support for nice D3D textures.
166 * 13 1/29/99 2:08a Dave
167 * Fixed beam weapon collisions with players. Reduced size of scoring
168 * struct for multiplayer. Disabled PXO.
170 * 12 1/14/99 5:15p Neilk
171 * changed credits, command debrief interfaces to high resolution support
173 * 11 1/13/99 2:11p Andsager
174 * change default debriefing string text
176 * 10 12/17/98 4:50p Andsager
177 * Added debrief_assemble_optional_mission_popup_text() for single and
180 * 9 12/12/98 3:17p Andsager
181 * Clean up mission eval, goal, event and mission scoring.
183 * 8 12/10/98 10:19a Andsager
184 * Fix mission loop assert
186 * 7 12/10/98 9:59a Andsager
187 * Fix some bugs with mission loops
189 * 6 12/09/98 1:56p Andsager
190 * Initial checkin of mission loop
192 * 5 11/05/98 4:18p Dave
193 * First run nebula support. Beefed up localization a bit. Removed all
194 * conditional compiles for foreign versions. Modified mission file
197 * 4 10/23/98 3:51p Dave
198 * Full support for tstrings.tbl and foreign languages. All that remains
199 * is to make it active in Fred.
201 * 3 10/13/98 9:28a Dave
202 * Started neatening up freespace.h. Many variables renamed and
203 * reorganized. Added AlphaColors.[h,cpp]
205 * 2 10/07/98 10:53a Dave
208 * 1 10/07/98 10:49a Dave
210 * 178 9/17/98 3:08p Dave
211 * PXO to non-pxo game warning popup. Player icon stuff in create and join
212 * game screens. Upped server count refresh time in PXO to 35 secs (from
215 * 177 7/07/98 1:46p Dave
216 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
219 * 175 6/09/98 10:31a Hoffoss
220 * Created index numbers for all xstr() references. Any new xstr() stuff
221 * added from here on out should be added to the end if the list. The
222 * current list count can be found in FreeSpace.cpp (search for
225 * 174 6/07/98 3:26p Lawrance
226 * Fix bug with cut-off popup text
228 * 173 6/05/98 9:54a Lawrance
231 * 172 6/01/98 11:43a John
232 * JAS & MK: Classified all strings for localization.
234 * 171 5/27/98 1:24p Allender
235 * make targeting dots work (as well as other targeting features) properly
236 * in multiplayer. Don't query for CD when entering debrief in
239 * 170 5/26/98 11:10a Lawrance
240 * Fix bug where window controls get disabled when F1 pressed twice
242 * 169 5/24/98 12:55a Mike
243 * Prevent Assert() when no debriefing text for a stage.
245 * 168 5/23/98 10:38p Lawrance
246 * Avoid doing a cfile refresh when running debug
248 * 167 5/23/98 6:49p Lawrance
249 * Fix problems with refreshing the file list when a CD is inserted
251 * 166 5/21/98 6:57p Lawrance
252 * Don't prompt for the CD if voice not found
254 * 165 5/20/98 2:24a Dave
255 * Fixed server side voice muting. Tweaked multi debrief/endgame
256 * sequencing a bit. Much friendlier for stats tossing/accepting now.
258 * 164 5/19/98 8:35p Dave
259 * Revamp PXO channel listing system. Send campaign goals/events to
260 * clients for evaluation. Made lock button pressable on all screens.
262 * 163 5/19/98 11:13a Hoffoss
263 * Fixed bug where wrong wings award was being displayed in debriefing.
265 * 162 5/19/98 12:28a Mike
268 * 161 5/18/98 8:08p Hoffoss
269 * Moved placement of 'More' text.
271 * 160 5/18/98 3:50p Dan
272 * AL: Pick correct traitor debriefing voice file
274 * 159 5/17/98 6:32p Dave
275 * Make sure clients/servers aren't kicked out of the debriefing when team
276 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
277 * xfer/pilot info popup stuff.
279 * 158 5/16/98 9:14p Allender
280 * fix scoring ckise fir training missions to actually count medals, but
281 * nothing else. Code used to Assert when wings were granted then taken
282 * away because they were actually never granted in scoring structure
284 * 157 5/15/98 5:15p Dave
285 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
286 * status for team vs. team. Put in asserts to check for invalid team vs.
289 * 156 5/15/98 4:36p Allender
290 * fixed minor bug with wings
292 * 155 5/15/98 4:12p Allender
293 * removed redbook code. Put back in ingame join timer. Major fixups for
294 * stats in multiplayer. Pass correct score, medals, etc when leaving
295 * game. Be sure clients display medals, badges, etc.
297 * 154 5/15/98 2:25p Jasen
298 * temporarily disable granting of promotion and badges for clients
300 * 153 5/15/98 10:57a Allender
301 * fixed client side debriefings
303 * 152 5/15/98 10:36a Dave
304 * Removed 2 bogus bitmap drawing Int3()'s
306 * 151 5/14/98 2:44p Hoffoss
307 * Added wings awarding to debrief screen.
309 * 150 5/13/98 9:11p Lawrance
310 * Make 'replay mission' popup warn users about the loss of mission stats.
315 #include "missiondebrief.h"
316 #include "missionbriefcommon.h"
317 #include "missionscreencommon.h"
318 #include "missiongoals.h"
319 #include "missionpause.h"
320 #include "freespace.h"
321 #include "gamesequence.h"
329 #include "audiostr.h"
332 #include "contexthelp.h"
338 #include "multimsgs.h"
339 #include "multiutil.h"
340 #include "multiteamselect.h"
342 #include "eventmusic.h"
346 #include "multi_pinfo.h"
347 #include "contexthelp.h"
348 #include "multi_kick.h"
349 #include "multi_campaign.h"
350 #include "alphacolors.h"
351 #include "localize.h"
352 #include "multi_endgame.h"
355 #define MAX_TOTAL_DEBRIEF_LINES 200
357 #define TEXT_TYPE_NORMAL 1
358 #define TEXT_TYPE_RECOMMENDATION 2
360 #define DEBRIEF_NUM_STATS_PAGES 4
361 #define DEBRIEF_MISSION_STATS 0
362 #define DEBRIEF_MISSION_KILLS 1
363 #define DEBRIEF_ALLTIME_STATS 2
364 #define DEBRIEF_ALLTIME_KILLS 3
366 // 3rd coord is max width in pixels
367 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
376 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
385 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
390 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
399 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
408 #define MULTI_LIST_TEAM_OFFSET 16
410 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
415 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
424 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
434 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
443 // 0=x, 1=y, 2=width of the field
444 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
453 // 0=x, 1=y, 2=height of the field
454 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
464 // 1 = without medal (text will use medal space)
465 #define DB_WITH_MEDAL 0
466 #define DB_WITHOUT_MEDAL 1
467 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
476 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
477 "DebriefSingle", // GR_640
478 "2_DebriefSingle" // GR_1024
480 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
481 "DebriefMulti", // GR_640
482 "2_DebriefMulti" // GR_1024
484 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
485 "Debrief-m", // GR_640
486 "2_Debrief-m" // GR_1024
489 #define NUM_BUTTONS 18
492 #define DEBRIEF_TAB 0
494 #define TEXT_SCROLL_UP 2
495 #define TEXT_SCROLL_DOWN 3
496 #define REPLAY_MISSION 4
497 #define RECOMMENDATIONS 5
498 #define FIRST_STAGE 6
502 #define MULTI_PINFO_POPUP 10
503 #define MULTI_KICK 11
504 #define MEDALS_BUTTON 12
505 #define PLAYER_SCROLL_UP 13
506 #define PLAYER_SCROLL_DOWN 14
507 #define HELP_BUTTON 15
508 #define OPTIONS_BUTTON 16
509 #define ACCEPT_BUTTON 17
514 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
515 "PleaseWait", // GR_640
516 "2_PleaseWait" // GR_1024
522 char text[NAME_LENGTH+1]; // name of ship type with a colon
523 int num; // how many ships of this type player has killed
524 } debrief_stats_kill_info;
527 int net_player_index; // index into Net_players[] array
528 int rank_bitmap; // bitmap id for rank
529 char callsign[CALLSIGN_LEN];
530 } debrief_multi_list_info;
532 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
534 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
535 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
536 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
537 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
538 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
539 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
540 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
541 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
542 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
543 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
544 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
545 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
546 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
547 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
548 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
549 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
550 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
551 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
554 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
555 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
556 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
557 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
558 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
559 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
560 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
561 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
562 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
563 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
564 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
565 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
566 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
567 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
568 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
569 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
570 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
571 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
576 #define NUM_DEBRIEF_TEXT 10
577 #define MP_TEXT_INDEX_1 4
578 #define MP_TEXT_INDEX_2 5
579 #define MP_TEXT_INDEX_3 6
580 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
582 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
583 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
584 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
585 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
586 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
587 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
588 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
589 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
590 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
591 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
594 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
595 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
596 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
597 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
598 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
599 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
600 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
601 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
602 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
603 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
608 char Debrief_current_callsign[CALLSIGN_LEN+10];
609 player *Debrief_player;
611 static UI_WINDOW Debrief_ui_window;
612 static UI_BUTTON List_region;
613 static int Background_bitmap; // bitmap for the background of the debriefing
614 static int Award_bg_bitmap;
615 static int Debrief_multi_loading_bitmap;
616 static int Rank_bitmap;
617 static int Medal_bitmap;
618 static int Badge_bitmap;
619 static int Wings_bitmap;
620 static int Crest_bitmap;
621 //static int Rank_text_bitmap;
622 //static int Medal_text_bitmap;
623 //static int Badge_text_bitmap;
625 static int Debrief_accepted;
626 static int Turned_traitor;
627 static int Must_replay_mission;
629 static int Current_mode;
631 static int Recommend_active;
632 static int Award_active;
633 static int Text_offset;
634 static int Num_text_lines = 0;
635 static int Num_debrief_lines = 0;
636 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
637 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
639 static int Debrief_inited = 0;
640 static int New_stage;
641 static int Current_stage;
642 static int Num_stages;
643 static int Num_debrief_stages;
644 static int Stage_voice;
646 static int Multi_list_size;
647 static int Multi_list_offset;
649 int Debrief_multi_stages_loaded = 0;
650 int Debrief_multi_voice_loaded = 0;
652 // static int Debrief_voice_ask_for_cd;
654 // voice id's for debriefing text
655 static int Debrief_voices[MAX_DEBRIEF_STAGES];
657 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
658 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
659 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
661 // pointer used for getting to debriefing information
662 debriefing Traitor_debriefing; // used when player is a traitor
664 // pointers to the active stages for this debriefing
665 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
666 static debrief_stage Promotion_stage, Badge_stage;
667 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
668 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
669 int Multi_list_select;
671 // flag indicating if we should display info for the given player (in multiplayer)
672 int Debrief_should_show_popup = 1;
674 // already shown skip mission popup?
675 static int Debrief_skip_popup_already_shown = 0;
677 void debrief_text_init();
678 void debrief_accept(int ok_to_post_start_game_event = 1);
679 void debrief_kick_selected_player();
682 // promotion voice selection stuff
683 #define NUM_VOLITION_CAMPAIGNS 1
685 char campaign_name[32];
687 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
689 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
690 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
694 // data for which voice goes w/ which mission
695 typedef struct voice_map {
696 char mission_file[32];
700 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
701 { // FreeSpace2 campaign
733 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
735 { "loop1-1.fs2", 4 },
736 { "loop1-2.fs2", 4 },
737 { "loop1-3.fs2", 5 },
738 { "loop2-1.fs2", 4 },
743 #define DB_AWARD_WINGS 0
744 #define DB_AWARD_MEDAL 1
745 #define DB_AWARD_SOC 2
746 #define DB_AWARD_RANK 3
747 #define DB_AWARD_BADGE 4
748 #define DB_AWARD_BG 5
749 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
768 #define AWARD_TEXT_MAX_LINES 5
769 #define AWARD_TEXT_MAX_LINE_LENGTH 128
770 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
771 int Debrief_award_text_num_lines = 0;
775 // prototypes, you know you love 'em
776 void debrief_add_award_text(char *str);
777 void debrief_award_text_clear();
782 char *debrief_tooltip_handler(char *str)
784 if (!stricmp(str, NOX("@.Medal"))) {
786 return XSTR( "Medal", 435);
789 } else if (!stricmp(str, NOX("@.Rank"))) {
791 return XSTR( "Rank", 436);
794 } else if (!stricmp(str, NOX("@.Badge"))) {
796 return XSTR( "Badge", 437);
799 } else if (!stricmp(str, NOX("@Medal"))) {
800 if (Medal_bitmap >= 0){
801 return Medals[Player->stats.m_medal_earned].name;
804 } else if (!stricmp(str, NOX("@Rank"))) {
805 if (Rank_bitmap >= 0){
806 return Ranks[Promoted].name;
809 } else if (!stricmp(str, NOX("@Badge"))) {
810 if (Badge_bitmap >= 0){
811 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
818 // initialize the array of handles to the different voice streams
819 void debrief_voice_init()
823 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
824 Debrief_voices[i] = -1;
828 void debrief_load_voice_file(int voice_num, char *name)
830 int load_attempts = 0;
833 if ( load_attempts++ > 5 ) {
837 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
838 if ( Debrief_voices[voice_num] >= 0 ) {
842 // Don't bother to ask for the CD in multiplayer
843 if ( Game_mode & GM_MULTIPLAYER ) {
847 // couldn't load voice, ask user to insert CD (if necessary)
849 // if ( Debrief_voice_ask_for_cd ) {
850 // if ( game_do_cd_check() == 0 ) {
851 // Debrief_voice_ask_for_cd = 0;
858 // open and pre-load the stream buffers for the different voice streams
859 void debrief_voice_load_all()
863 // Debrief_voice_ask_for_cd = 1;
865 for ( i=0; i<Num_debrief_stages; i++ ) {
866 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
869 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
870 debrief_load_voice_file(i, Debrief_stages[i]->voice);
871 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
876 // close all the briefing voice streams
877 void debrief_voice_unload_all()
881 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
882 if ( Debrief_voices[i] != -1 ) {
883 audiostream_close_file(Debrief_voices[i], 0);
884 Debrief_voices[i] = -1;
889 // start playback of the voice for a particular briefing stage
890 void debrief_voice_play()
892 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
896 // no more stages? We are done then.
897 if (Stage_voice >= Num_debrief_stages){
901 // if in delayed start, see if delay has elapsed and start voice if so
902 if (Debrief_cue_voice) {
903 if (!timestamp_elapsed(Debrief_cue_voice)){
907 Stage_voice++; // move up to next voice
908 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
909 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
910 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
916 // see if voice is still playing. If so, do nothing yet.
917 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
921 // set voice to play in a little while from now.
922 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
925 // stop playback of the voice for a particular briefing stage
926 void debrief_voice_stop()
928 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
931 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
935 // function to deal with inserting possible promition and badge stages into the debriefing
937 void debrief_multi_fixup_stages()
941 // possibly insert the badge stage first, them the promotion stage since they are
942 // inserted at the front of the debrief stages.
943 if ( Badge_bitmap >= 0 ) {
944 // move all stages forward one. Don't
945 for ( i = Num_debrief_stages; i > 0; i-- ) {
946 Debrief_stages[i] = Debrief_stages[i-1];
948 Debrief_stages[0] = &Badge_stage;
949 Num_debrief_stages++;
952 if ( Promoted >= 0) {
953 // move all stages forward one
954 for ( i = Num_debrief_stages; i > 0; i-- ) {
955 Debrief_stages[i] = Debrief_stages[i-1];
957 Debrief_stages[0] = &Promotion_stage;
958 Num_debrief_stages++;
963 // function called from multiplayer clients to set up the debriefing information for them
964 // (sent from the server).
965 void debrief_set_multi_clients( int stage_count, int active_stages[] )
969 // set up the right briefing for this guy
970 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
971 Debriefing = &Debriefings[Net_player->p_info.team];
973 Debriefing = &Debriefings[0];
976 // see if this client was promoted -- if so, then add the first stage.
977 Num_debrief_stages = 0;
979 // set the pointers to the debriefings for this client
980 for (i = 0; i < stage_count; i++) {
981 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
984 Debrief_multi_stages_loaded = 1;
987 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
988 // information to all clients after leaving this screen.
989 void debrief_multi_server_stuff()
991 debriefing *debriefp;
993 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
994 int i, j, num_stages, stage_count[MAX_TEAMS];
996 memset( stage_active, 0, sizeof(stage_active) );
998 for (i=0; i<Num_teams; i++) {
999 debriefp = &Debriefings[i];
1001 stages[i] = stage_active[i];
1002 for (j=0; j<debriefp->num_stages; j++) {
1003 if ( eval_sexp(debriefp->stages[j].formula) ) {
1004 stage_active[i][num_stages] = j;
1009 stage_count[i] = num_stages;
1012 // if we're in campaign mode, evaluate campaign stuff
1013 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1014 multi_campaign_eval_debrief();
1017 // send the information to all clients.
1018 send_debrief_info( stage_count, stages );
1022 // --------------------------------------------------------------------------------------
1023 // debrief_set_stages_and_multi_stuff()
1025 // Set up the active stages for this debriefing
1027 // returns: number of active debriefing stages
1029 int debrief_set_stages_and_multi_stuff()
1032 debriefing *debriefp;
1034 if ( MULTIPLAYER_CLIENT ) {
1038 Num_debrief_stages = 0;
1040 if ( Game_mode & GM_MULTIPLAYER ) {
1041 debrief_multi_server_stuff();
1044 // check to see if player is a traitor (looking at his team). If so, use the special
1045 // traitor debriefing. Only done in single player
1046 debriefp = Debriefing;
1047 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1048 if (Player_ship->team == TEAM_TRAITOR)
1049 debriefp = &Traitor_debriefing;
1052 Num_debrief_stages = 0;
1053 if (Promoted >= 0) {
1054 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1057 if (Badge_bitmap >= 0) {
1058 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1061 for (i=0; i<debriefp->num_stages; i++) {
1062 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1063 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1067 return Num_debrief_stages;
1070 // init the buttons that are specific to the debriefing screen
1071 void debrief_buttons_init()
1076 for ( i=0; i<NUM_BUTTONS; i++ ) {
1077 b = &Buttons[gr_screen.res][i];
1078 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1079 // set up callback for when a mouse first goes over a button
1080 b->button.set_highlight_action( common_play_highlight_sound );
1081 b->button.set_bmaps(b->filename);
1082 b->button.link_hotspot(b->hotspot);
1086 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1087 // multiplayer specific text
1088 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1089 // only add if in multiplayer mode
1090 if(Game_mode & GM_MULTIPLAYER){
1091 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1096 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1100 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1101 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1102 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1103 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1104 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1105 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1106 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1107 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1109 // if in multiplayer, disable the button for all players except the host
1110 // also disable for squad war matches
1111 if(Game_mode & GM_MULTIPLAYER){
1112 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1113 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1118 // --------------------------------------------------------------------------------------
1119 // debrief_ui_init()
1121 void debrief_ui_init()
1123 // init ship selection masks and buttons
1124 common_set_interface_palette("DebriefPalette"); // set the interface palette
1125 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1126 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1127 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1128 debrief_buttons_init();
1130 // load in help overlay bitmap
1131 help_overlay_load(DEBRIEFING_OVERLAY);
1132 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1134 if ( Game_mode & GM_MULTIPLAYER ) {
1135 // close down any old instances of the chatbox
1138 // create the new one
1140 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1141 List_region.create(&Debrief_ui_window, "", Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1], Debrief_list_coords[gr_screen.res][2], Debrief_list_coords[gr_screen.res][3], 0, 1);
1144 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1147 if ( Background_bitmap < 0 ) {
1148 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1151 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1152 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1155 // sets Promotion_stage.voice
1156 // defaults to number 9 (Petrarch) for non-volition missions
1157 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1158 void debrief_choose_promotion_voice()
1162 if(Campaign.current_mission < 0){
1163 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1167 // search thru all official campaigns for our current campaign
1168 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1169 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1170 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1171 // now search thru the mission filenames,
1172 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1173 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1174 // found it! set the persona and bail
1175 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1183 // default to petrarch
1184 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1187 // sets Promotion_stage.voice
1188 // defaults to number 9 (Petrarch) for non-volition missions
1189 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1190 void debrief_choose_badge_voice()
1194 if(Campaign.current_mission < 0){
1195 // default to petrarch
1196 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1199 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1200 // search thru all official campaigns for our current campaign
1201 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1202 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1203 // now search thru the mission filenames,
1204 for (j=0; j<Campaign.num_missions; j++) {
1205 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1206 // found it! set the persona and bail
1207 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1215 // default to petrarch
1216 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1220 void debrief_award_init()
1232 // be sure there are no old award texts floating around
1233 debrief_award_text_clear();
1235 // handle medal earned
1236 if (Player->stats.m_medal_earned != -1) {
1237 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1239 if ( Player->stats.medals[13] > 1 ) {
1244 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1245 Wings_bitmap = bm_load(buf);
1247 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1248 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1250 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1251 Medal_bitmap = bm_load(buf);
1254 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1257 // handle promotions
1258 if ( Player->stats.m_promotion_earned != -1 ) {
1259 Promoted = Player->stats.m_promotion_earned;
1260 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1261 Rank_bitmap = bm_load(buf);
1263 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1264 Promotion_stage.new_recommendation_text = NULL;
1266 // choose appropriate promotion voice for this mission
1267 debrief_choose_promotion_voice();
1269 debrief_add_award_text(Ranks[Promoted].name);
1272 // handle badge earned
1273 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1274 if ( Player->stats.m_badge_earned != -1 ) {
1275 i = Player->stats.m_badge_earned;
1276 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1277 Badge_bitmap = bm_load(buf);
1279 Badge_stage.new_text = Badge_info[i].promotion_text;
1280 Badge_stage.new_recommendation_text = NULL;
1282 // choose appropriate voice
1283 debrief_choose_badge_voice();
1285 debrief_add_award_text(Medals[Badge_index[i]].name);
1288 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1295 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1296 // mission a traitor. The same debriefing always gets played
1297 void debrief_traitor_init()
1299 static int inited = 0;
1302 debriefing *debrief;
1303 debrief_stage *stagep;
1307 if ((rval = setjmp(parse_abort)) != 0) {
1308 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1311 read_file_text("traitor.tbl");
1315 // open localization
1318 // simplied form of the debriefing stuff.
1319 debrief = &Traitor_debriefing;
1320 required_string("#Debriefing_info");
1322 required_string("$Num stages:");
1323 stuff_int(&debrief->num_stages);
1324 Assert(debrief->num_stages == 1);
1327 stagep = &debrief->stages[stage_num++];
1328 required_string("$Formula:");
1329 stagep->formula = get_sexp_main();
1330 required_string("$multi text");
1331 if ( Fred_running ) {
1332 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1334 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1336 required_string("$Voice:");
1337 char traitor_voice_file[NAME_LENGTH];
1338 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1340 // DKA 9/13/99 Only 1 traitor msg for FS2
1341 // if ( Player->on_bastion ) {
1342 // strcpy(stagep->voice, NOX("3_"));
1344 // strcpy(stagep->voice, NOX("1_"));
1347 strcat(stagep->voice, traitor_voice_file);
1349 required_string("$Recommendation text:");
1350 if ( Fred_running ) {
1351 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1353 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1357 // close localization
1361 // disable the accept button if in single player and I am a traitor
1362 Debrief_accepted = 0;
1363 Turned_traitor = Must_replay_mission = 0;
1364 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1365 if (Player_ship->team == TEAM_TRAITOR){
1369 if (Campaign.next_mission == Campaign.current_mission){
1370 Must_replay_mission = 1;
1374 if (Turned_traitor || Must_replay_mission) {
1375 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1377 // kill off any stats
1378 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1379 scoring_level_init( &Player->stats );
1383 // initialization for listing of players in game
1384 void debrief_multi_list_init()
1386 Multi_list_size = 0; // number of net players to choose from
1387 Multi_list_offset = 0;
1389 Multi_list_select = -1;
1391 if ( !(Game_mode & GM_MULTIPLAYER) )
1394 debrief_rebuild_player_list();
1396 // switch stats display to this newly selected player
1397 set_player_stats(Multi_list[0].net_player_index);
1398 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1399 Debrief_player = Player;
1402 void debrief_multi_list_scroll_up()
1404 // if we're at the beginning of the list, don't do anything
1405 if(Multi_list_offset == 0){
1406 gamesnd_play_iface(SND_GENERAL_FAIL);
1410 // otherwise scroll up
1411 Multi_list_offset--;
1412 gamesnd_play_iface(SND_USER_SELECT);
1415 void debrief_multi_list_scroll_down()
1417 // if we can scroll down no further
1418 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1419 gamesnd_play_iface(SND_GENERAL_FAIL);
1422 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1423 gamesnd_play_iface(SND_GENERAL_FAIL);
1427 // otherwise scroll down
1428 Multi_list_offset++;
1429 gamesnd_play_iface(SND_USER_SELECT);
1432 // draw the connected net players
1433 void debrief_multi_list_draw()
1435 int y, z, font_height,idx;
1436 char str[CALLSIGN_LEN+5];
1439 font_height = gr_get_font_height();
1441 // if we currently have no item picked, pick a reasonable one
1442 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1443 // select the entry which corresponds to the local player
1444 Multi_list_select = 0;
1445 for(idx=0;idx<Multi_list_size;idx++){
1446 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1447 Multi_list_select = idx;
1449 // switch stats display to this newly selected player
1450 set_player_stats(Multi_list[idx].net_player_index);
1451 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1452 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1458 // draw the list itself
1460 z = Multi_list_offset;
1461 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1462 np = &Net_players[Multi_list[z].net_player_index];
1464 if (z >= Multi_list_size){
1467 // set the proper text color for the highlight
1468 if(np->flags & NETINFO_FLAG_GAME_HOST){
1469 if(Multi_list_select == z){
1470 gr_set_color_fast(&Color_text_active_hi);
1472 gr_set_color_fast(&Color_bright);
1475 if(Multi_list_select == z){
1476 gr_set_color_fast(&Color_text_active);
1478 gr_set_color_fast(&Color_text_normal);
1482 // blit the proper indicator - skipping observers
1483 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1484 if(Netgame.type_flags & NG_TYPE_TEAM){
1486 if(np->p_info.team == 0){
1487 // draw his "selected" icon
1488 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1489 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1490 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1492 // draw his "normal" icon
1493 else if(Multi_common_icons[MICON_TEAM0] != -1){
1494 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1495 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1497 } else if(np->p_info.team == 1){
1498 // draw his "selected" icon
1499 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1500 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1501 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1503 // draw his "normal" icon
1504 else if(Multi_common_icons[MICON_TEAM1] != -1){
1505 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1506 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1510 // draw the team 0 selected icon
1511 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1512 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1513 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1518 strcpy(str,Multi_list[z].callsign);
1519 if(Net_players[Multi_list[z].net_player_index].flags & NETINFO_FLAG_OBSERVER && !(Net_players[Multi_list[z].net_player_index].flags & NETINFO_FLAG_OBS_PLAYER)){
1520 strcat(str,XSTR( "(O)", 438));
1524 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1531 void debrief_kick_selected_player()
1533 if(Multi_list_select >= 0){
1534 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1535 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1539 // get optional mission popup text
1540 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1542 Assert(buffer != NULL);
1545 if (mission_loop_desc == NULL) {
1546 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1547 mprintf(("No mission loop description avail"));
1549 strcpy(buffer, mission_loop_desc);
1552 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1555 // what to do when the accept button is hit
1556 void debrief_accept(int ok_to_post_start_game_event)
1560 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1564 if (Game_mode & GM_MULTIPLAYER) {
1568 if (Player_ship->team == TEAM_TRAITOR){
1569 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1570 }/* else if (Cheats_enabled) {
1571 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1573 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1576 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1578 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1579 } else if ( z == 1 ) {
1580 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1586 Debrief_accepted = 1;
1587 // save mission stats
1588 if (Game_mode & GM_MULTIPLAYER) {
1589 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1590 // as well as doing stats transfers, etc.
1591 multi_debrief_accept_hit();
1595 int play_commit_sound = 1;
1596 // only write the player's stats if he's accepted
1598 // if we are just playing a single mission, then don't do many of the things
1599 // that need to be done. Nothing much should happen when just playing a single
1600 // mission that isn't in a campaign.
1601 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1603 // check for possible mission loop
1604 // check for (1) mission loop available, (2) dont have to repeat last mission
1605 if(!(Game_mode & GM_MULTIPLAYER)){
1606 int cur = Campaign.current_mission;
1607 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1608 if (Campaign.missions[cur].has_mission_loop) {
1609 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1612 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1615 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1617 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1619 Campaign.loop_enabled = 1;
1620 Campaign.next_mission = Campaign.loop_mission;
1629 if(ok_to_post_start_game_event){
1630 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1632 play_commit_sound = 0;
1635 // continue as normal
1638 mission_campaign_mission_over();
1640 // check to see if we are out of the loop now
1641 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1642 Campaign.loop_enabled = 0;
1645 // check if campaign is over
1646 if ( Campaign.next_mission == -1 ) {
1647 #if defined(FS2_DEMO) || defined(OEM_BUILD)
1648 gameseq_post_event(GS_EVENT_END_DEMO);
1650 gameseq_post_event(GS_EVENT_MAIN_MENU);
1653 if ( ok_to_post_start_game_event ) {
1655 if(game_do_cd_mission_check(Game_current_mission_filename)){
1656 gameseq_post_event(GS_EVENT_START_GAME);
1658 gameseq_post_event(GS_EVENT_MAIN_MENU);
1661 play_commit_sound = 0;
1666 gameseq_post_event(GS_EVENT_MAIN_MENU);
1669 if ( play_commit_sound ) {
1670 gamesnd_play_iface(SND_COMMIT_PRESSED);
1677 void debrief_next_tab()
1679 New_mode = Current_mode + 1;
1680 if (New_mode >= NUM_TABS)
1684 void debrief_prev_tab()
1686 New_mode = Current_mode - 1;
1688 New_mode = NUM_TABS - 1;
1691 // --------------------------------------------------------------------------------------
1692 // debrief_next_stage()
1694 void debrief_next_stage()
1696 if (Current_stage < Num_stages - 1) {
1697 New_stage = Current_stage + 1;
1698 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1701 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1704 // --------------------------------------------------------------------------------------
1705 // debrief_prev_stage()
1707 void debrief_prev_stage()
1709 if (Current_stage) {
1710 New_stage = Current_stage - 1;
1711 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1714 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1717 // --------------------------------------------------------------------------------------
1718 // debrief_first_stage()
1719 void debrief_first_stage()
1721 if (Current_stage) {
1723 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1726 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1729 // --------------------------------------------------------------------------------------
1730 // debrief_last_stage()
1731 void debrief_last_stage()
1733 if (Current_stage != Num_stages - 1) {
1734 New_stage = Num_stages - 1;
1735 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1738 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1741 // draw what stage number the debriefing is on
1742 void debrief_render_stagenum()
1750 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1751 gr_get_string_size(&w, NULL, buf);
1752 gr_set_color_fast(&Color_bright_blue);
1753 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1754 gr_set_color_fast(&Color_white);
1757 // render the mission time at the specified y location
1758 void debrief_render_mission_time(int y_loc)
1762 game_format_time(Missiontime, time_str);
1763 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1764 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1767 // render out the debriefing text to the scroll window
1768 void debrief_render()
1770 int y, z, font_height;
1772 if ( Num_stages <= 0 )
1775 font_height = gr_get_font_height();
1777 gr_set_clip(Debrief_text_wnd_coords[gr_screen.res][0], Debrief_text_wnd_coords[gr_screen.res][1], Debrief_text_wnd_coords[gr_screen.res][2], Debrief_text_wnd_coords[gr_screen.res][3]);
1780 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1781 if (z >= Num_text_lines)
1784 if (Text_type[z] == TEXT_TYPE_NORMAL)
1785 gr_set_color_fast(&Color_white);
1787 gr_set_color_fast(&Color_bright_red);
1790 gr_string(0, y, Text[z]);
1799 // render out the stats info to the scroll window
1801 void debrief_stats_render()
1803 int i, y, font_height;
1805 gr_set_color_fast(&Color_blue);
1806 gr_set_clip(Debrief_text_wnd_coords[gr_screen.res][0], Debrief_text_wnd_coords[gr_screen.res][1], Debrief_text_wnd_coords[gr_screen.res][2], Debrief_text_wnd_coords[gr_screen.res][3]);
1807 gr_string(0, 0, Debrief_current_callsign);
1808 font_height = gr_get_font_height();
1811 switch ( Current_stage ) {
1812 case DEBRIEF_MISSION_STATS:
1813 i = Current_stage - 1;
1817 gr_set_color_fast(&Color_white);
1819 // display mission completion time
1820 debrief_render_mission_time(y);
1823 show_stats_label(i, 0, y, font_height);
1824 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1826 case DEBRIEF_ALLTIME_STATS:
1827 i = Current_stage - 1;
1831 gr_set_color_fast(&Color_white);
1832 show_stats_label(i, 0, y, font_height);
1833 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1836 case DEBRIEF_ALLTIME_KILLS:
1837 case DEBRIEF_MISSION_KILLS:
1838 gr_set_color_fast(&Color_white);
1840 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1841 if (i >= Num_text_lines)
1845 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1846 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
1848 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
1851 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
1852 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
1859 if (Num_text_lines == 2) {
1860 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1861 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
1863 gr_printf(0, y, XSTR( "(No ship kills)", 450));
1876 // do action for when the replay button is pressed
1877 void debrief_replay_pressed()
1879 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
1881 choice = popup(0, 2, POPUP_CANCEL, XSTR( "&Replay", 451), XSTR( "If you choose to replay this mission, you will be required to complete it again before proceeding to future missions.\n\nIn addition, any statistics gathered during this mission will be discarded if you choose to replay.", 452));
1888 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
1889 gamesnd_play_iface(SND_COMMIT_PRESSED);
1892 // -------------------------------------------------------------------
1893 // debrief_redraw_pressed_buttons()
1895 // Redraw any debriefing buttons that are pressed down. This function is needed
1896 // since we sometimes need to draw pressed buttons last to ensure the entire
1897 // button gets drawn (and not overlapped by other buttons)
1899 void debrief_redraw_pressed_buttons()
1904 for ( i=0; i<NUM_BUTTONS; i++ ) {
1905 b = &Buttons[gr_screen.res][i].button;
1906 // don't draw the recommendations button if we're in stats mode
1907 if ( b->button_down() ) {
1913 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
1915 void debrief_button_pressed(int num)
1919 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
1920 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
1921 if (num != Current_mode){
1922 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1927 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
1928 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
1929 if (num != Current_mode){
1930 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1935 case TEXT_SCROLL_UP:
1938 gamesnd_play_iface(SND_SCROLL);
1940 gamesnd_play_iface(SND_GENERAL_FAIL);
1944 case TEXT_SCROLL_DOWN:
1945 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
1947 gamesnd_play_iface(SND_SCROLL);
1949 gamesnd_play_iface(SND_GENERAL_FAIL);
1953 case REPLAY_MISSION:
1954 if(Game_mode & GM_MULTIPLAYER){
1955 multi_debrief_replay_hit();
1957 debrief_replay_pressed();
1961 case RECOMMENDATIONS:
1962 gamesnd_play_iface(SND_USER_SELECT);
1963 Recommend_active = !Recommend_active;
1964 debrief_text_init();
1968 debrief_first_stage();
1972 debrief_prev_stage();
1976 debrief_next_stage();
1980 debrief_last_stage();
1984 gamesnd_play_iface(SND_HELP_PRESSED);
1985 launch_context_help();
1988 case OPTIONS_BUTTON:
1989 gamesnd_play_iface(SND_SWITCH_SCREENS);
1990 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
1998 gamesnd_play_iface(SND_SWITCH_SCREENS);
1999 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2002 case PLAYER_SCROLL_UP:
2003 debrief_multi_list_scroll_up();
2006 case PLAYER_SCROLL_DOWN:
2007 debrief_multi_list_scroll_down();
2010 case MULTI_PINFO_POPUP:
2011 Debrief_should_show_popup = 1;
2015 debrief_kick_selected_player();
2020 void debrief_setup_ship_kill_stats(int stage_num)
2024 debrief_stats_kill_info *kill_info;
2026 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2027 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2030 Assert(Debrief_player != NULL);
2032 // kill_ar points to an array of MAX_SHIP_TYPE ints
2033 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2034 kill_arr = Debrief_player->stats.m_okKills;
2036 kill_arr = Debrief_player->stats.kills;
2040 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2042 // code used to add in mission kills, but the new system assumes that the player will accept, so
2043 // all time stats already have mission stats added in.
2044 if ( kill_arr[i] <= 0 ){
2049 kill_info = &Debrief_stats_kills[Num_text_lines++];
2051 kill_info->num = kill_arr[i];
2053 strcpy(kill_info->text, Ship_info[i].name);
2054 strcat(kill_info->text, NOX(":"));
2057 Num_text_lines += 2;
2060 // Iterate through the debriefing buttons, checking if they are pressed
2061 void debrief_check_buttons()
2065 for ( i=0; i<NUM_BUTTONS; i++ ) {
2066 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2067 debrief_button_pressed(i);
2071 if ( !(Game_mode & GM_MULTIPLAYER) )
2074 if (List_region.pressed()) {
2075 List_region.get_mouse_pos(NULL, &y);
2076 z = Multi_list_offset + y / gr_get_font_height();
2077 if ((z >= 0) && (z < Multi_list_size)) {
2078 // switch stats display to this newly selected player
2079 set_player_stats(Multi_list[z].net_player_index);
2080 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2081 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2082 Multi_list_select = z;
2083 debrief_setup_ship_kill_stats(Current_stage);
2084 gamesnd_play_iface(SND_USER_SELECT);
2088 // if the player was double clicked on - we should popup a player info popup
2090 if (List_region.double_clicked()) {
2091 Debrief_should_show_popup = 1;
2096 void debrief_text_stage_init(char *src, int type)
2098 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2099 char line[MAX_DEBRIEF_LINE_LEN];
2100 char *p_str[MAX_DEBRIEF_LINES];
2102 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2103 Assert(n_lines >= 0);
2105 // if you hit this, you proba
2106 if(n_lines >= MAX_DEBRIEF_LINES){
2107 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2110 for ( i=0; i<n_lines; i++ ) {
2111 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2112 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2113 strncpy(line, p_str[i], n_chars[i]);
2114 line[n_chars[i]] = 0;
2115 drop_white_space(line);
2116 Text_type[Num_text_lines] = type;
2117 Text[Num_text_lines++] = strdup(line);
2123 void debrief_free_text()
2127 for (i=0; i<Num_debrief_lines; i++)
2131 Num_debrief_lines = 0;
2134 // setup the debriefing text lines for rendering
2135 void debrief_text_init()
2140 // release old text lines first
2141 debrief_free_text();
2142 Num_text_lines = Text_offset = 0;
2144 if (Current_mode == DEBRIEF_TAB) {
2145 for (i=0; i<Num_debrief_stages; i++) {
2147 Text[Num_text_lines++] = NULL; // add a blank line between stages
2149 src = Debrief_stages[i]->new_text;
2151 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2153 if (Recommend_active) {
2154 src = Debrief_stages[i]->new_recommendation_text;
2155 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2156 src = XSTR( "We have no recommendations for you.", 1054);
2159 Text[Num_text_lines++] = NULL;
2160 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2166 Num_debrief_lines = Num_text_lines;
2170 // not in debriefing mode, must be in stats mode
2172 debrief_setup_ship_kill_stats(Current_stage);
2176 // --------------------------------------------------------------------------------------
2180 Assert(!Debrief_inited);
2181 // Campaign.loop_enabled = 0;
2182 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2184 // set up the right briefing for this guy
2185 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2186 Debriefing = &Debriefings[Net_player->p_info.team];
2188 Debriefing = &Debriefings[0];
2191 // no longer is mission
2192 Game_mode &= ~(GM_IN_MISSION);
2196 New_mode = DEBRIEF_TAB;
2197 Recommend_active = Award_active = 0;
2202 Debrief_cue_voice = 0;
2203 Num_text_lines = Num_debrief_lines = 0;
2204 Debrief_first_voice_flag = 1;
2206 Debrief_multi_voice_loaded = 0;
2208 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2209 // MUST store goals and events first - may be used to evaluate next mission
2210 // store goals and events
2211 mission_campaign_store_goals_and_events();
2213 // evaluate next mission
2214 mission_campaign_eval_next_mission();
2217 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2219 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2220 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2223 // call scoring level close for my stats. Needed for award_init. The stats will
2224 // be backed out if used chooses to replace them.
2225 scoring_level_close();
2227 debrief_ui_init(); // init UI items
2228 debrief_award_init();
2230 debrief_voice_init();
2231 debrief_multi_list_init();
2232 // rank_bitmaps_clear();
2233 // rank_bitmaps_load();
2235 strcpy(Debrief_current_callsign, Player->callsign);
2236 Debrief_player = Player;
2237 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2239 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2240 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2241 // info directly from the server.
2242 if ( !MULTIPLAYER_CLIENT ) {
2243 debrief_set_stages_and_multi_stuff();
2245 if ( Num_debrief_stages <= 0 ) {
2246 Num_debrief_stages = 0;
2248 debrief_voice_load_all();
2251 // multiplayer client may have already received their debriefing info. If they have not,
2252 // then set the num debrief stages to 0
2253 if ( !Debrief_multi_stages_loaded ) {
2254 Num_debrief_stages = 0;
2259 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2260 common_music_init(SCORE_DEBRIEF_SUCCESS);
2262 common_music_init(SCORE_DEBRIEF_FAIL);
2266 // start up the appropriate music
2267 if (Campaign.next_mission == Campaign.current_mission) {
2268 // you failed the mission because you suck, so you get the suck music
2269 common_music_init(SCORE_DEBRIEF_FAIL);
2270 } else if (mission_goals_met()) {
2271 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2272 common_music_init(SCORE_DEBRIEF_SUCCESS);
2274 // you somehow passed the mission, so you get a little something for your efforts.
2275 common_music_init(SCORE_DEBRIEF_AVERAGE);
2278 if (Campaign.next_mission == Campaign.current_mission) {
2279 // better luck next time, increase his retries
2280 Player->failures_this_session++;
2282 // clear his retries info regardless of whether or not he accepts
2283 Player->failures_this_session = 0;
2286 if (Game_mode & GM_MULTIPLAYER) {
2287 multi_debrief_init();
2289 // if i'm not the host of the game, disable the multi kick button
2290 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2291 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2294 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2295 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2296 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2297 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2298 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2299 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2300 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2301 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2304 if (!Award_active) {
2305 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2306 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2309 Debrief_skip_popup_already_shown = 0;
2314 // --------------------------------------------------------------------------------------
2316 void debrief_close()
2320 Assert(Debrief_inited);
2322 // if the mission wasn't accepted, clear out my stats
2323 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2324 // are a little bit different
2325 if (Game_mode & GM_MULTIPLAYER) {
2326 // if stats weren't accepted, backout my own stats
2327 if (multi_debrief_stats_accept_code() != 1) {
2328 if(MULTIPLAYER_MASTER){
2329 for(idx=0; idx<MAX_PLAYERS; idx++){
2330 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2331 scoring_backout_accept(&Net_players[idx].player->stats);
2335 scoring_backout_accept( &Player->stats );
2340 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2341 scoring_backout_accept( &Player->stats );
2345 // if dude passed the misson and accepted, reset his show skip popup flag
2346 if (Debrief_accepted) {
2347 Player->show_skip_popup = 1;
2350 if (Num_debrief_lines) {
2351 for (i=0; i<Num_debrief_lines; i++){
2358 // unload the overlay bitmap
2359 // help_overlay_unload(DEBRIEFING_OVERLAY);
2361 // clear out award text
2362 Debrief_award_text_num_lines = 0;
2364 debrief_voice_unload_all();
2365 common_music_close();
2368 // rank_bitmaps_release();
2371 if (Background_bitmap >= 0){
2372 bm_unload(Background_bitmap);
2375 if (Award_bg_bitmap >= 0){
2376 bm_unload(Award_bg_bitmap);
2379 if (Rank_bitmap >= 0){
2380 bm_unload(Rank_bitmap);
2383 if (Medal_bitmap >= 0){
2384 bm_unload(Medal_bitmap);
2387 if (Badge_bitmap >= 0){
2388 bm_unload(Badge_bitmap);
2391 if (Wings_bitmap >= 0) {
2392 bm_unload(Wings_bitmap);
2395 if (Crest_bitmap >= 0) {
2396 bm_unload(Crest_bitmap);
2399 Debrief_ui_window.destroy();
2400 common_free_interface_palette(); // restore game palette
2403 if (Game_mode & GM_MULTIPLAYER){
2404 multi_debrief_close();
2412 // handle keypresses in debriefing
2413 void debrief_do_keys(int new_k)
2420 case KEY_SHIFTED | KEY_TAB:
2428 // multiplayer accept popup is a little bit different
2429 if (Game_mode & GM_MULTIPLAYER) {
2430 multi_debrief_esc_hit();
2432 // display the normal debrief popup
2434 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2435 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2436 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2437 if (choice == 1) { // accept and continue on
2439 gameseq_post_event(GS_EVENT_MAIN_MENU);
2445 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2446 // need to popup saying that mission was a failure and must be replayed
2447 choice = popup(0, 2, POPUP_NO, POPUP_YES, XSTR( "Because this mission was a failure, you must replay this mission when you continue your campaign.\n\nReturn to the Flight Deck?", 457));
2452 // Return to Main Hall
2453 gameseq_post_event(GS_EVENT_END_GAME);
2463 void debrief_draw_award_text()
2465 int start_y, curr_y, i, x, sw;
2466 int fh = gr_get_font_height();
2467 int field_width = (Medal_bitmap > 0) ? Debrief_award_text_width[gr_screen.res][DB_WITH_MEDAL] : Debrief_award_text_width[gr_screen.res][DB_WITHOUT_MEDAL];
2469 // vertically centered within field
2470 start_y = Debrief_award_text_coords[gr_screen.res][1] + ((Debrief_award_text_coords[gr_screen.res][2] - (fh * Debrief_award_text_num_lines)) / 2);
2474 for (i=0; i<Debrief_award_text_num_lines; i++) {
2475 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2476 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2477 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2478 gr_set_color_fast(&Color_white);
2479 gr_string(x, curr_y, Debrief_award_text[i]);
2481 // adjust y pos, including a little extra between the "pairs"
2483 if ((i == 1) || (i == 3)) {
2484 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2489 // clears out text array so we dont have old award text showing up on new awards.
2490 void debrief_award_text_clear() {
2493 Debrief_award_text_num_lines = 0;
2494 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2495 //Debrief_award_text[i][0] = 0;
2496 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2500 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2501 void debrief_add_award_text(char *str)
2503 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2504 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2509 int field_width = (Medal_bitmap > 0) ? Debrief_award_text_width[gr_screen.res][DB_WITH_MEDAL] : Debrief_award_text_width[gr_screen.res][DB_WITHOUT_MEDAL];
2512 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2514 // maybe translate for displaying
2516 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2519 Debrief_award_text_num_lines++;
2521 // if its too long, split once ONLY
2522 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2523 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2524 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2525 if (line2 != NULL) {
2526 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2528 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2532 // called once per frame to drive all the input reading and rendering
2533 void debrief_do_frame(float frametime)
2536 char *please_wait_str = XSTR("Please Wait", 1242);
2540 Assert(Debrief_inited);
2542 // first thing is to load the files
2543 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2544 // draw the background, etc
2545 GR_MAYBE_CLEAR_RES(Background_bitmap);
2546 if (Background_bitmap >= 0) {
2547 gr_set_bitmap(Background_bitmap);
2551 Debrief_ui_window.draw();
2553 if ( Debrief_multi_loading_bitmap > -1 ){
2554 gr_set_bitmap(Debrief_multi_loading_bitmap);
2555 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2558 // draw "Please Wait"
2559 gr_set_color_fast(&Color_normal);
2561 gr_get_string_size(&str_w, &str_h, please_wait_str);
2562 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2567 // make sure we run the debrief do frame
2568 if (Game_mode & GM_MULTIPLAYER) {
2569 multi_debrief_do_frame();
2574 int keypress = game_check_key();
2575 if(keypress == KEY_ESC){
2577 multi_quit_game(PROMPT_CLIENT);
2583 // if multiplayer client, and not loaded voice, then load it
2584 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2585 debrief_multi_fixup_stages();
2586 debrief_voice_load_all();
2587 Debrief_multi_voice_loaded = 1;
2590 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2591 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2592 Debrief_ui_window.set_ignore_gadgets(1);
2595 k = chatbox_process();
2596 if ( Game_mode & GM_NORMAL ) {
2597 new_k = Debrief_ui_window.process(k);
2599 new_k = Debrief_ui_window.process(k, 0);
2602 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2603 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2604 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2605 Debrief_ui_window.set_ignore_gadgets(0);
2611 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2612 Debrief_ui_window.set_ignore_gadgets(0);
2615 // don't show pilot info popup by default
2616 Debrief_should_show_popup = 0;
2618 // see if the mode has changed and handle it if so.
2619 if ( Current_mode != New_mode ) {
2620 debrief_voice_stop();
2621 Current_mode = New_mode;
2624 if (New_mode == DEBRIEF_TAB) {
2626 Debrief_cue_voice = 0;
2628 if (Debrief_first_voice_flag) {
2629 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2630 Debrief_first_voice_flag = 0;
2633 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2637 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2638 Current_stage = New_stage;
2639 debrief_text_init();
2642 debrief_voice_play();
2645 if (Game_mode & GM_MULTIPLAYER) {
2646 multi_debrief_do_frame();
2649 // Now do all the rendering for the frame
2650 GR_MAYBE_CLEAR_RES(Background_bitmap);
2651 if (Background_bitmap >= 0) {
2652 gr_set_bitmap(Background_bitmap);
2656 // draw the damn awarded stuff, G
2657 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2658 gr_set_bitmap(Award_bg_bitmap);
2659 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2660 if (Rank_bitmap >= 0) {
2661 gr_set_bitmap(Rank_bitmap);
2662 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2665 if (Medal_bitmap >= 0) {
2666 gr_set_bitmap(Medal_bitmap);
2667 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2670 if (Badge_bitmap >= 0) {
2671 gr_set_bitmap(Badge_bitmap);
2672 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2675 if (Wings_bitmap >= 0) {
2676 gr_set_bitmap(Wings_bitmap);
2677 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2680 if (Crest_bitmap >= 0) {
2681 gr_set_bitmap(Crest_bitmap);
2682 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2685 // draw medal/badge/rank labels
2686 debrief_draw_award_text();
2688 /* if (Rank_text_bitmap >= 0) {
2689 gr_set_bitmap(Rank_text_bitmap);
2690 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2694 if (Medal_text_bitmap >= 0) {
2695 gr_set_bitmap(Medal_text_bitmap);
2696 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2699 if (Badge_text_bitmap >= 0) {
2700 gr_set_bitmap(Badge_text_bitmap);
2701 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2706 Debrief_ui_window.draw();
2707 debrief_redraw_pressed_buttons();
2708 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2709 if (Recommend_active && (Current_mode != STATS_TAB)) {
2710 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2713 // draw the title of the mission
2714 gr_set_color_fast(&Color_bright_white);
2715 strcpy(buf, The_mission.name);
2716 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2717 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2719 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2720 gr_set_color_fast(&Color_normal);
2721 gr_printf(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1] - 10, NOX("[name: %s, mod: %s]"), Mission_filename, The_mission.modified);
2724 // draw the screen-specific text
2725 switch (Current_mode) {
2727 if ( Num_debrief_stages <= 0 ) {
2728 gr_set_color_fast(&Color_white);
2729 Assert( Game_current_mission_filename != NULL );
2730 gr_printf(Debrief_text_wnd_coords[gr_screen.res][0], Debrief_text_wnd_coords[gr_screen.res][1], XSTR( "No Debriefing for mission: %s", 458), Game_current_mission_filename);
2739 debrief_stats_render();
2743 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2746 gr_set_color_fast(&Color_red);
2747 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2748 gr_printf(Debrief_text_wnd_coords[gr_screen.res][0] + Debrief_text_wnd_coords[gr_screen.res][2] / 2 - w / 2, Debrief_text_wnd_coords[gr_screen.res][1] + Debrief_text_wnd_coords[gr_screen.res][3], XSTR( "More", 459));
2751 debrief_render_stagenum();
2752 debrief_multi_list_draw();
2754 // render some extra stuff in multiplayer
2755 if (Game_mode & GM_MULTIPLAYER) {
2756 // render the chatbox last
2760 Debrief_ui_window.draw_tooltip();
2762 // render the status indicator for the voice system
2763 multi_common_voice_display_status();
2766 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2767 // want to include the mouse pointer which is drawn in the flip
2769 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2770 debrief_check_buttons();
2771 debrief_do_keys(new_k);
2774 // blit help overlay if active
2775 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2779 // dont let dude skip 3-09. hack.
2780 if(Game_mode & GM_CAMPAIGN_MODE){
2781 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2782 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2783 Debrief_skip_popup_already_shown = 1;
2788 // maybe show skip mission popup
2789 if ((!Debrief_skip_popup_already_shown) && (Player->show_skip_popup) && (Game_mode & GM_NORMAL) && (Game_mode & GM_CAMPAIGN_MODE) && (Player->failures_this_session >= PLAYER_MISSION_FAILURE_LIMIT) && !(Game_mode & GM_MULTIPLAYER)) {
2790 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
2791 XSTR("Advance To The Next Mission", 1474),
2792 XSTR("Don't Show Me This Again", 1475),
2793 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
2794 switch (popup_choice) {
2796 // stay on this mission, so proceed to normal debrief
2797 // in other words, do nothing.
2800 // skip this mission
2801 mission_campaign_skip_to_next();
2802 gameseq_post_event(GS_EVENT_START_GAME);
2805 // dont show this again
2806 Player->show_skip_popup = 0;
2810 Debrief_skip_popup_already_shown = 1;
2813 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
2814 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
2815 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
2816 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
2818 Debrief_should_show_popup = 0;
2822 void debrief_rebuild_player_list()
2826 debrief_multi_list_info *list;
2828 Multi_list_size = 0; // number of net players to choose from
2830 for ( i=0; i<MAX_PLAYERS; i++ ) {
2831 np = &Net_players[i];
2832 // remember not to include the standalone.
2833 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
2834 list = &Multi_list[Multi_list_size++];
2835 list->net_player_index = i;
2836 strcpy(list->callsign, np->player->callsign);
2838 // make sure to leave some room to blit the team indicator
2839 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
2844 void debrief_handle_player_drop()
2846 debrief_rebuild_player_list();
2849 void debrief_disable_accept()