2 * $Logfile: /Freespace2/code/MissionUI/MissionDebrief.cpp $
7 * C module for running the debriefing
10 * Revision 1.1 2002/05/03 03:28:10 root
14 * 57 10/29/99 10:40p Jefff
15 * hack to make german medal names display without actually changing them
17 * 56 10/13/99 3:26p Jefff
18 * fixed unnumbered XSTRs
20 * 55 10/06/99 10:28a Jefff
23 * 54 9/30/99 5:57p Jefff
24 * show upsell at end of campaign in OEM builds
26 * 53 9/15/99 3:42a Jefff
29 * 52 9/14/99 4:35a Dave
30 * Argh. Added all kinds of code to handle potential crashes in debriefing
33 * 51 9/14/99 3:26a Dave
34 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
35 * respawn-too-early problem. Made a few crash points safe.
37 * 50 9/14/99 12:51a Jefff
39 * 49 9/13/99 6:01p Jefff
40 * fixed wrong promotion voice mapping for sm1-08
42 * 48 9/13/99 11:15a Jefff
43 * clear out award text bug fixed
45 * 47 9/13/99 12:17p Andsager
46 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
49 * 46 9/07/99 9:35p Jefff
50 * fixed bug where award text was not getting cleared properly between
53 * 45 9/07/99 6:56p Jefff
54 * a few adjustments to loop detection
56 * 44 9/07/99 1:54p Jefff
57 * skip mission cleanup
59 * 43 9/06/99 9:45p Jefff
60 * skip mission support
62 * 42 9/06/99 6:38p Dave
63 * Improved CD detection code.
65 * 41 9/03/99 1:32a Dave
66 * CD checking by act. Added support to play 2 cutscenes in a row
67 * seamlessly. Fixed super low level cfile bug related to files in the
68 * root directory of a CD. Added cheat code to set campaign mission # in
71 * 40 9/02/99 3:45p Jefff
72 * forgot to remove some debug code. doh.
74 * 39 9/02/99 3:41p Jefff
75 * changed badge voice handling to be similar to promotion voice handling
77 * 38 9/01/99 4:41p Jefff
78 * fixed stoopid text color bug
80 * 37 8/31/99 11:54a Jefff
81 * minor debrief music tweak
83 * 36 8/27/99 9:57a Dave
84 * Enabled standard cheat codes. Allow player to continue in a campaing
85 * after using cheat codes.
87 * 35 8/27/99 12:04a Dave
88 * Campaign loop screen.
90 * 34 8/26/99 8:49p Jefff
91 * Updated medals screen and about everything that ever touches medals in
92 * one way or another. Sheesh.
94 * 33 8/20/99 4:20p Jefff
95 * hack for choosing the correct promotion voice
97 * 32 8/16/99 4:05p Dave
98 * Big honking checkin.
100 * 31 8/16/99 9:49a Jefff
101 * mission title length fix in multi
103 * 30 8/11/99 5:33p Jefff
104 * added 3rd debrief music track
106 * 29 8/10/99 7:28p Jefff
107 * shuffled some text around
109 * 28 8/04/99 5:36p Andsager
110 * Show upsell screens at end of demo campaign before returning to main
113 * 27 8/04/99 2:07p Jefff
114 * mission title no longer overwrites popup
116 * 26 8/02/99 5:37p Jefff
118 * 25 8/02/99 4:52p Jefff
119 * negative feedback sound when recommendations button pressed and
122 * 24 7/21/99 6:21p Jefff
123 * added hotkeys to the "you cannot accept" popup
125 * 23 6/15/99 12:04p Anoop
126 * Added a warning for running out of debrief text lines.
128 * 22 6/09/99 2:17p Dave
129 * Fixed up pleasewait bitmap rendering.
131 * 21 6/01/99 6:07p Dave
132 * New loading/pause/please wait bar.
134 * 20 5/22/99 6:05p Dave
135 * Fixed a few localization # problems.
137 * 19 5/22/99 5:35p Dave
138 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
140 * 18 3/20/99 3:47p Andsager
141 * Fix crash with no mission loop description.
143 * 17 2/23/99 2:29p Dave
144 * First run of oldschool dogfight mode.
146 * 16 2/21/99 6:01p Dave
147 * Fixed standalone WSS packets.
149 * 15 2/11/99 3:08p Dave
150 * PXO refresh button. Very preliminary squad war support.
152 * 14 1/30/99 5:08p Dave
153 * More new hi-res stuff.Support for nice D3D textures.
155 * 13 1/29/99 2:08a Dave
156 * Fixed beam weapon collisions with players. Reduced size of scoring
157 * struct for multiplayer. Disabled PXO.
159 * 12 1/14/99 5:15p Neilk
160 * changed credits, command debrief interfaces to high resolution support
162 * 11 1/13/99 2:11p Andsager
163 * change default debriefing string text
165 * 10 12/17/98 4:50p Andsager
166 * Added debrief_assemble_optional_mission_popup_text() for single and
169 * 9 12/12/98 3:17p Andsager
170 * Clean up mission eval, goal, event and mission scoring.
172 * 8 12/10/98 10:19a Andsager
173 * Fix mission loop assert
175 * 7 12/10/98 9:59a Andsager
176 * Fix some bugs with mission loops
178 * 6 12/09/98 1:56p Andsager
179 * Initial checkin of mission loop
181 * 5 11/05/98 4:18p Dave
182 * First run nebula support. Beefed up localization a bit. Removed all
183 * conditional compiles for foreign versions. Modified mission file
186 * 4 10/23/98 3:51p Dave
187 * Full support for tstrings.tbl and foreign languages. All that remains
188 * is to make it active in Fred.
190 * 3 10/13/98 9:28a Dave
191 * Started neatening up freespace.h. Many variables renamed and
192 * reorganized. Added AlphaColors.[h,cpp]
194 * 2 10/07/98 10:53a Dave
197 * 1 10/07/98 10:49a Dave
199 * 178 9/17/98 3:08p Dave
200 * PXO to non-pxo game warning popup. Player icon stuff in create and join
201 * game screens. Upped server count refresh time in PXO to 35 secs (from
204 * 177 7/07/98 1:46p Dave
205 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
208 * 175 6/09/98 10:31a Hoffoss
209 * Created index numbers for all xstr() references. Any new xstr() stuff
210 * added from here on out should be added to the end if the list. The
211 * current list count can be found in FreeSpace.cpp (search for
214 * 174 6/07/98 3:26p Lawrance
215 * Fix bug with cut-off popup text
217 * 173 6/05/98 9:54a Lawrance
220 * 172 6/01/98 11:43a John
221 * JAS & MK: Classified all strings for localization.
223 * 171 5/27/98 1:24p Allender
224 * make targeting dots work (as well as other targeting features) properly
225 * in multiplayer. Don't query for CD when entering debrief in
228 * 170 5/26/98 11:10a Lawrance
229 * Fix bug where window controls get disabled when F1 pressed twice
231 * 169 5/24/98 12:55a Mike
232 * Prevent Assert() when no debriefing text for a stage.
234 * 168 5/23/98 10:38p Lawrance
235 * Avoid doing a cfile refresh when running debug
237 * 167 5/23/98 6:49p Lawrance
238 * Fix problems with refreshing the file list when a CD is inserted
240 * 166 5/21/98 6:57p Lawrance
241 * Don't prompt for the CD if voice not found
243 * 165 5/20/98 2:24a Dave
244 * Fixed server side voice muting. Tweaked multi debrief/endgame
245 * sequencing a bit. Much friendlier for stats tossing/accepting now.
247 * 164 5/19/98 8:35p Dave
248 * Revamp PXO channel listing system. Send campaign goals/events to
249 * clients for evaluation. Made lock button pressable on all screens.
251 * 163 5/19/98 11:13a Hoffoss
252 * Fixed bug where wrong wings award was being displayed in debriefing.
254 * 162 5/19/98 12:28a Mike
257 * 161 5/18/98 8:08p Hoffoss
258 * Moved placement of 'More' text.
260 * 160 5/18/98 3:50p Dan
261 * AL: Pick correct traitor debriefing voice file
263 * 159 5/17/98 6:32p Dave
264 * Make sure clients/servers aren't kicked out of the debriefing when team
265 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
266 * xfer/pilot info popup stuff.
268 * 158 5/16/98 9:14p Allender
269 * fix scoring ckise fir training missions to actually count medals, but
270 * nothing else. Code used to Assert when wings were granted then taken
271 * away because they were actually never granted in scoring structure
273 * 157 5/15/98 5:15p Dave
274 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
275 * status for team vs. team. Put in asserts to check for invalid team vs.
278 * 156 5/15/98 4:36p Allender
279 * fixed minor bug with wings
281 * 155 5/15/98 4:12p Allender
282 * removed redbook code. Put back in ingame join timer. Major fixups for
283 * stats in multiplayer. Pass correct score, medals, etc when leaving
284 * game. Be sure clients display medals, badges, etc.
286 * 154 5/15/98 2:25p Jasen
287 * temporarily disable granting of promotion and badges for clients
289 * 153 5/15/98 10:57a Allender
290 * fixed client side debriefings
292 * 152 5/15/98 10:36a Dave
293 * Removed 2 bogus bitmap drawing Int3()'s
295 * 151 5/14/98 2:44p Hoffoss
296 * Added wings awarding to debrief screen.
298 * 150 5/13/98 9:11p Lawrance
299 * Make 'replay mission' popup warn users about the loss of mission stats.
304 #include "missiondebrief.h"
305 #include "missionbriefcommon.h"
306 #include "missionscreencommon.h"
307 #include "missiongoals.h"
308 #include "missionpause.h"
309 #include "freespace.h"
310 #include "gamesequence.h"
318 #include "audiostr.h"
321 #include "contexthelp.h"
327 #include "multimsgs.h"
328 #include "multiutil.h"
329 #include "multiteamselect.h"
331 #include "eventmusic.h"
335 #include "multi_pinfo.h"
336 #include "contexthelp.h"
337 #include "multi_kick.h"
338 #include "multi_campaign.h"
339 #include "alphacolors.h"
340 #include "localize.h"
341 #include "multi_endgame.h"
344 #define MAX_TOTAL_DEBRIEF_LINES 200
346 #define TEXT_TYPE_NORMAL 1
347 #define TEXT_TYPE_RECOMMENDATION 2
349 #define DEBRIEF_NUM_STATS_PAGES 4
350 #define DEBRIEF_MISSION_STATS 0
351 #define DEBRIEF_MISSION_KILLS 1
352 #define DEBRIEF_ALLTIME_STATS 2
353 #define DEBRIEF_ALLTIME_KILLS 3
355 // 3rd coord is max width in pixels
356 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
365 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
374 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
379 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
388 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
397 #define MULTI_LIST_TEAM_OFFSET 16
399 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
404 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
413 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
423 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
432 // 0=x, 1=y, 2=width of the field
433 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
442 // 0=x, 1=y, 2=height of the field
443 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
453 // 1 = without medal (text will use medal space)
454 #define DB_WITH_MEDAL 0
455 #define DB_WITHOUT_MEDAL 1
456 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
465 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
466 "DebriefSingle", // GR_640
467 "2_DebriefSingle" // GR_1024
469 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
470 "DebriefMulti", // GR_640
471 "2_DebriefMulti" // GR_1024
473 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
474 "Debrief-m", // GR_640
475 "2_Debrief-m" // GR_1024
478 #define NUM_BUTTONS 18
481 #define DEBRIEF_TAB 0
483 #define TEXT_SCROLL_UP 2
484 #define TEXT_SCROLL_DOWN 3
485 #define REPLAY_MISSION 4
486 #define RECOMMENDATIONS 5
487 #define FIRST_STAGE 6
491 #define MULTI_PINFO_POPUP 10
492 #define MULTI_KICK 11
493 #define MEDALS_BUTTON 12
494 #define PLAYER_SCROLL_UP 13
495 #define PLAYER_SCROLL_DOWN 14
496 #define HELP_BUTTON 15
497 #define OPTIONS_BUTTON 16
498 #define ACCEPT_BUTTON 17
503 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
504 "PleaseWait", // GR_640
505 "2_PleaseWait" // GR_1024
511 char text[NAME_LENGTH+1]; // name of ship type with a colon
512 int num; // how many ships of this type player has killed
513 } debrief_stats_kill_info;
516 int net_player_index; // index into Net_players[] array
517 int rank_bitmap; // bitmap id for rank
518 char callsign[CALLSIGN_LEN];
519 } debrief_multi_list_info;
521 ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
523 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
524 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
525 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
526 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
527 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
528 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
529 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
530 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
531 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
532 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
533 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
534 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
535 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
536 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
537 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
538 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
539 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
540 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
543 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
544 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
545 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
546 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
547 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
548 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
549 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
550 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
551 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
552 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
553 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
554 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
555 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
556 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
557 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
558 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
559 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
560 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
565 #define NUM_DEBRIEF_TEXT 10
566 #define MP_TEXT_INDEX_1 4
567 #define MP_TEXT_INDEX_2 5
568 #define MP_TEXT_INDEX_3 6
569 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
571 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
572 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
573 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
574 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
575 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
576 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
577 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
578 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
579 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
580 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
583 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
584 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
585 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
586 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
587 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
588 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
589 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
590 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
591 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
592 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
597 char Debrief_current_callsign[CALLSIGN_LEN+10];
598 player *Debrief_player;
600 static UI_WINDOW Debrief_ui_window;
601 static UI_BUTTON List_region;
602 static int Background_bitmap; // bitmap for the background of the debriefing
603 static int Award_bg_bitmap;
604 static int Debrief_multi_loading_bitmap;
605 static int Rank_bitmap;
606 static int Medal_bitmap;
607 static int Badge_bitmap;
608 static int Wings_bitmap;
609 static int Crest_bitmap;
610 //static int Rank_text_bitmap;
611 //static int Medal_text_bitmap;
612 //static int Badge_text_bitmap;
614 static int Debrief_accepted;
615 static int Turned_traitor;
616 static int Must_replay_mission;
618 static int Current_mode;
620 static int Recommend_active;
621 static int Award_active;
622 static int Text_offset;
623 static int Num_text_lines = 0;
624 static int Num_debrief_lines = 0;
625 static int Num_normal_debrief_lines = 0;
626 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
627 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
629 static int Debrief_inited = 0;
630 static int New_stage;
631 static int Current_stage;
632 static int Num_stages;
633 static int Num_debrief_stages;
634 static int Stage_voice;
636 static int Multi_list_size;
637 static int Multi_list_offset;
639 int Debrief_multi_stages_loaded = 0;
640 int Debrief_multi_voice_loaded = 0;
642 // static int Debrief_voice_ask_for_cd;
644 // voice id's for debriefing text
645 static int Debrief_voices[MAX_DEBRIEF_STAGES];
647 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
648 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
649 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
651 // pointer used for getting to debriefing information
652 debriefing Traitor_debriefing; // used when player is a traitor
654 // pointers to the active stages for this debriefing
655 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
656 static debrief_stage Promotion_stage, Badge_stage;
657 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
658 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
659 int Multi_list_select;
661 // flag indicating if we should display info for the given player (in multiplayer)
662 int Debrief_should_show_popup = 1;
664 // already shown skip mission popup?
665 static int Debrief_skip_popup_already_shown = 0;
667 void debrief_text_init();
668 void debrief_accept(int ok_to_post_start_game_event = 1);
669 void debrief_kick_selected_player();
672 // promotion voice selection stuff
673 #define NUM_VOLITION_CAMPAIGNS 1
675 char campaign_name[32];
677 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
679 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
680 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
684 // data for which voice goes w/ which mission
685 typedef struct voice_map {
686 char mission_file[32];
690 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
691 { // FreeSpace2 campaign
723 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
725 { "loop1-1.fs2", 4 },
726 { "loop1-2.fs2", 4 },
727 { "loop1-3.fs2", 5 },
728 { "loop2-1.fs2", 4 },
733 #define DB_AWARD_WINGS 0
734 #define DB_AWARD_MEDAL 1
735 #define DB_AWARD_SOC 2
736 #define DB_AWARD_RANK 3
737 #define DB_AWARD_BADGE 4
738 #define DB_AWARD_BG 5
739 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
758 #define AWARD_TEXT_MAX_LINES 5
759 #define AWARD_TEXT_MAX_LINE_LENGTH 128
760 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
761 int Debrief_award_text_num_lines = 0;
765 // prototypes, you know you love 'em
766 void debrief_add_award_text(char *str);
767 void debrief_award_text_clear();
772 char *debrief_tooltip_handler(char *str)
774 if (!stricmp(str, NOX("@.Medal"))) {
776 return XSTR( "Medal", 435);
779 } else if (!stricmp(str, NOX("@.Rank"))) {
781 return XSTR( "Rank", 436);
784 } else if (!stricmp(str, NOX("@.Badge"))) {
786 return XSTR( "Badge", 437);
789 } else if (!stricmp(str, NOX("@Medal"))) {
790 if (Medal_bitmap >= 0){
791 return Medals[Player->stats.m_medal_earned].name;
794 } else if (!stricmp(str, NOX("@Rank"))) {
795 if (Rank_bitmap >= 0){
796 return Ranks[Promoted].name;
799 } else if (!stricmp(str, NOX("@Badge"))) {
800 if (Badge_bitmap >= 0){
801 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
808 // initialize the array of handles to the different voice streams
809 void debrief_voice_init()
813 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
814 Debrief_voices[i] = -1;
818 void debrief_load_voice_file(int voice_num, char *name)
820 int load_attempts = 0;
823 if ( load_attempts++ > 5 ) {
827 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
828 if ( Debrief_voices[voice_num] >= 0 ) {
832 // Don't bother to ask for the CD in multiplayer
833 if ( Game_mode & GM_MULTIPLAYER ) {
837 // couldn't load voice, ask user to insert CD (if necessary)
839 // if ( Debrief_voice_ask_for_cd ) {
840 // if ( game_do_cd_check() == 0 ) {
841 // Debrief_voice_ask_for_cd = 0;
848 // open and pre-load the stream buffers for the different voice streams
849 void debrief_voice_load_all()
853 // Debrief_voice_ask_for_cd = 1;
855 for ( i=0; i<Num_debrief_stages; i++ ) {
856 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
859 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
860 debrief_load_voice_file(i, Debrief_stages[i]->voice);
861 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
866 // close all the briefing voice streams
867 void debrief_voice_unload_all()
871 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
872 if ( Debrief_voices[i] != -1 ) {
873 audiostream_close_file(Debrief_voices[i], 0);
874 Debrief_voices[i] = -1;
879 // start playback of the voice for a particular briefing stage
880 void debrief_voice_play()
882 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
886 // no more stages? We are done then.
887 if (Stage_voice >= Num_debrief_stages){
891 // if in delayed start, see if delay has elapsed and start voice if so
892 if (Debrief_cue_voice) {
893 if (!timestamp_elapsed(Debrief_cue_voice)){
897 Stage_voice++; // move up to next voice
898 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
899 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
900 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
906 // see if voice is still playing. If so, do nothing yet.
907 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
911 // set voice to play in a little while from now.
912 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
915 // stop playback of the voice for a particular briefing stage
916 void debrief_voice_stop()
918 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
921 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
925 // function to deal with inserting possible promition and badge stages into the debriefing
927 void debrief_multi_fixup_stages()
931 // possibly insert the badge stage first, them the promotion stage since they are
932 // inserted at the front of the debrief stages.
933 if ( Badge_bitmap >= 0 ) {
934 // move all stages forward one. Don't
935 for ( i = Num_debrief_stages; i > 0; i-- ) {
936 Debrief_stages[i] = Debrief_stages[i-1];
938 Debrief_stages[0] = &Badge_stage;
939 Num_debrief_stages++;
942 if ( Promoted >= 0) {
943 // move all stages forward one
944 for ( i = Num_debrief_stages; i > 0; i-- ) {
945 Debrief_stages[i] = Debrief_stages[i-1];
947 Debrief_stages[0] = &Promotion_stage;
948 Num_debrief_stages++;
953 // function called from multiplayer clients to set up the debriefing information for them
954 // (sent from the server).
955 void debrief_set_multi_clients( int stage_count, int active_stages[] )
959 // set up the right briefing for this guy
960 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
961 Debriefing = &Debriefings[Net_player->p_info.team];
963 Debriefing = &Debriefings[0];
966 // see if this client was promoted -- if so, then add the first stage.
967 Num_debrief_stages = 0;
969 // set the pointers to the debriefings for this client
970 for (i = 0; i < stage_count; i++) {
971 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
974 Debrief_multi_stages_loaded = 1;
977 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
978 // information to all clients after leaving this screen.
979 void debrief_multi_server_stuff()
981 debriefing *debriefp;
983 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
984 int i, j, num_stages, stage_count[MAX_TEAMS];
986 memset( stage_active, 0, sizeof(stage_active) );
988 for (i=0; i<Num_teams; i++) {
989 debriefp = &Debriefings[i];
991 stages[i] = stage_active[i];
992 for (j=0; j<debriefp->num_stages; j++) {
993 if ( eval_sexp(debriefp->stages[j].formula) ) {
994 stage_active[i][num_stages] = j;
999 stage_count[i] = num_stages;
1002 // if we're in campaign mode, evaluate campaign stuff
1003 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1004 multi_campaign_eval_debrief();
1007 // send the information to all clients.
1008 send_debrief_info( stage_count, stages );
1012 // --------------------------------------------------------------------------------------
1013 // debrief_set_stages_and_multi_stuff()
1015 // Set up the active stages for this debriefing
1017 // returns: number of active debriefing stages
1019 int debrief_set_stages_and_multi_stuff()
1022 debriefing *debriefp;
1024 if ( MULTIPLAYER_CLIENT ) {
1028 Num_debrief_stages = 0;
1030 if ( Game_mode & GM_MULTIPLAYER ) {
1031 debrief_multi_server_stuff();
1034 // check to see if player is a traitor (looking at his team). If so, use the special
1035 // traitor debriefing. Only done in single player
1036 debriefp = Debriefing;
1037 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1038 if (Player_ship->team == TEAM_TRAITOR)
1039 debriefp = &Traitor_debriefing;
1042 Num_debrief_stages = 0;
1043 if (Promoted >= 0) {
1044 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1047 if (Badge_bitmap >= 0) {
1048 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1051 for (i=0; i<debriefp->num_stages; i++) {
1052 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1053 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1057 return Num_debrief_stages;
1060 // init the buttons that are specific to the debriefing screen
1061 void debrief_buttons_init()
1066 for ( i=0; i<NUM_BUTTONS; i++ ) {
1067 b = &Buttons[gr_screen.res][i];
1068 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1069 // set up callback for when a mouse first goes over a button
1070 b->button.set_highlight_action( common_play_highlight_sound );
1071 b->button.set_bmaps(b->filename);
1072 b->button.link_hotspot(b->hotspot);
1076 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1077 // multiplayer specific text
1078 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1079 // only add if in multiplayer mode
1080 if(Game_mode & GM_MULTIPLAYER){
1081 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1086 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1090 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1091 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1092 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1093 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1094 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1095 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1096 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1097 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1099 // if in multiplayer, disable the button for all players except the host
1100 // also disable for squad war matches
1101 if(Game_mode & GM_MULTIPLAYER){
1102 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1103 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1108 // --------------------------------------------------------------------------------------
1109 // debrief_ui_init()
1111 void debrief_ui_init()
1113 // init ship selection masks and buttons
1114 common_set_interface_palette("DebriefPalette"); // set the interface palette
1115 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1116 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1117 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1118 debrief_buttons_init();
1120 // load in help overlay bitmap
1121 help_overlay_load(DEBRIEFING_OVERLAY);
1122 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1124 if ( Game_mode & GM_MULTIPLAYER ) {
1125 // close down any old instances of the chatbox
1128 // create the new one
1130 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1131 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);
1134 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1137 if ( Background_bitmap < 0 ) {
1138 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1141 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1142 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1145 // sets Promotion_stage.voice
1146 // defaults to number 9 (Petrarch) for non-volition missions
1147 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1148 void debrief_choose_promotion_voice()
1152 if(Campaign.current_mission < 0){
1153 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1157 // search thru all official campaigns for our current campaign
1158 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1159 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1160 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1161 // now search thru the mission filenames,
1162 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1163 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1164 // found it! set the persona and bail
1165 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1173 // default to petrarch
1174 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1177 // sets Promotion_stage.voice
1178 // defaults to number 9 (Petrarch) for non-volition missions
1179 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1180 void debrief_choose_badge_voice()
1184 if(Campaign.current_mission < 0){
1185 // default to petrarch
1186 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1189 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1190 // search thru all official campaigns for our current campaign
1191 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1192 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1193 // now search thru the mission filenames,
1194 for (j=0; j<Campaign.num_missions; j++) {
1195 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1196 // found it! set the persona and bail
1197 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1205 // default to petrarch
1206 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1210 void debrief_award_init()
1222 // be sure there are no old award texts floating around
1223 debrief_award_text_clear();
1225 // handle medal earned
1226 if (Player->stats.m_medal_earned != -1) {
1227 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1229 if ( Player->stats.medals[13] > 1 ) {
1234 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1235 Wings_bitmap = bm_load(buf);
1237 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1238 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1240 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1241 Medal_bitmap = bm_load(buf);
1244 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1247 // handle promotions
1248 if ( Player->stats.m_promotion_earned != -1 ) {
1249 Promoted = Player->stats.m_promotion_earned;
1250 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1251 Rank_bitmap = bm_load(buf);
1253 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1254 Promotion_stage.new_recommendation_text = NULL;
1256 // choose appropriate promotion voice for this mission
1257 debrief_choose_promotion_voice();
1259 debrief_add_award_text(Ranks[Promoted].name);
1262 // handle badge earned
1263 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1264 if ( Player->stats.m_badge_earned != -1 ) {
1265 i = Player->stats.m_badge_earned;
1266 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1267 Badge_bitmap = bm_load(buf);
1269 Badge_stage.new_text = Badge_info[i].promotion_text;
1270 Badge_stage.new_recommendation_text = NULL;
1272 // choose appropriate voice
1273 debrief_choose_badge_voice();
1275 debrief_add_award_text(Medals[Badge_index[i]].name);
1278 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1285 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1286 // mission a traitor. The same debriefing always gets played
1287 void debrief_traitor_init()
1289 static int inited = 0;
1292 debriefing *debrief;
1293 debrief_stage *stagep;
1297 if ((rval = setjmp(parse_abort)) != 0) {
1298 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1301 read_file_text("traitor.tbl");
1305 // open localization
1308 // simplied form of the debriefing stuff.
1309 debrief = &Traitor_debriefing;
1310 required_string("#Debriefing_info");
1312 required_string("$Num stages:");
1313 stuff_int(&debrief->num_stages);
1314 Assert(debrief->num_stages == 1);
1317 stagep = &debrief->stages[stage_num++];
1318 required_string("$Formula:");
1319 stagep->formula = get_sexp_main();
1320 required_string("$multi text");
1321 if ( Fred_running ) {
1322 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1324 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1326 required_string("$Voice:");
1327 char traitor_voice_file[NAME_LENGTH];
1328 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1330 // DKA 9/13/99 Only 1 traitor msg for FS2
1331 // if ( Player->on_bastion ) {
1332 // strcpy(stagep->voice, NOX("3_"));
1334 // strcpy(stagep->voice, NOX("1_"));
1337 strcat(stagep->voice, traitor_voice_file);
1339 required_string("$Recommendation text:");
1340 if ( Fred_running ) {
1341 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1343 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1347 // close localization
1351 // disable the accept button if in single player and I am a traitor
1352 Debrief_accepted = 0;
1353 Turned_traitor = Must_replay_mission = 0;
1354 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1355 if (Player_ship->team == TEAM_TRAITOR){
1359 if (Campaign.next_mission == Campaign.current_mission){
1360 Must_replay_mission = 1;
1364 if (Turned_traitor || Must_replay_mission) {
1365 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1367 // kill off any stats
1368 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1369 scoring_level_init( &Player->stats );
1373 // initialization for listing of players in game
1374 void debrief_multi_list_init()
1376 Multi_list_size = 0; // number of net players to choose from
1377 Multi_list_offset = 0;
1379 Multi_list_select = -1;
1381 if ( !(Game_mode & GM_MULTIPLAYER) )
1384 debrief_rebuild_player_list();
1386 // switch stats display to this newly selected player
1387 set_player_stats(Multi_list[0].net_player_index);
1388 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1389 Debrief_player = Player;
1392 void debrief_multi_list_scroll_up()
1394 // if we're at the beginning of the list, don't do anything
1395 if(Multi_list_offset == 0){
1396 gamesnd_play_iface(SND_GENERAL_FAIL);
1400 // otherwise scroll up
1401 Multi_list_offset--;
1402 gamesnd_play_iface(SND_USER_SELECT);
1405 void debrief_multi_list_scroll_down()
1407 // if we can scroll down no further
1408 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1409 gamesnd_play_iface(SND_GENERAL_FAIL);
1412 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1413 gamesnd_play_iface(SND_GENERAL_FAIL);
1417 // otherwise scroll down
1418 Multi_list_offset++;
1419 gamesnd_play_iface(SND_USER_SELECT);
1422 // draw the connected net players
1423 void debrief_multi_list_draw()
1425 int y, z, font_height,idx;
1426 char str[CALLSIGN_LEN+5];
1429 font_height = gr_get_font_height();
1431 // if we currently have no item picked, pick a reasonable one
1432 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1433 // select the entry which corresponds to the local player
1434 Multi_list_select = 0;
1435 for(idx=0;idx<Multi_list_size;idx++){
1436 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1437 Multi_list_select = idx;
1439 // switch stats display to this newly selected player
1440 set_player_stats(Multi_list[idx].net_player_index);
1441 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1442 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1448 // draw the list itself
1450 z = Multi_list_offset;
1451 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1452 np = &Net_players[Multi_list[z].net_player_index];
1454 if (z >= Multi_list_size){
1457 // set the proper text color for the highlight
1458 if(np->flags & NETINFO_FLAG_GAME_HOST){
1459 if(Multi_list_select == z){
1460 gr_set_color_fast(&Color_text_active_hi);
1462 gr_set_color_fast(&Color_bright);
1465 if(Multi_list_select == z){
1466 gr_set_color_fast(&Color_text_active);
1468 gr_set_color_fast(&Color_text_normal);
1472 // blit the proper indicator - skipping observers
1473 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1474 if(Netgame.type_flags & NG_TYPE_TEAM){
1476 if(np->p_info.team == 0){
1477 // draw his "selected" icon
1478 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1479 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1480 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1482 // draw his "normal" icon
1483 else if(Multi_common_icons[MICON_TEAM0] != -1){
1484 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1485 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1487 } else if(np->p_info.team == 1){
1488 // draw his "selected" icon
1489 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1490 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1491 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1493 // draw his "normal" icon
1494 else if(Multi_common_icons[MICON_TEAM1] != -1){
1495 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1496 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1500 // draw the team 0 selected icon
1501 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1502 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1503 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1508 strcpy(str,Multi_list[z].callsign);
1509 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)){
1510 strcat(str,XSTR( "(O)", 438));
1514 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1521 void debrief_kick_selected_player()
1523 if(Multi_list_select >= 0){
1524 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1525 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1529 // get optional mission popup text
1530 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1532 Assert(buffer != NULL);
1535 if (mission_loop_desc == NULL) {
1536 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1537 mprintf(("No mission loop description avail"));
1539 strcpy(buffer, mission_loop_desc);
1542 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1545 // what to do when the accept button is hit
1546 void debrief_accept(int ok_to_post_start_game_event)
1550 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1554 if (Game_mode & GM_MULTIPLAYER) {
1558 if (Player_ship->team == TEAM_TRAITOR){
1559 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1560 }/* else if (Cheats_enabled) {
1561 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1563 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1566 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1568 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1569 } else if ( z == 1 ) {
1570 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1576 Debrief_accepted = 1;
1577 // save mission stats
1578 if (Game_mode & GM_MULTIPLAYER) {
1579 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1580 // as well as doing stats transfers, etc.
1581 multi_debrief_accept_hit();
1585 int play_commit_sound = 1;
1586 // only write the player's stats if he's accepted
1588 // if we are just playing a single mission, then don't do many of the things
1589 // that need to be done. Nothing much should happen when just playing a single
1590 // mission that isn't in a campaign.
1591 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1593 // check for possible mission loop
1594 // check for (1) mission loop available, (2) dont have to repeat last mission
1595 if(!(Game_mode & GM_MULTIPLAYER)){
1596 int cur = Campaign.current_mission;
1597 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1598 if (Campaign.missions[cur].has_mission_loop) {
1599 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1602 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1605 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1607 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1609 Campaign.loop_enabled = 1;
1610 Campaign.next_mission = Campaign.loop_mission;
1619 if(ok_to_post_start_game_event){
1620 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1622 play_commit_sound = 0;
1625 // continue as normal
1628 mission_campaign_mission_over();
1630 // check to see if we are out of the loop now
1631 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1632 Campaign.loop_enabled = 0;
1635 // check if campaign is over
1636 if ( Campaign.next_mission == -1 ) {
1637 #if defined(FS2_DEMO) || defined(OEM_BUILD)
1638 gameseq_post_event(GS_EVENT_END_DEMO);
1640 gameseq_post_event(GS_EVENT_MAIN_MENU);
1643 if ( ok_to_post_start_game_event ) {
1645 if(game_do_cd_mission_check(Game_current_mission_filename)){
1646 gameseq_post_event(GS_EVENT_START_GAME);
1648 gameseq_post_event(GS_EVENT_MAIN_MENU);
1651 play_commit_sound = 0;
1656 gameseq_post_event(GS_EVENT_MAIN_MENU);
1659 if ( play_commit_sound ) {
1660 gamesnd_play_iface(SND_COMMIT_PRESSED);
1667 void debrief_next_tab()
1669 New_mode = Current_mode + 1;
1670 if (New_mode >= NUM_TABS)
1674 void debrief_prev_tab()
1676 New_mode = Current_mode - 1;
1678 New_mode = NUM_TABS - 1;
1681 // --------------------------------------------------------------------------------------
1682 // debrief_next_stage()
1684 void debrief_next_stage()
1686 if (Current_stage < Num_stages - 1) {
1687 New_stage = Current_stage + 1;
1688 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1691 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1694 // --------------------------------------------------------------------------------------
1695 // debrief_prev_stage()
1697 void debrief_prev_stage()
1699 if (Current_stage) {
1700 New_stage = Current_stage - 1;
1701 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1704 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1707 // --------------------------------------------------------------------------------------
1708 // debrief_first_stage()
1709 void debrief_first_stage()
1711 if (Current_stage) {
1713 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1716 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1719 // --------------------------------------------------------------------------------------
1720 // debrief_last_stage()
1721 void debrief_last_stage()
1723 if (Current_stage != Num_stages - 1) {
1724 New_stage = Num_stages - 1;
1725 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1728 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1731 // draw what stage number the debriefing is on
1732 void debrief_render_stagenum()
1740 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1741 gr_get_string_size(&w, NULL, buf);
1742 gr_set_color_fast(&Color_bright_blue);
1743 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1744 gr_set_color_fast(&Color_white);
1747 // render the mission time at the specified y location
1748 void debrief_render_mission_time(int y_loc)
1752 game_format_time(Missiontime, time_str);
1753 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1754 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1757 // render out the debriefing text to the scroll window
1758 void debrief_render()
1760 int y, z, font_height;
1762 if ( Num_stages <= 0 )
1765 font_height = gr_get_font_height();
1767 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]);
1770 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1771 if (z >= Num_text_lines)
1774 if (Text_type[z] == TEXT_TYPE_NORMAL)
1775 gr_set_color_fast(&Color_white);
1777 gr_set_color_fast(&Color_bright_red);
1780 gr_string(0, y, Text[z]);
1789 // render out the stats info to the scroll window
1791 void debrief_stats_render()
1793 int i, y, font_height;
1795 gr_set_color_fast(&Color_blue);
1796 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]);
1797 gr_string(0, 0, Debrief_current_callsign);
1798 font_height = gr_get_font_height();
1801 switch ( Current_stage ) {
1802 case DEBRIEF_MISSION_STATS:
1803 i = Current_stage - 1;
1807 gr_set_color_fast(&Color_white);
1809 // display mission completion time
1810 debrief_render_mission_time(y);
1813 show_stats_label(i, 0, y, font_height);
1814 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1816 case DEBRIEF_ALLTIME_STATS:
1817 i = Current_stage - 1;
1821 gr_set_color_fast(&Color_white);
1822 show_stats_label(i, 0, y, font_height);
1823 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1826 case DEBRIEF_ALLTIME_KILLS:
1827 case DEBRIEF_MISSION_KILLS:
1828 gr_set_color_fast(&Color_white);
1830 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1831 if (i >= Num_text_lines)
1835 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1836 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
1838 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
1841 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
1842 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
1849 if (Num_text_lines == 2) {
1850 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1851 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
1853 gr_printf(0, y, XSTR( "(No ship kills)", 450));
1866 // do action for when the replay button is pressed
1867 void debrief_replay_pressed()
1869 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
1871 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));
1878 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
1879 gamesnd_play_iface(SND_COMMIT_PRESSED);
1882 // -------------------------------------------------------------------
1883 // debrief_redraw_pressed_buttons()
1885 // Redraw any debriefing buttons that are pressed down. This function is needed
1886 // since we sometimes need to draw pressed buttons last to ensure the entire
1887 // button gets drawn (and not overlapped by other buttons)
1889 void debrief_redraw_pressed_buttons()
1894 for ( i=0; i<NUM_BUTTONS; i++ ) {
1895 b = &Buttons[gr_screen.res][i].button;
1896 // don't draw the recommendations button if we're in stats mode
1897 if ( b->button_down() ) {
1903 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
1905 void debrief_button_pressed(int num)
1909 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
1910 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
1911 if (num != Current_mode){
1912 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1917 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
1918 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
1919 if (num != Current_mode){
1920 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1925 case TEXT_SCROLL_UP:
1928 gamesnd_play_iface(SND_SCROLL);
1930 gamesnd_play_iface(SND_GENERAL_FAIL);
1934 case TEXT_SCROLL_DOWN:
1935 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
1937 gamesnd_play_iface(SND_SCROLL);
1939 gamesnd_play_iface(SND_GENERAL_FAIL);
1943 case REPLAY_MISSION:
1944 if(Game_mode & GM_MULTIPLAYER){
1945 multi_debrief_replay_hit();
1947 debrief_replay_pressed();
1951 case RECOMMENDATIONS:
1952 gamesnd_play_iface(SND_USER_SELECT);
1953 Recommend_active = !Recommend_active;
1954 debrief_text_init();
1958 debrief_first_stage();
1962 debrief_prev_stage();
1966 debrief_next_stage();
1970 debrief_last_stage();
1974 gamesnd_play_iface(SND_HELP_PRESSED);
1975 launch_context_help();
1978 case OPTIONS_BUTTON:
1979 gamesnd_play_iface(SND_SWITCH_SCREENS);
1980 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
1988 gamesnd_play_iface(SND_SWITCH_SCREENS);
1989 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
1992 case PLAYER_SCROLL_UP:
1993 debrief_multi_list_scroll_up();
1996 case PLAYER_SCROLL_DOWN:
1997 debrief_multi_list_scroll_down();
2000 case MULTI_PINFO_POPUP:
2001 Debrief_should_show_popup = 1;
2005 debrief_kick_selected_player();
2010 void debrief_setup_ship_kill_stats(int stage_num)
2014 debrief_stats_kill_info *kill_info;
2016 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2017 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2020 Assert(Debrief_player != NULL);
2022 // kill_ar points to an array of MAX_SHIP_TYPE ints
2023 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2024 kill_arr = Debrief_player->stats.m_okKills;
2026 kill_arr = Debrief_player->stats.kills;
2030 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2032 // code used to add in mission kills, but the new system assumes that the player will accept, so
2033 // all time stats already have mission stats added in.
2034 if ( kill_arr[i] <= 0 ){
2039 kill_info = &Debrief_stats_kills[Num_text_lines++];
2041 kill_info->num = kill_arr[i];
2043 strcpy(kill_info->text, Ship_info[i].name);
2044 strcat(kill_info->text, NOX(":"));
2047 Num_text_lines += 2;
2050 // Iterate through the debriefing buttons, checking if they are pressed
2051 void debrief_check_buttons()
2055 for ( i=0; i<NUM_BUTTONS; i++ ) {
2056 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2057 debrief_button_pressed(i);
2061 if ( !(Game_mode & GM_MULTIPLAYER) )
2064 if (List_region.pressed()) {
2065 List_region.get_mouse_pos(NULL, &y);
2066 z = Multi_list_offset + y / gr_get_font_height();
2067 if ((z >= 0) && (z < Multi_list_size)) {
2068 // switch stats display to this newly selected player
2069 set_player_stats(Multi_list[z].net_player_index);
2070 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2071 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2072 Multi_list_select = z;
2073 debrief_setup_ship_kill_stats(Current_stage);
2074 gamesnd_play_iface(SND_USER_SELECT);
2078 // if the player was double clicked on - we should popup a player info popup
2080 if (List_region.double_clicked()) {
2081 Debrief_should_show_popup = 1;
2086 void debrief_text_stage_init(char *src, int type)
2088 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2089 char line[MAX_DEBRIEF_LINE_LEN];
2090 char *p_str[MAX_DEBRIEF_LINES];
2092 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2093 Assert(n_lines >= 0);
2095 // if you hit this, you proba
2096 if(n_lines >= MAX_DEBRIEF_LINES){
2097 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2100 for ( i=0; i<n_lines; i++ ) {
2101 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2102 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2103 strncpy(line, p_str[i], n_chars[i]);
2104 line[n_chars[i]] = 0;
2105 drop_white_space(line);
2106 Text_type[Num_text_lines] = type;
2107 Text[Num_text_lines++] = strdup(line);
2113 void debrief_free_text()
2117 for (i=0; i<Num_debrief_lines; i++)
2121 Num_debrief_lines = 0;
2124 // setup the debriefing text lines for rendering
2125 void debrief_text_init()
2130 // release old text lines first
2131 debrief_free_text();
2132 Num_text_lines = Text_offset = 0;
2134 if (Current_mode == DEBRIEF_TAB) {
2135 for (i=0; i<Num_debrief_stages; i++) {
2137 Text[Num_text_lines++] = NULL; // add a blank line between stages
2139 src = Debrief_stages[i]->new_text;
2141 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2143 if (Recommend_active) {
2144 src = Debrief_stages[i]->new_recommendation_text;
2145 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2146 src = XSTR( "We have no recommendations for you.", 1054);
2149 Text[Num_text_lines++] = NULL;
2150 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2156 Num_debrief_lines = Num_text_lines;
2160 // not in debriefing mode, must be in stats mode
2162 debrief_setup_ship_kill_stats(Current_stage);
2166 // --------------------------------------------------------------------------------------
2170 Assert(!Debrief_inited);
2171 // Campaign.loop_enabled = 0;
2172 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2174 // set up the right briefing for this guy
2175 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2176 Debriefing = &Debriefings[Net_player->p_info.team];
2178 Debriefing = &Debriefings[0];
2181 // no longer is mission
2182 Game_mode &= ~(GM_IN_MISSION);
2186 New_mode = DEBRIEF_TAB;
2187 Recommend_active = Award_active = 0;
2192 Debrief_cue_voice = 0;
2193 Num_text_lines = Num_debrief_lines = 0;
2194 Debrief_first_voice_flag = 1;
2196 Debrief_multi_voice_loaded = 0;
2198 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2199 // MUST store goals and events first - may be used to evaluate next mission
2200 // store goals and events
2201 mission_campaign_store_goals_and_events();
2203 // evaluate next mission
2204 mission_campaign_eval_next_mission();
2207 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2209 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2210 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2213 // call scoring level close for my stats. Needed for award_init. The stats will
2214 // be backed out if used chooses to replace them.
2215 scoring_level_close();
2217 debrief_ui_init(); // init UI items
2218 debrief_award_init();
2220 debrief_voice_init();
2221 debrief_multi_list_init();
2222 // rank_bitmaps_clear();
2223 // rank_bitmaps_load();
2225 strcpy(Debrief_current_callsign, Player->callsign);
2226 Debrief_player = Player;
2227 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2229 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2230 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2231 // info directly from the server.
2232 if ( !MULTIPLAYER_CLIENT ) {
2233 debrief_set_stages_and_multi_stuff();
2235 if ( Num_debrief_stages <= 0 ) {
2236 Num_debrief_stages = 0;
2238 debrief_voice_load_all();
2241 // multiplayer client may have already received their debriefing info. If they have not,
2242 // then set the num debrief stages to 0
2243 if ( !Debrief_multi_stages_loaded ) {
2244 Num_debrief_stages = 0;
2249 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2250 common_music_init(SCORE_DEBRIEF_SUCCESS);
2252 common_music_init(SCORE_DEBRIEF_FAIL);
2256 // start up the appropriate music
2257 if (Campaign.next_mission == Campaign.current_mission) {
2258 // you failed the mission because you suck, so you get the suck music
2259 common_music_init(SCORE_DEBRIEF_FAIL);
2260 } else if (mission_goals_met()) {
2261 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2262 common_music_init(SCORE_DEBRIEF_SUCCESS);
2264 // you somehow passed the mission, so you get a little something for your efforts.
2265 common_music_init(SCORE_DEBRIEF_AVERAGE);
2268 if (Campaign.next_mission == Campaign.current_mission) {
2269 // better luck next time, increase his retries
2270 Player->failures_this_session++;
2272 // clear his retries info regardless of whether or not he accepts
2273 Player->failures_this_session = 0;
2276 if (Game_mode & GM_MULTIPLAYER) {
2277 multi_debrief_init();
2279 // if i'm not the host of the game, disable the multi kick button
2280 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2281 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2284 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2285 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2286 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2287 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2288 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2289 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2290 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2291 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2294 if (!Award_active) {
2295 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2296 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2299 Debrief_skip_popup_already_shown = 0;
2304 // --------------------------------------------------------------------------------------
2306 void debrief_close()
2310 Assert(Debrief_inited);
2312 // if the mission wasn't accepted, clear out my stats
2313 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2314 // are a little bit different
2315 if (Game_mode & GM_MULTIPLAYER) {
2316 // if stats weren't accepted, backout my own stats
2317 if (multi_debrief_stats_accept_code() != 1) {
2318 if(MULTIPLAYER_MASTER){
2319 for(idx=0; idx<MAX_PLAYERS; idx++){
2320 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2321 scoring_backout_accept(&Net_players[idx].player->stats);
2325 scoring_backout_accept( &Player->stats );
2330 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2331 scoring_backout_accept( &Player->stats );
2335 // if dude passed the misson and accepted, reset his show skip popup flag
2336 if (Debrief_accepted) {
2337 Player->show_skip_popup = 1;
2340 if (Num_debrief_lines) {
2341 for (i=0; i<Num_debrief_lines; i++){
2348 // unload the overlay bitmap
2349 // help_overlay_unload(DEBRIEFING_OVERLAY);
2351 // clear out award text
2352 Debrief_award_text_num_lines = 0;
2354 debrief_voice_unload_all();
2355 common_music_close();
2358 // rank_bitmaps_release();
2361 if (Background_bitmap >= 0){
2362 bm_unload(Background_bitmap);
2365 if (Award_bg_bitmap >= 0){
2366 bm_unload(Award_bg_bitmap);
2369 if (Rank_bitmap >= 0){
2370 bm_unload(Rank_bitmap);
2373 if (Medal_bitmap >= 0){
2374 bm_unload(Medal_bitmap);
2377 if (Badge_bitmap >= 0){
2378 bm_unload(Badge_bitmap);
2381 if (Wings_bitmap >= 0) {
2382 bm_unload(Wings_bitmap);
2385 if (Crest_bitmap >= 0) {
2386 bm_unload(Crest_bitmap);
2389 Debrief_ui_window.destroy();
2390 common_free_interface_palette(); // restore game palette
2393 if (Game_mode & GM_MULTIPLAYER){
2394 multi_debrief_close();
2402 // handle keypresses in debriefing
2403 void debrief_do_keys(int new_k)
2410 case KEY_SHIFTED | KEY_TAB:
2418 // multiplayer accept popup is a little bit different
2419 if (Game_mode & GM_MULTIPLAYER) {
2420 multi_debrief_esc_hit();
2422 // display the normal debrief popup
2424 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2425 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2426 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2427 if (choice == 1) { // accept and continue on
2429 gameseq_post_event(GS_EVENT_MAIN_MENU);
2435 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2436 // need to popup saying that mission was a failure and must be replayed
2437 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));
2442 // Return to Main Hall
2443 gameseq_post_event(GS_EVENT_END_GAME);
2453 void debrief_draw_award_text()
2455 int start_y, curr_y, i, x, sw;
2456 int fh = gr_get_font_height();
2457 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];
2459 // vertically centered within field
2460 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);
2464 for (i=0; i<Debrief_award_text_num_lines; i++) {
2465 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2466 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2467 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2468 gr_set_color_fast(&Color_white);
2469 gr_string(x, curr_y, Debrief_award_text[i]);
2471 // adjust y pos, including a little extra between the "pairs"
2473 if ((i == 1) || (i == 3)) {
2474 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2479 // clears out text array so we dont have old award text showing up on new awards.
2480 void debrief_award_text_clear() {
2483 Debrief_award_text_num_lines = 0;
2484 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2485 //Debrief_award_text[i][0] = 0;
2486 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2490 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2491 void debrief_add_award_text(char *str)
2493 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2494 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2499 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];
2502 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2504 // maybe translate for displaying
2506 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2509 Debrief_award_text_num_lines++;
2511 // if its too long, split once ONLY
2512 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2513 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2514 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2515 if (line2 != NULL) {
2516 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2518 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2522 // called once per frame to drive all the input reading and rendering
2523 void debrief_do_frame(float frametime)
2526 char *please_wait_str = XSTR("Please Wait", 1242);
2530 Assert(Debrief_inited);
2532 // first thing is to load the files
2533 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2534 // draw the background, etc
2535 GR_MAYBE_CLEAR_RES(Background_bitmap);
2536 if (Background_bitmap >= 0) {
2537 gr_set_bitmap(Background_bitmap);
2541 Debrief_ui_window.draw();
2543 if ( Debrief_multi_loading_bitmap > -1 ){
2544 gr_set_bitmap(Debrief_multi_loading_bitmap);
2545 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2548 // draw "Please Wait"
2549 gr_set_color_fast(&Color_normal);
2551 gr_get_string_size(&str_w, &str_h, please_wait_str);
2552 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2557 // make sure we run the debrief do frame
2558 if (Game_mode & GM_MULTIPLAYER) {
2559 multi_debrief_do_frame();
2564 int keypress = game_check_key();
2565 if(keypress == KEY_ESC){
2567 multi_quit_game(PROMPT_CLIENT);
2573 // if multiplayer client, and not loaded voice, then load it
2574 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2575 debrief_multi_fixup_stages();
2576 debrief_voice_load_all();
2577 Debrief_multi_voice_loaded = 1;
2580 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2581 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2582 Debrief_ui_window.set_ignore_gadgets(1);
2585 k = chatbox_process();
2586 if ( Game_mode & GM_NORMAL ) {
2587 new_k = Debrief_ui_window.process(k);
2589 new_k = Debrief_ui_window.process(k, 0);
2592 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2593 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2594 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2595 Debrief_ui_window.set_ignore_gadgets(0);
2601 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2602 Debrief_ui_window.set_ignore_gadgets(0);
2605 // don't show pilot info popup by default
2606 Debrief_should_show_popup = 0;
2608 // see if the mode has changed and handle it if so.
2609 if ( Current_mode != New_mode ) {
2610 debrief_voice_stop();
2611 Current_mode = New_mode;
2614 if (New_mode == DEBRIEF_TAB) {
2616 Debrief_cue_voice = 0;
2618 if (Debrief_first_voice_flag) {
2619 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2620 Debrief_first_voice_flag = 0;
2623 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2627 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2628 Current_stage = New_stage;
2629 debrief_text_init();
2632 debrief_voice_play();
2635 if (Game_mode & GM_MULTIPLAYER) {
2636 multi_debrief_do_frame();
2639 // Now do all the rendering for the frame
2640 GR_MAYBE_CLEAR_RES(Background_bitmap);
2641 if (Background_bitmap >= 0) {
2642 gr_set_bitmap(Background_bitmap);
2646 // draw the damn awarded stuff, G
2647 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2648 gr_set_bitmap(Award_bg_bitmap);
2649 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2650 if (Rank_bitmap >= 0) {
2651 gr_set_bitmap(Rank_bitmap);
2652 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2655 if (Medal_bitmap >= 0) {
2656 gr_set_bitmap(Medal_bitmap);
2657 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2660 if (Badge_bitmap >= 0) {
2661 gr_set_bitmap(Badge_bitmap);
2662 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2665 if (Wings_bitmap >= 0) {
2666 gr_set_bitmap(Wings_bitmap);
2667 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2670 if (Crest_bitmap >= 0) {
2671 gr_set_bitmap(Crest_bitmap);
2672 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2675 // draw medal/badge/rank labels
2676 debrief_draw_award_text();
2678 /* if (Rank_text_bitmap >= 0) {
2679 gr_set_bitmap(Rank_text_bitmap);
2680 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2684 if (Medal_text_bitmap >= 0) {
2685 gr_set_bitmap(Medal_text_bitmap);
2686 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2689 if (Badge_text_bitmap >= 0) {
2690 gr_set_bitmap(Badge_text_bitmap);
2691 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2696 Debrief_ui_window.draw();
2697 debrief_redraw_pressed_buttons();
2698 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2699 if (Recommend_active && (Current_mode != STATS_TAB)) {
2700 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2703 // draw the title of the mission
2704 gr_set_color_fast(&Color_bright_white);
2705 strcpy(buf, The_mission.name);
2706 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2707 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2709 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2710 gr_set_color_fast(&Color_normal);
2711 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);
2714 // draw the screen-specific text
2715 switch (Current_mode) {
2717 if ( Num_debrief_stages <= 0 ) {
2718 gr_set_color_fast(&Color_white);
2719 Assert( Game_current_mission_filename != NULL );
2720 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);
2729 debrief_stats_render();
2733 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2736 gr_set_color_fast(&Color_red);
2737 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2738 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));
2741 debrief_render_stagenum();
2742 debrief_multi_list_draw();
2744 // render some extra stuff in multiplayer
2745 if (Game_mode & GM_MULTIPLAYER) {
2746 // render the chatbox last
2750 Debrief_ui_window.draw_tooltip();
2752 // render the status indicator for the voice system
2753 multi_common_voice_display_status();
2756 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2757 // want to include the mouse pointer which is drawn in the flip
2759 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2760 debrief_check_buttons();
2761 debrief_do_keys(new_k);
2764 // blit help overlay if active
2765 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2769 // dont let dude skip 3-09. hack.
2770 if(Game_mode & GM_CAMPAIGN_MODE){
2771 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2772 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2773 Debrief_skip_popup_already_shown = 1;
2778 // maybe show skip mission popup
2779 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)) {
2780 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
2781 XSTR("Advance To The Next Mission", 1474),
2782 XSTR("Don't Show Me This Again", 1475),
2783 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
2784 switch (popup_choice) {
2786 // stay on this mission, so proceed to normal debrief
2787 // in other words, do nothing.
2790 // skip this mission
2791 mission_campaign_skip_to_next();
2792 gameseq_post_event(GS_EVENT_START_GAME);
2795 // dont show this again
2796 Player->show_skip_popup = 0;
2800 Debrief_skip_popup_already_shown = 1;
2803 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
2804 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
2805 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
2806 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
2808 Debrief_should_show_popup = 0;
2812 void debrief_rebuild_player_list()
2816 debrief_multi_list_info *list;
2818 Multi_list_size = 0; // number of net players to choose from
2820 for ( i=0; i<MAX_PLAYERS; i++ ) {
2821 np = &Net_players[i];
2822 // remember not to include the standalone.
2823 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
2824 list = &Multi_list[Multi_list_size++];
2825 list->net_player_index = i;
2826 strcpy(list->callsign, np->player->callsign);
2828 // make sure to leave some room to blit the team indicator
2829 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
2834 void debrief_handle_player_drop()
2836 debrief_rebuild_player_list();
2839 void debrief_disable_accept()