2 * $Logfile: /Freespace2/code/MissionUI/MissionDebrief.cpp $
7 * C module for running the debriefing
10 * Revision 1.2 2002/05/07 03:16:46 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:10 root
17 * 57 10/29/99 10:40p Jefff
18 * hack to make german medal names display without actually changing them
20 * 56 10/13/99 3:26p Jefff
21 * fixed unnumbered XSTRs
23 * 55 10/06/99 10:28a Jefff
26 * 54 9/30/99 5:57p Jefff
27 * show upsell at end of campaign in OEM builds
29 * 53 9/15/99 3:42a Jefff
32 * 52 9/14/99 4:35a Dave
33 * Argh. Added all kinds of code to handle potential crashes in debriefing
36 * 51 9/14/99 3:26a Dave
37 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
38 * respawn-too-early problem. Made a few crash points safe.
40 * 50 9/14/99 12:51a Jefff
42 * 49 9/13/99 6:01p Jefff
43 * fixed wrong promotion voice mapping for sm1-08
45 * 48 9/13/99 11:15a Jefff
46 * clear out award text bug fixed
48 * 47 9/13/99 12:17p Andsager
49 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
52 * 46 9/07/99 9:35p Jefff
53 * fixed bug where award text was not getting cleared properly between
56 * 45 9/07/99 6:56p Jefff
57 * a few adjustments to loop detection
59 * 44 9/07/99 1:54p Jefff
60 * skip mission cleanup
62 * 43 9/06/99 9:45p Jefff
63 * skip mission support
65 * 42 9/06/99 6:38p Dave
66 * Improved CD detection code.
68 * 41 9/03/99 1:32a Dave
69 * CD checking by act. Added support to play 2 cutscenes in a row
70 * seamlessly. Fixed super low level cfile bug related to files in the
71 * root directory of a CD. Added cheat code to set campaign mission # in
74 * 40 9/02/99 3:45p Jefff
75 * forgot to remove some debug code. doh.
77 * 39 9/02/99 3:41p Jefff
78 * changed badge voice handling to be similar to promotion voice handling
80 * 38 9/01/99 4:41p Jefff
81 * fixed stoopid text color bug
83 * 37 8/31/99 11:54a Jefff
84 * minor debrief music tweak
86 * 36 8/27/99 9:57a Dave
87 * Enabled standard cheat codes. Allow player to continue in a campaing
88 * after using cheat codes.
90 * 35 8/27/99 12:04a Dave
91 * Campaign loop screen.
93 * 34 8/26/99 8:49p Jefff
94 * Updated medals screen and about everything that ever touches medals in
95 * one way or another. Sheesh.
97 * 33 8/20/99 4:20p Jefff
98 * hack for choosing the correct promotion voice
100 * 32 8/16/99 4:05p Dave
101 * Big honking checkin.
103 * 31 8/16/99 9:49a Jefff
104 * mission title length fix in multi
106 * 30 8/11/99 5:33p Jefff
107 * added 3rd debrief music track
109 * 29 8/10/99 7:28p Jefff
110 * shuffled some text around
112 * 28 8/04/99 5:36p Andsager
113 * Show upsell screens at end of demo campaign before returning to main
116 * 27 8/04/99 2:07p Jefff
117 * mission title no longer overwrites popup
119 * 26 8/02/99 5:37p Jefff
121 * 25 8/02/99 4:52p Jefff
122 * negative feedback sound when recommendations button pressed and
125 * 24 7/21/99 6:21p Jefff
126 * added hotkeys to the "you cannot accept" popup
128 * 23 6/15/99 12:04p Anoop
129 * Added a warning for running out of debrief text lines.
131 * 22 6/09/99 2:17p Dave
132 * Fixed up pleasewait bitmap rendering.
134 * 21 6/01/99 6:07p Dave
135 * New loading/pause/please wait bar.
137 * 20 5/22/99 6:05p Dave
138 * Fixed a few localization # problems.
140 * 19 5/22/99 5:35p Dave
141 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
143 * 18 3/20/99 3:47p Andsager
144 * Fix crash with no mission loop description.
146 * 17 2/23/99 2:29p Dave
147 * First run of oldschool dogfight mode.
149 * 16 2/21/99 6:01p Dave
150 * Fixed standalone WSS packets.
152 * 15 2/11/99 3:08p Dave
153 * PXO refresh button. Very preliminary squad war support.
155 * 14 1/30/99 5:08p Dave
156 * More new hi-res stuff.Support for nice D3D textures.
158 * 13 1/29/99 2:08a Dave
159 * Fixed beam weapon collisions with players. Reduced size of scoring
160 * struct for multiplayer. Disabled PXO.
162 * 12 1/14/99 5:15p Neilk
163 * changed credits, command debrief interfaces to high resolution support
165 * 11 1/13/99 2:11p Andsager
166 * change default debriefing string text
168 * 10 12/17/98 4:50p Andsager
169 * Added debrief_assemble_optional_mission_popup_text() for single and
172 * 9 12/12/98 3:17p Andsager
173 * Clean up mission eval, goal, event and mission scoring.
175 * 8 12/10/98 10:19a Andsager
176 * Fix mission loop assert
178 * 7 12/10/98 9:59a Andsager
179 * Fix some bugs with mission loops
181 * 6 12/09/98 1:56p Andsager
182 * Initial checkin of mission loop
184 * 5 11/05/98 4:18p Dave
185 * First run nebula support. Beefed up localization a bit. Removed all
186 * conditional compiles for foreign versions. Modified mission file
189 * 4 10/23/98 3:51p Dave
190 * Full support for tstrings.tbl and foreign languages. All that remains
191 * is to make it active in Fred.
193 * 3 10/13/98 9:28a Dave
194 * Started neatening up freespace.h. Many variables renamed and
195 * reorganized. Added AlphaColors.[h,cpp]
197 * 2 10/07/98 10:53a Dave
200 * 1 10/07/98 10:49a Dave
202 * 178 9/17/98 3:08p Dave
203 * PXO to non-pxo game warning popup. Player icon stuff in create and join
204 * game screens. Upped server count refresh time in PXO to 35 secs (from
207 * 177 7/07/98 1:46p Dave
208 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
211 * 175 6/09/98 10:31a Hoffoss
212 * Created index numbers for all xstr() references. Any new xstr() stuff
213 * added from here on out should be added to the end if the list. The
214 * current list count can be found in FreeSpace.cpp (search for
217 * 174 6/07/98 3:26p Lawrance
218 * Fix bug with cut-off popup text
220 * 173 6/05/98 9:54a Lawrance
223 * 172 6/01/98 11:43a John
224 * JAS & MK: Classified all strings for localization.
226 * 171 5/27/98 1:24p Allender
227 * make targeting dots work (as well as other targeting features) properly
228 * in multiplayer. Don't query for CD when entering debrief in
231 * 170 5/26/98 11:10a Lawrance
232 * Fix bug where window controls get disabled when F1 pressed twice
234 * 169 5/24/98 12:55a Mike
235 * Prevent Assert() when no debriefing text for a stage.
237 * 168 5/23/98 10:38p Lawrance
238 * Avoid doing a cfile refresh when running debug
240 * 167 5/23/98 6:49p Lawrance
241 * Fix problems with refreshing the file list when a CD is inserted
243 * 166 5/21/98 6:57p Lawrance
244 * Don't prompt for the CD if voice not found
246 * 165 5/20/98 2:24a Dave
247 * Fixed server side voice muting. Tweaked multi debrief/endgame
248 * sequencing a bit. Much friendlier for stats tossing/accepting now.
250 * 164 5/19/98 8:35p Dave
251 * Revamp PXO channel listing system. Send campaign goals/events to
252 * clients for evaluation. Made lock button pressable on all screens.
254 * 163 5/19/98 11:13a Hoffoss
255 * Fixed bug where wrong wings award was being displayed in debriefing.
257 * 162 5/19/98 12:28a Mike
260 * 161 5/18/98 8:08p Hoffoss
261 * Moved placement of 'More' text.
263 * 160 5/18/98 3:50p Dan
264 * AL: Pick correct traitor debriefing voice file
266 * 159 5/17/98 6:32p Dave
267 * Make sure clients/servers aren't kicked out of the debriefing when team
268 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
269 * xfer/pilot info popup stuff.
271 * 158 5/16/98 9:14p Allender
272 * fix scoring ckise fir training missions to actually count medals, but
273 * nothing else. Code used to Assert when wings were granted then taken
274 * away because they were actually never granted in scoring structure
276 * 157 5/15/98 5:15p Dave
277 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
278 * status for team vs. team. Put in asserts to check for invalid team vs.
281 * 156 5/15/98 4:36p Allender
282 * fixed minor bug with wings
284 * 155 5/15/98 4:12p Allender
285 * removed redbook code. Put back in ingame join timer. Major fixups for
286 * stats in multiplayer. Pass correct score, medals, etc when leaving
287 * game. Be sure clients display medals, badges, etc.
289 * 154 5/15/98 2:25p Jasen
290 * temporarily disable granting of promotion and badges for clients
292 * 153 5/15/98 10:57a Allender
293 * fixed client side debriefings
295 * 152 5/15/98 10:36a Dave
296 * Removed 2 bogus bitmap drawing Int3()'s
298 * 151 5/14/98 2:44p Hoffoss
299 * Added wings awarding to debrief screen.
301 * 150 5/13/98 9:11p Lawrance
302 * Make 'replay mission' popup warn users about the loss of mission stats.
307 #include "missiondebrief.h"
308 #include "missionbriefcommon.h"
309 #include "missionscreencommon.h"
310 #include "missiongoals.h"
311 #include "missionpause.h"
312 #include "freespace.h"
313 #include "gamesequence.h"
321 #include "audiostr.h"
324 #include "contexthelp.h"
330 #include "multimsgs.h"
331 #include "multiutil.h"
332 #include "multiteamselect.h"
334 #include "eventmusic.h"
338 #include "multi_pinfo.h"
339 #include "contexthelp.h"
340 #include "multi_kick.h"
341 #include "multi_campaign.h"
342 #include "alphacolors.h"
343 #include "localize.h"
344 #include "multi_endgame.h"
347 #define MAX_TOTAL_DEBRIEF_LINES 200
349 #define TEXT_TYPE_NORMAL 1
350 #define TEXT_TYPE_RECOMMENDATION 2
352 #define DEBRIEF_NUM_STATS_PAGES 4
353 #define DEBRIEF_MISSION_STATS 0
354 #define DEBRIEF_MISSION_KILLS 1
355 #define DEBRIEF_ALLTIME_STATS 2
356 #define DEBRIEF_ALLTIME_KILLS 3
358 // 3rd coord is max width in pixels
359 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
368 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
377 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
382 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
391 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
400 #define MULTI_LIST_TEAM_OFFSET 16
402 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
407 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
416 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
426 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
435 // 0=x, 1=y, 2=width of the field
436 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
445 // 0=x, 1=y, 2=height of the field
446 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
456 // 1 = without medal (text will use medal space)
457 #define DB_WITH_MEDAL 0
458 #define DB_WITHOUT_MEDAL 1
459 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
468 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
469 "DebriefSingle", // GR_640
470 "2_DebriefSingle" // GR_1024
472 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
473 "DebriefMulti", // GR_640
474 "2_DebriefMulti" // GR_1024
476 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
477 "Debrief-m", // GR_640
478 "2_Debrief-m" // GR_1024
481 #define NUM_BUTTONS 18
484 #define DEBRIEF_TAB 0
486 #define TEXT_SCROLL_UP 2
487 #define TEXT_SCROLL_DOWN 3
488 #define REPLAY_MISSION 4
489 #define RECOMMENDATIONS 5
490 #define FIRST_STAGE 6
494 #define MULTI_PINFO_POPUP 10
495 #define MULTI_KICK 11
496 #define MEDALS_BUTTON 12
497 #define PLAYER_SCROLL_UP 13
498 #define PLAYER_SCROLL_DOWN 14
499 #define HELP_BUTTON 15
500 #define OPTIONS_BUTTON 16
501 #define ACCEPT_BUTTON 17
506 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
507 "PleaseWait", // GR_640
508 "2_PleaseWait" // GR_1024
514 char text[NAME_LENGTH+1]; // name of ship type with a colon
515 int num; // how many ships of this type player has killed
516 } debrief_stats_kill_info;
519 int net_player_index; // index into Net_players[] array
520 int rank_bitmap; // bitmap id for rank
521 char callsign[CALLSIGN_LEN];
522 } debrief_multi_list_info;
524 ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
526 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
527 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
528 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
529 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
530 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
531 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
532 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
533 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
534 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
535 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
536 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
537 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
538 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
539 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
540 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
541 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
542 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
543 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
546 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
547 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
548 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
549 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
550 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
551 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
552 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
553 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
554 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
555 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
556 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
557 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
558 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
559 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
560 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
561 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
562 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
563 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
568 #define NUM_DEBRIEF_TEXT 10
569 #define MP_TEXT_INDEX_1 4
570 #define MP_TEXT_INDEX_2 5
571 #define MP_TEXT_INDEX_3 6
572 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
574 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
575 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
576 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
577 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
578 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
579 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
580 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
581 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
582 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
583 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
586 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
587 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
588 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
589 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
590 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
591 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
592 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
593 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
594 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
595 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
600 char Debrief_current_callsign[CALLSIGN_LEN+10];
601 player *Debrief_player;
603 static UI_WINDOW Debrief_ui_window;
604 static UI_BUTTON List_region;
605 static int Background_bitmap; // bitmap for the background of the debriefing
606 static int Award_bg_bitmap;
607 static int Debrief_multi_loading_bitmap;
608 static int Rank_bitmap;
609 static int Medal_bitmap;
610 static int Badge_bitmap;
611 static int Wings_bitmap;
612 static int Crest_bitmap;
613 //static int Rank_text_bitmap;
614 //static int Medal_text_bitmap;
615 //static int Badge_text_bitmap;
617 static int Debrief_accepted;
618 static int Turned_traitor;
619 static int Must_replay_mission;
621 static int Current_mode;
623 static int Recommend_active;
624 static int Award_active;
625 static int Text_offset;
626 static int Num_text_lines = 0;
627 static int Num_debrief_lines = 0;
628 static int Num_normal_debrief_lines = 0;
629 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
630 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
632 static int Debrief_inited = 0;
633 static int New_stage;
634 static int Current_stage;
635 static int Num_stages;
636 static int Num_debrief_stages;
637 static int Stage_voice;
639 static int Multi_list_size;
640 static int Multi_list_offset;
642 int Debrief_multi_stages_loaded = 0;
643 int Debrief_multi_voice_loaded = 0;
645 // static int Debrief_voice_ask_for_cd;
647 // voice id's for debriefing text
648 static int Debrief_voices[MAX_DEBRIEF_STAGES];
650 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
651 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
652 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
654 // pointer used for getting to debriefing information
655 debriefing Traitor_debriefing; // used when player is a traitor
657 // pointers to the active stages for this debriefing
658 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
659 static debrief_stage Promotion_stage, Badge_stage;
660 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
661 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
662 int Multi_list_select;
664 // flag indicating if we should display info for the given player (in multiplayer)
665 int Debrief_should_show_popup = 1;
667 // already shown skip mission popup?
668 static int Debrief_skip_popup_already_shown = 0;
670 void debrief_text_init();
671 void debrief_accept(int ok_to_post_start_game_event = 1);
672 void debrief_kick_selected_player();
675 // promotion voice selection stuff
676 #define NUM_VOLITION_CAMPAIGNS 1
678 char campaign_name[32];
680 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
682 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
683 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
687 // data for which voice goes w/ which mission
688 typedef struct voice_map {
689 char mission_file[32];
693 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
694 { // FreeSpace2 campaign
726 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
728 { "loop1-1.fs2", 4 },
729 { "loop1-2.fs2", 4 },
730 { "loop1-3.fs2", 5 },
731 { "loop2-1.fs2", 4 },
736 #define DB_AWARD_WINGS 0
737 #define DB_AWARD_MEDAL 1
738 #define DB_AWARD_SOC 2
739 #define DB_AWARD_RANK 3
740 #define DB_AWARD_BADGE 4
741 #define DB_AWARD_BG 5
742 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
761 #define AWARD_TEXT_MAX_LINES 5
762 #define AWARD_TEXT_MAX_LINE_LENGTH 128
763 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
764 int Debrief_award_text_num_lines = 0;
768 // prototypes, you know you love 'em
769 void debrief_add_award_text(char *str);
770 void debrief_award_text_clear();
775 char *debrief_tooltip_handler(char *str)
777 if (!stricmp(str, NOX("@.Medal"))) {
779 return XSTR( "Medal", 435);
782 } else if (!stricmp(str, NOX("@.Rank"))) {
784 return XSTR( "Rank", 436);
787 } else if (!stricmp(str, NOX("@.Badge"))) {
789 return XSTR( "Badge", 437);
792 } else if (!stricmp(str, NOX("@Medal"))) {
793 if (Medal_bitmap >= 0){
794 return Medals[Player->stats.m_medal_earned].name;
797 } else if (!stricmp(str, NOX("@Rank"))) {
798 if (Rank_bitmap >= 0){
799 return Ranks[Promoted].name;
802 } else if (!stricmp(str, NOX("@Badge"))) {
803 if (Badge_bitmap >= 0){
804 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
811 // initialize the array of handles to the different voice streams
812 void debrief_voice_init()
816 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
817 Debrief_voices[i] = -1;
821 void debrief_load_voice_file(int voice_num, char *name)
823 int load_attempts = 0;
826 if ( load_attempts++ > 5 ) {
830 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
831 if ( Debrief_voices[voice_num] >= 0 ) {
835 // Don't bother to ask for the CD in multiplayer
836 if ( Game_mode & GM_MULTIPLAYER ) {
840 // couldn't load voice, ask user to insert CD (if necessary)
842 // if ( Debrief_voice_ask_for_cd ) {
843 // if ( game_do_cd_check() == 0 ) {
844 // Debrief_voice_ask_for_cd = 0;
851 // open and pre-load the stream buffers for the different voice streams
852 void debrief_voice_load_all()
856 // Debrief_voice_ask_for_cd = 1;
858 for ( i=0; i<Num_debrief_stages; i++ ) {
859 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
862 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
863 debrief_load_voice_file(i, Debrief_stages[i]->voice);
864 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
869 // close all the briefing voice streams
870 void debrief_voice_unload_all()
874 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
875 if ( Debrief_voices[i] != -1 ) {
876 audiostream_close_file(Debrief_voices[i], 0);
877 Debrief_voices[i] = -1;
882 // start playback of the voice for a particular briefing stage
883 void debrief_voice_play()
885 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
889 // no more stages? We are done then.
890 if (Stage_voice >= Num_debrief_stages){
894 // if in delayed start, see if delay has elapsed and start voice if so
895 if (Debrief_cue_voice) {
896 if (!timestamp_elapsed(Debrief_cue_voice)){
900 Stage_voice++; // move up to next voice
901 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
902 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
903 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
909 // see if voice is still playing. If so, do nothing yet.
910 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
914 // set voice to play in a little while from now.
915 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
918 // stop playback of the voice for a particular briefing stage
919 void debrief_voice_stop()
921 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
924 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
928 // function to deal with inserting possible promition and badge stages into the debriefing
930 void debrief_multi_fixup_stages()
934 // possibly insert the badge stage first, them the promotion stage since they are
935 // inserted at the front of the debrief stages.
936 if ( Badge_bitmap >= 0 ) {
937 // move all stages forward one. Don't
938 for ( i = Num_debrief_stages; i > 0; i-- ) {
939 Debrief_stages[i] = Debrief_stages[i-1];
941 Debrief_stages[0] = &Badge_stage;
942 Num_debrief_stages++;
945 if ( Promoted >= 0) {
946 // move all stages forward one
947 for ( i = Num_debrief_stages; i > 0; i-- ) {
948 Debrief_stages[i] = Debrief_stages[i-1];
950 Debrief_stages[0] = &Promotion_stage;
951 Num_debrief_stages++;
956 // function called from multiplayer clients to set up the debriefing information for them
957 // (sent from the server).
958 void debrief_set_multi_clients( int stage_count, int active_stages[] )
962 // set up the right briefing for this guy
963 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
964 Debriefing = &Debriefings[Net_player->p_info.team];
966 Debriefing = &Debriefings[0];
969 // see if this client was promoted -- if so, then add the first stage.
970 Num_debrief_stages = 0;
972 // set the pointers to the debriefings for this client
973 for (i = 0; i < stage_count; i++) {
974 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
977 Debrief_multi_stages_loaded = 1;
980 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
981 // information to all clients after leaving this screen.
982 void debrief_multi_server_stuff()
984 debriefing *debriefp;
986 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
987 int i, j, num_stages, stage_count[MAX_TEAMS];
989 memset( stage_active, 0, sizeof(stage_active) );
991 for (i=0; i<Num_teams; i++) {
992 debriefp = &Debriefings[i];
994 stages[i] = stage_active[i];
995 for (j=0; j<debriefp->num_stages; j++) {
996 if ( eval_sexp(debriefp->stages[j].formula) ) {
997 stage_active[i][num_stages] = j;
1002 stage_count[i] = num_stages;
1005 // if we're in campaign mode, evaluate campaign stuff
1006 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1007 multi_campaign_eval_debrief();
1010 // send the information to all clients.
1011 send_debrief_info( stage_count, stages );
1015 // --------------------------------------------------------------------------------------
1016 // debrief_set_stages_and_multi_stuff()
1018 // Set up the active stages for this debriefing
1020 // returns: number of active debriefing stages
1022 int debrief_set_stages_and_multi_stuff()
1025 debriefing *debriefp;
1027 if ( MULTIPLAYER_CLIENT ) {
1031 Num_debrief_stages = 0;
1033 if ( Game_mode & GM_MULTIPLAYER ) {
1034 debrief_multi_server_stuff();
1037 // check to see if player is a traitor (looking at his team). If so, use the special
1038 // traitor debriefing. Only done in single player
1039 debriefp = Debriefing;
1040 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1041 if (Player_ship->team == TEAM_TRAITOR)
1042 debriefp = &Traitor_debriefing;
1045 Num_debrief_stages = 0;
1046 if (Promoted >= 0) {
1047 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1050 if (Badge_bitmap >= 0) {
1051 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1054 for (i=0; i<debriefp->num_stages; i++) {
1055 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1056 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1060 return Num_debrief_stages;
1063 // init the buttons that are specific to the debriefing screen
1064 void debrief_buttons_init()
1069 for ( i=0; i<NUM_BUTTONS; i++ ) {
1070 b = &Buttons[gr_screen.res][i];
1071 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1072 // set up callback for when a mouse first goes over a button
1073 b->button.set_highlight_action( common_play_highlight_sound );
1074 b->button.set_bmaps(b->filename);
1075 b->button.link_hotspot(b->hotspot);
1079 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1080 // multiplayer specific text
1081 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1082 // only add if in multiplayer mode
1083 if(Game_mode & GM_MULTIPLAYER){
1084 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1089 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1093 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1094 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1095 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1096 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1097 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1098 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1099 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1100 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1102 // if in multiplayer, disable the button for all players except the host
1103 // also disable for squad war matches
1104 if(Game_mode & GM_MULTIPLAYER){
1105 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1106 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1111 // --------------------------------------------------------------------------------------
1112 // debrief_ui_init()
1114 void debrief_ui_init()
1116 // init ship selection masks and buttons
1117 common_set_interface_palette("DebriefPalette"); // set the interface palette
1118 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1119 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1120 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1121 debrief_buttons_init();
1123 // load in help overlay bitmap
1124 help_overlay_load(DEBRIEFING_OVERLAY);
1125 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1127 if ( Game_mode & GM_MULTIPLAYER ) {
1128 // close down any old instances of the chatbox
1131 // create the new one
1133 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1134 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);
1137 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1140 if ( Background_bitmap < 0 ) {
1141 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1144 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1145 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1148 // sets Promotion_stage.voice
1149 // defaults to number 9 (Petrarch) for non-volition missions
1150 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1151 void debrief_choose_promotion_voice()
1155 if(Campaign.current_mission < 0){
1156 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1160 // search thru all official campaigns for our current campaign
1161 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1162 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1163 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1164 // now search thru the mission filenames,
1165 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1166 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1167 // found it! set the persona and bail
1168 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1176 // default to petrarch
1177 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1180 // sets Promotion_stage.voice
1181 // defaults to number 9 (Petrarch) for non-volition missions
1182 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1183 void debrief_choose_badge_voice()
1187 if(Campaign.current_mission < 0){
1188 // default to petrarch
1189 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1192 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1193 // search thru all official campaigns for our current campaign
1194 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1195 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1196 // now search thru the mission filenames,
1197 for (j=0; j<Campaign.num_missions; j++) {
1198 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1199 // found it! set the persona and bail
1200 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1208 // default to petrarch
1209 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1213 void debrief_award_init()
1225 // be sure there are no old award texts floating around
1226 debrief_award_text_clear();
1228 // handle medal earned
1229 if (Player->stats.m_medal_earned != -1) {
1230 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1232 if ( Player->stats.medals[13] > 1 ) {
1237 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1238 Wings_bitmap = bm_load(buf);
1240 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1241 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1243 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1244 Medal_bitmap = bm_load(buf);
1247 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1250 // handle promotions
1251 if ( Player->stats.m_promotion_earned != -1 ) {
1252 Promoted = Player->stats.m_promotion_earned;
1253 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1254 Rank_bitmap = bm_load(buf);
1256 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1257 Promotion_stage.new_recommendation_text = NULL;
1259 // choose appropriate promotion voice for this mission
1260 debrief_choose_promotion_voice();
1262 debrief_add_award_text(Ranks[Promoted].name);
1265 // handle badge earned
1266 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1267 if ( Player->stats.m_badge_earned != -1 ) {
1268 i = Player->stats.m_badge_earned;
1269 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1270 Badge_bitmap = bm_load(buf);
1272 Badge_stage.new_text = Badge_info[i].promotion_text;
1273 Badge_stage.new_recommendation_text = NULL;
1275 // choose appropriate voice
1276 debrief_choose_badge_voice();
1278 debrief_add_award_text(Medals[Badge_index[i]].name);
1281 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1288 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1289 // mission a traitor. The same debriefing always gets played
1290 void debrief_traitor_init()
1292 static int inited = 0;
1295 debriefing *debrief;
1296 debrief_stage *stagep;
1300 if ((rval = setjmp(parse_abort)) != 0) {
1301 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1304 read_file_text("traitor.tbl");
1308 // open localization
1311 // simplied form of the debriefing stuff.
1312 debrief = &Traitor_debriefing;
1313 required_string("#Debriefing_info");
1315 required_string("$Num stages:");
1316 stuff_int(&debrief->num_stages);
1317 Assert(debrief->num_stages == 1);
1320 stagep = &debrief->stages[stage_num++];
1321 required_string("$Formula:");
1322 stagep->formula = get_sexp_main();
1323 required_string("$multi text");
1324 if ( Fred_running ) {
1325 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1327 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1329 required_string("$Voice:");
1330 char traitor_voice_file[NAME_LENGTH];
1331 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1333 // DKA 9/13/99 Only 1 traitor msg for FS2
1334 // if ( Player->on_bastion ) {
1335 // strcpy(stagep->voice, NOX("3_"));
1337 // strcpy(stagep->voice, NOX("1_"));
1340 strcat(stagep->voice, traitor_voice_file);
1342 required_string("$Recommendation text:");
1343 if ( Fred_running ) {
1344 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1346 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1350 // close localization
1354 // disable the accept button if in single player and I am a traitor
1355 Debrief_accepted = 0;
1356 Turned_traitor = Must_replay_mission = 0;
1357 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1358 if (Player_ship->team == TEAM_TRAITOR){
1362 if (Campaign.next_mission == Campaign.current_mission){
1363 Must_replay_mission = 1;
1367 if (Turned_traitor || Must_replay_mission) {
1368 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1370 // kill off any stats
1371 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1372 scoring_level_init( &Player->stats );
1376 // initialization for listing of players in game
1377 void debrief_multi_list_init()
1379 Multi_list_size = 0; // number of net players to choose from
1380 Multi_list_offset = 0;
1382 Multi_list_select = -1;
1384 if ( !(Game_mode & GM_MULTIPLAYER) )
1387 debrief_rebuild_player_list();
1389 // switch stats display to this newly selected player
1390 set_player_stats(Multi_list[0].net_player_index);
1391 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1392 Debrief_player = Player;
1395 void debrief_multi_list_scroll_up()
1397 // if we're at the beginning of the list, don't do anything
1398 if(Multi_list_offset == 0){
1399 gamesnd_play_iface(SND_GENERAL_FAIL);
1403 // otherwise scroll up
1404 Multi_list_offset--;
1405 gamesnd_play_iface(SND_USER_SELECT);
1408 void debrief_multi_list_scroll_down()
1410 // if we can scroll down no further
1411 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1412 gamesnd_play_iface(SND_GENERAL_FAIL);
1415 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1416 gamesnd_play_iface(SND_GENERAL_FAIL);
1420 // otherwise scroll down
1421 Multi_list_offset++;
1422 gamesnd_play_iface(SND_USER_SELECT);
1425 // draw the connected net players
1426 void debrief_multi_list_draw()
1428 int y, z, font_height,idx;
1429 char str[CALLSIGN_LEN+5];
1432 font_height = gr_get_font_height();
1434 // if we currently have no item picked, pick a reasonable one
1435 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1436 // select the entry which corresponds to the local player
1437 Multi_list_select = 0;
1438 for(idx=0;idx<Multi_list_size;idx++){
1439 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1440 Multi_list_select = idx;
1442 // switch stats display to this newly selected player
1443 set_player_stats(Multi_list[idx].net_player_index);
1444 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1445 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1451 // draw the list itself
1453 z = Multi_list_offset;
1454 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1455 np = &Net_players[Multi_list[z].net_player_index];
1457 if (z >= Multi_list_size){
1460 // set the proper text color for the highlight
1461 if(np->flags & NETINFO_FLAG_GAME_HOST){
1462 if(Multi_list_select == z){
1463 gr_set_color_fast(&Color_text_active_hi);
1465 gr_set_color_fast(&Color_bright);
1468 if(Multi_list_select == z){
1469 gr_set_color_fast(&Color_text_active);
1471 gr_set_color_fast(&Color_text_normal);
1475 // blit the proper indicator - skipping observers
1476 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1477 if(Netgame.type_flags & NG_TYPE_TEAM){
1479 if(np->p_info.team == 0){
1480 // draw his "selected" icon
1481 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1482 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1483 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1485 // draw his "normal" icon
1486 else if(Multi_common_icons[MICON_TEAM0] != -1){
1487 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1488 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1490 } else if(np->p_info.team == 1){
1491 // draw his "selected" icon
1492 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1493 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1494 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1496 // draw his "normal" icon
1497 else if(Multi_common_icons[MICON_TEAM1] != -1){
1498 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1499 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1503 // draw the team 0 selected icon
1504 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1505 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1506 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1511 strcpy(str,Multi_list[z].callsign);
1512 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)){
1513 strcat(str,XSTR( "(O)", 438));
1517 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1524 void debrief_kick_selected_player()
1526 if(Multi_list_select >= 0){
1527 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1528 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1532 // get optional mission popup text
1533 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1535 Assert(buffer != NULL);
1538 if (mission_loop_desc == NULL) {
1539 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1540 mprintf(("No mission loop description avail"));
1542 strcpy(buffer, mission_loop_desc);
1545 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1548 // what to do when the accept button is hit
1549 void debrief_accept(int ok_to_post_start_game_event)
1553 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1557 if (Game_mode & GM_MULTIPLAYER) {
1561 if (Player_ship->team == TEAM_TRAITOR){
1562 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1563 }/* else if (Cheats_enabled) {
1564 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1566 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1569 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1571 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1572 } else if ( z == 1 ) {
1573 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1579 Debrief_accepted = 1;
1580 // save mission stats
1581 if (Game_mode & GM_MULTIPLAYER) {
1582 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1583 // as well as doing stats transfers, etc.
1584 multi_debrief_accept_hit();
1588 int play_commit_sound = 1;
1589 // only write the player's stats if he's accepted
1591 // if we are just playing a single mission, then don't do many of the things
1592 // that need to be done. Nothing much should happen when just playing a single
1593 // mission that isn't in a campaign.
1594 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1596 // check for possible mission loop
1597 // check for (1) mission loop available, (2) dont have to repeat last mission
1598 if(!(Game_mode & GM_MULTIPLAYER)){
1599 int cur = Campaign.current_mission;
1600 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1601 if (Campaign.missions[cur].has_mission_loop) {
1602 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1605 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1608 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1610 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1612 Campaign.loop_enabled = 1;
1613 Campaign.next_mission = Campaign.loop_mission;
1622 if(ok_to_post_start_game_event){
1623 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1625 play_commit_sound = 0;
1628 // continue as normal
1631 mission_campaign_mission_over();
1633 // check to see if we are out of the loop now
1634 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1635 Campaign.loop_enabled = 0;
1638 // check if campaign is over
1639 if ( Campaign.next_mission == -1 ) {
1640 #if defined(FS2_DEMO) || defined(OEM_BUILD)
1641 gameseq_post_event(GS_EVENT_END_DEMO);
1643 gameseq_post_event(GS_EVENT_MAIN_MENU);
1646 if ( ok_to_post_start_game_event ) {
1648 if(game_do_cd_mission_check(Game_current_mission_filename)){
1649 gameseq_post_event(GS_EVENT_START_GAME);
1651 gameseq_post_event(GS_EVENT_MAIN_MENU);
1654 play_commit_sound = 0;
1659 gameseq_post_event(GS_EVENT_MAIN_MENU);
1662 if ( play_commit_sound ) {
1663 gamesnd_play_iface(SND_COMMIT_PRESSED);
1670 void debrief_next_tab()
1672 New_mode = Current_mode + 1;
1673 if (New_mode >= NUM_TABS)
1677 void debrief_prev_tab()
1679 New_mode = Current_mode - 1;
1681 New_mode = NUM_TABS - 1;
1684 // --------------------------------------------------------------------------------------
1685 // debrief_next_stage()
1687 void debrief_next_stage()
1689 if (Current_stage < Num_stages - 1) {
1690 New_stage = Current_stage + 1;
1691 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1694 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1697 // --------------------------------------------------------------------------------------
1698 // debrief_prev_stage()
1700 void debrief_prev_stage()
1702 if (Current_stage) {
1703 New_stage = Current_stage - 1;
1704 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1707 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1710 // --------------------------------------------------------------------------------------
1711 // debrief_first_stage()
1712 void debrief_first_stage()
1714 if (Current_stage) {
1716 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1719 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1722 // --------------------------------------------------------------------------------------
1723 // debrief_last_stage()
1724 void debrief_last_stage()
1726 if (Current_stage != Num_stages - 1) {
1727 New_stage = Num_stages - 1;
1728 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1731 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1734 // draw what stage number the debriefing is on
1735 void debrief_render_stagenum()
1743 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1744 gr_get_string_size(&w, NULL, buf);
1745 gr_set_color_fast(&Color_bright_blue);
1746 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1747 gr_set_color_fast(&Color_white);
1750 // render the mission time at the specified y location
1751 void debrief_render_mission_time(int y_loc)
1755 game_format_time(Missiontime, time_str);
1756 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1757 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1760 // render out the debriefing text to the scroll window
1761 void debrief_render()
1763 int y, z, font_height;
1765 if ( Num_stages <= 0 )
1768 font_height = gr_get_font_height();
1770 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]);
1773 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1774 if (z >= Num_text_lines)
1777 if (Text_type[z] == TEXT_TYPE_NORMAL)
1778 gr_set_color_fast(&Color_white);
1780 gr_set_color_fast(&Color_bright_red);
1783 gr_string(0, y, Text[z]);
1792 // render out the stats info to the scroll window
1794 void debrief_stats_render()
1796 int i, y, font_height;
1798 gr_set_color_fast(&Color_blue);
1799 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]);
1800 gr_string(0, 0, Debrief_current_callsign);
1801 font_height = gr_get_font_height();
1804 switch ( Current_stage ) {
1805 case DEBRIEF_MISSION_STATS:
1806 i = Current_stage - 1;
1810 gr_set_color_fast(&Color_white);
1812 // display mission completion time
1813 debrief_render_mission_time(y);
1816 show_stats_label(i, 0, y, font_height);
1817 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1819 case DEBRIEF_ALLTIME_STATS:
1820 i = Current_stage - 1;
1824 gr_set_color_fast(&Color_white);
1825 show_stats_label(i, 0, y, font_height);
1826 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1829 case DEBRIEF_ALLTIME_KILLS:
1830 case DEBRIEF_MISSION_KILLS:
1831 gr_set_color_fast(&Color_white);
1833 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1834 if (i >= Num_text_lines)
1838 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1839 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
1841 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
1844 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
1845 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
1852 if (Num_text_lines == 2) {
1853 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1854 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
1856 gr_printf(0, y, XSTR( "(No ship kills)", 450));
1869 // do action for when the replay button is pressed
1870 void debrief_replay_pressed()
1872 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
1874 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));
1881 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
1882 gamesnd_play_iface(SND_COMMIT_PRESSED);
1885 // -------------------------------------------------------------------
1886 // debrief_redraw_pressed_buttons()
1888 // Redraw any debriefing buttons that are pressed down. This function is needed
1889 // since we sometimes need to draw pressed buttons last to ensure the entire
1890 // button gets drawn (and not overlapped by other buttons)
1892 void debrief_redraw_pressed_buttons()
1897 for ( i=0; i<NUM_BUTTONS; i++ ) {
1898 b = &Buttons[gr_screen.res][i].button;
1899 // don't draw the recommendations button if we're in stats mode
1900 if ( b->button_down() ) {
1906 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
1908 void debrief_button_pressed(int num)
1912 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
1913 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
1914 if (num != Current_mode){
1915 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1920 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
1921 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
1922 if (num != Current_mode){
1923 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1928 case TEXT_SCROLL_UP:
1931 gamesnd_play_iface(SND_SCROLL);
1933 gamesnd_play_iface(SND_GENERAL_FAIL);
1937 case TEXT_SCROLL_DOWN:
1938 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
1940 gamesnd_play_iface(SND_SCROLL);
1942 gamesnd_play_iface(SND_GENERAL_FAIL);
1946 case REPLAY_MISSION:
1947 if(Game_mode & GM_MULTIPLAYER){
1948 multi_debrief_replay_hit();
1950 debrief_replay_pressed();
1954 case RECOMMENDATIONS:
1955 gamesnd_play_iface(SND_USER_SELECT);
1956 Recommend_active = !Recommend_active;
1957 debrief_text_init();
1961 debrief_first_stage();
1965 debrief_prev_stage();
1969 debrief_next_stage();
1973 debrief_last_stage();
1977 gamesnd_play_iface(SND_HELP_PRESSED);
1978 launch_context_help();
1981 case OPTIONS_BUTTON:
1982 gamesnd_play_iface(SND_SWITCH_SCREENS);
1983 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
1991 gamesnd_play_iface(SND_SWITCH_SCREENS);
1992 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
1995 case PLAYER_SCROLL_UP:
1996 debrief_multi_list_scroll_up();
1999 case PLAYER_SCROLL_DOWN:
2000 debrief_multi_list_scroll_down();
2003 case MULTI_PINFO_POPUP:
2004 Debrief_should_show_popup = 1;
2008 debrief_kick_selected_player();
2013 void debrief_setup_ship_kill_stats(int stage_num)
2017 debrief_stats_kill_info *kill_info;
2019 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2020 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2023 Assert(Debrief_player != NULL);
2025 // kill_ar points to an array of MAX_SHIP_TYPE ints
2026 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2027 kill_arr = Debrief_player->stats.m_okKills;
2029 kill_arr = Debrief_player->stats.kills;
2033 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2035 // code used to add in mission kills, but the new system assumes that the player will accept, so
2036 // all time stats already have mission stats added in.
2037 if ( kill_arr[i] <= 0 ){
2042 kill_info = &Debrief_stats_kills[Num_text_lines++];
2044 kill_info->num = kill_arr[i];
2046 strcpy(kill_info->text, Ship_info[i].name);
2047 strcat(kill_info->text, NOX(":"));
2050 Num_text_lines += 2;
2053 // Iterate through the debriefing buttons, checking if they are pressed
2054 void debrief_check_buttons()
2058 for ( i=0; i<NUM_BUTTONS; i++ ) {
2059 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2060 debrief_button_pressed(i);
2064 if ( !(Game_mode & GM_MULTIPLAYER) )
2067 if (List_region.pressed()) {
2068 List_region.get_mouse_pos(NULL, &y);
2069 z = Multi_list_offset + y / gr_get_font_height();
2070 if ((z >= 0) && (z < Multi_list_size)) {
2071 // switch stats display to this newly selected player
2072 set_player_stats(Multi_list[z].net_player_index);
2073 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2074 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2075 Multi_list_select = z;
2076 debrief_setup_ship_kill_stats(Current_stage);
2077 gamesnd_play_iface(SND_USER_SELECT);
2081 // if the player was double clicked on - we should popup a player info popup
2083 if (List_region.double_clicked()) {
2084 Debrief_should_show_popup = 1;
2089 void debrief_text_stage_init(char *src, int type)
2091 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2092 char line[MAX_DEBRIEF_LINE_LEN];
2093 char *p_str[MAX_DEBRIEF_LINES];
2095 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2096 Assert(n_lines >= 0);
2098 // if you hit this, you proba
2099 if(n_lines >= MAX_DEBRIEF_LINES){
2100 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2103 for ( i=0; i<n_lines; i++ ) {
2104 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2105 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2106 strncpy(line, p_str[i], n_chars[i]);
2107 line[n_chars[i]] = 0;
2108 drop_white_space(line);
2109 Text_type[Num_text_lines] = type;
2110 Text[Num_text_lines++] = strdup(line);
2116 void debrief_free_text()
2120 for (i=0; i<Num_debrief_lines; i++)
2124 Num_debrief_lines = 0;
2127 // setup the debriefing text lines for rendering
2128 void debrief_text_init()
2133 // release old text lines first
2134 debrief_free_text();
2135 Num_text_lines = Text_offset = 0;
2137 if (Current_mode == DEBRIEF_TAB) {
2138 for (i=0; i<Num_debrief_stages; i++) {
2140 Text[Num_text_lines++] = NULL; // add a blank line between stages
2142 src = Debrief_stages[i]->new_text;
2144 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2146 if (Recommend_active) {
2147 src = Debrief_stages[i]->new_recommendation_text;
2148 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2149 src = XSTR( "We have no recommendations for you.", 1054);
2152 Text[Num_text_lines++] = NULL;
2153 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2159 Num_debrief_lines = Num_text_lines;
2163 // not in debriefing mode, must be in stats mode
2165 debrief_setup_ship_kill_stats(Current_stage);
2169 // --------------------------------------------------------------------------------------
2173 Assert(!Debrief_inited);
2174 // Campaign.loop_enabled = 0;
2175 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2177 // set up the right briefing for this guy
2178 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2179 Debriefing = &Debriefings[Net_player->p_info.team];
2181 Debriefing = &Debriefings[0];
2184 // no longer is mission
2185 Game_mode &= ~(GM_IN_MISSION);
2189 New_mode = DEBRIEF_TAB;
2190 Recommend_active = Award_active = 0;
2195 Debrief_cue_voice = 0;
2196 Num_text_lines = Num_debrief_lines = 0;
2197 Debrief_first_voice_flag = 1;
2199 Debrief_multi_voice_loaded = 0;
2201 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2202 // MUST store goals and events first - may be used to evaluate next mission
2203 // store goals and events
2204 mission_campaign_store_goals_and_events();
2206 // evaluate next mission
2207 mission_campaign_eval_next_mission();
2210 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2212 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2213 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2216 // call scoring level close for my stats. Needed for award_init. The stats will
2217 // be backed out if used chooses to replace them.
2218 scoring_level_close();
2220 debrief_ui_init(); // init UI items
2221 debrief_award_init();
2223 debrief_voice_init();
2224 debrief_multi_list_init();
2225 // rank_bitmaps_clear();
2226 // rank_bitmaps_load();
2228 strcpy(Debrief_current_callsign, Player->callsign);
2229 Debrief_player = Player;
2230 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2232 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2233 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2234 // info directly from the server.
2235 if ( !MULTIPLAYER_CLIENT ) {
2236 debrief_set_stages_and_multi_stuff();
2238 if ( Num_debrief_stages <= 0 ) {
2239 Num_debrief_stages = 0;
2241 debrief_voice_load_all();
2244 // multiplayer client may have already received their debriefing info. If they have not,
2245 // then set the num debrief stages to 0
2246 if ( !Debrief_multi_stages_loaded ) {
2247 Num_debrief_stages = 0;
2252 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2253 common_music_init(SCORE_DEBRIEF_SUCCESS);
2255 common_music_init(SCORE_DEBRIEF_FAIL);
2259 // start up the appropriate music
2260 if (Campaign.next_mission == Campaign.current_mission) {
2261 // you failed the mission because you suck, so you get the suck music
2262 common_music_init(SCORE_DEBRIEF_FAIL);
2263 } else if (mission_goals_met()) {
2264 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2265 common_music_init(SCORE_DEBRIEF_SUCCESS);
2267 // you somehow passed the mission, so you get a little something for your efforts.
2268 common_music_init(SCORE_DEBRIEF_AVERAGE);
2271 if (Campaign.next_mission == Campaign.current_mission) {
2272 // better luck next time, increase his retries
2273 Player->failures_this_session++;
2275 // clear his retries info regardless of whether or not he accepts
2276 Player->failures_this_session = 0;
2279 if (Game_mode & GM_MULTIPLAYER) {
2280 multi_debrief_init();
2282 // if i'm not the host of the game, disable the multi kick button
2283 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2284 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2287 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2288 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2289 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2290 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2291 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2292 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2293 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2294 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2297 if (!Award_active) {
2298 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2299 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2302 Debrief_skip_popup_already_shown = 0;
2307 // --------------------------------------------------------------------------------------
2309 void debrief_close()
2313 Assert(Debrief_inited);
2315 // if the mission wasn't accepted, clear out my stats
2316 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2317 // are a little bit different
2318 if (Game_mode & GM_MULTIPLAYER) {
2319 // if stats weren't accepted, backout my own stats
2320 if (multi_debrief_stats_accept_code() != 1) {
2321 if(MULTIPLAYER_MASTER){
2322 for(idx=0; idx<MAX_PLAYERS; idx++){
2323 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2324 scoring_backout_accept(&Net_players[idx].player->stats);
2328 scoring_backout_accept( &Player->stats );
2333 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2334 scoring_backout_accept( &Player->stats );
2338 // if dude passed the misson and accepted, reset his show skip popup flag
2339 if (Debrief_accepted) {
2340 Player->show_skip_popup = 1;
2343 if (Num_debrief_lines) {
2344 for (i=0; i<Num_debrief_lines; i++){
2351 // unload the overlay bitmap
2352 // help_overlay_unload(DEBRIEFING_OVERLAY);
2354 // clear out award text
2355 Debrief_award_text_num_lines = 0;
2357 debrief_voice_unload_all();
2358 common_music_close();
2361 // rank_bitmaps_release();
2364 if (Background_bitmap >= 0){
2365 bm_unload(Background_bitmap);
2368 if (Award_bg_bitmap >= 0){
2369 bm_unload(Award_bg_bitmap);
2372 if (Rank_bitmap >= 0){
2373 bm_unload(Rank_bitmap);
2376 if (Medal_bitmap >= 0){
2377 bm_unload(Medal_bitmap);
2380 if (Badge_bitmap >= 0){
2381 bm_unload(Badge_bitmap);
2384 if (Wings_bitmap >= 0) {
2385 bm_unload(Wings_bitmap);
2388 if (Crest_bitmap >= 0) {
2389 bm_unload(Crest_bitmap);
2392 Debrief_ui_window.destroy();
2393 common_free_interface_palette(); // restore game palette
2396 if (Game_mode & GM_MULTIPLAYER){
2397 multi_debrief_close();
2405 // handle keypresses in debriefing
2406 void debrief_do_keys(int new_k)
2413 case KEY_SHIFTED | KEY_TAB:
2421 // multiplayer accept popup is a little bit different
2422 if (Game_mode & GM_MULTIPLAYER) {
2423 multi_debrief_esc_hit();
2425 // display the normal debrief popup
2427 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2428 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2429 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2430 if (choice == 1) { // accept and continue on
2432 gameseq_post_event(GS_EVENT_MAIN_MENU);
2438 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2439 // need to popup saying that mission was a failure and must be replayed
2440 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));
2445 // Return to Main Hall
2446 gameseq_post_event(GS_EVENT_END_GAME);
2456 void debrief_draw_award_text()
2458 int start_y, curr_y, i, x, sw;
2459 int fh = gr_get_font_height();
2460 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];
2462 // vertically centered within field
2463 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);
2467 for (i=0; i<Debrief_award_text_num_lines; i++) {
2468 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2469 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2470 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2471 gr_set_color_fast(&Color_white);
2472 gr_string(x, curr_y, Debrief_award_text[i]);
2474 // adjust y pos, including a little extra between the "pairs"
2476 if ((i == 1) || (i == 3)) {
2477 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2482 // clears out text array so we dont have old award text showing up on new awards.
2483 void debrief_award_text_clear() {
2486 Debrief_award_text_num_lines = 0;
2487 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2488 //Debrief_award_text[i][0] = 0;
2489 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2493 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2494 void debrief_add_award_text(char *str)
2496 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2497 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2502 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];
2505 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2507 // maybe translate for displaying
2509 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2512 Debrief_award_text_num_lines++;
2514 // if its too long, split once ONLY
2515 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2516 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2517 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2518 if (line2 != NULL) {
2519 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2521 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2525 // called once per frame to drive all the input reading and rendering
2526 void debrief_do_frame(float frametime)
2529 char *please_wait_str = XSTR("Please Wait", 1242);
2533 Assert(Debrief_inited);
2535 // first thing is to load the files
2536 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2537 // draw the background, etc
2538 GR_MAYBE_CLEAR_RES(Background_bitmap);
2539 if (Background_bitmap >= 0) {
2540 gr_set_bitmap(Background_bitmap);
2544 Debrief_ui_window.draw();
2546 if ( Debrief_multi_loading_bitmap > -1 ){
2547 gr_set_bitmap(Debrief_multi_loading_bitmap);
2548 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2551 // draw "Please Wait"
2552 gr_set_color_fast(&Color_normal);
2554 gr_get_string_size(&str_w, &str_h, please_wait_str);
2555 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2560 // make sure we run the debrief do frame
2561 if (Game_mode & GM_MULTIPLAYER) {
2562 multi_debrief_do_frame();
2567 int keypress = game_check_key();
2568 if(keypress == KEY_ESC){
2570 multi_quit_game(PROMPT_CLIENT);
2576 // if multiplayer client, and not loaded voice, then load it
2577 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2578 debrief_multi_fixup_stages();
2579 debrief_voice_load_all();
2580 Debrief_multi_voice_loaded = 1;
2583 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2584 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2585 Debrief_ui_window.set_ignore_gadgets(1);
2588 k = chatbox_process();
2589 if ( Game_mode & GM_NORMAL ) {
2590 new_k = Debrief_ui_window.process(k);
2592 new_k = Debrief_ui_window.process(k, 0);
2595 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2596 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2597 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2598 Debrief_ui_window.set_ignore_gadgets(0);
2604 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2605 Debrief_ui_window.set_ignore_gadgets(0);
2608 // don't show pilot info popup by default
2609 Debrief_should_show_popup = 0;
2611 // see if the mode has changed and handle it if so.
2612 if ( Current_mode != New_mode ) {
2613 debrief_voice_stop();
2614 Current_mode = New_mode;
2617 if (New_mode == DEBRIEF_TAB) {
2619 Debrief_cue_voice = 0;
2621 if (Debrief_first_voice_flag) {
2622 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2623 Debrief_first_voice_flag = 0;
2626 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2630 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2631 Current_stage = New_stage;
2632 debrief_text_init();
2635 debrief_voice_play();
2638 if (Game_mode & GM_MULTIPLAYER) {
2639 multi_debrief_do_frame();
2642 // Now do all the rendering for the frame
2643 GR_MAYBE_CLEAR_RES(Background_bitmap);
2644 if (Background_bitmap >= 0) {
2645 gr_set_bitmap(Background_bitmap);
2649 // draw the damn awarded stuff, G
2650 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2651 gr_set_bitmap(Award_bg_bitmap);
2652 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2653 if (Rank_bitmap >= 0) {
2654 gr_set_bitmap(Rank_bitmap);
2655 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2658 if (Medal_bitmap >= 0) {
2659 gr_set_bitmap(Medal_bitmap);
2660 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2663 if (Badge_bitmap >= 0) {
2664 gr_set_bitmap(Badge_bitmap);
2665 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2668 if (Wings_bitmap >= 0) {
2669 gr_set_bitmap(Wings_bitmap);
2670 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2673 if (Crest_bitmap >= 0) {
2674 gr_set_bitmap(Crest_bitmap);
2675 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2678 // draw medal/badge/rank labels
2679 debrief_draw_award_text();
2681 /* if (Rank_text_bitmap >= 0) {
2682 gr_set_bitmap(Rank_text_bitmap);
2683 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2687 if (Medal_text_bitmap >= 0) {
2688 gr_set_bitmap(Medal_text_bitmap);
2689 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2692 if (Badge_text_bitmap >= 0) {
2693 gr_set_bitmap(Badge_text_bitmap);
2694 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2699 Debrief_ui_window.draw();
2700 debrief_redraw_pressed_buttons();
2701 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2702 if (Recommend_active && (Current_mode != STATS_TAB)) {
2703 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2706 // draw the title of the mission
2707 gr_set_color_fast(&Color_bright_white);
2708 strcpy(buf, The_mission.name);
2709 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2710 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2712 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2713 gr_set_color_fast(&Color_normal);
2714 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);
2717 // draw the screen-specific text
2718 switch (Current_mode) {
2720 if ( Num_debrief_stages <= 0 ) {
2721 gr_set_color_fast(&Color_white);
2722 Assert( Game_current_mission_filename != NULL );
2723 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);
2732 debrief_stats_render();
2736 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2739 gr_set_color_fast(&Color_red);
2740 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2741 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));
2744 debrief_render_stagenum();
2745 debrief_multi_list_draw();
2747 // render some extra stuff in multiplayer
2748 if (Game_mode & GM_MULTIPLAYER) {
2749 // render the chatbox last
2753 Debrief_ui_window.draw_tooltip();
2755 // render the status indicator for the voice system
2756 multi_common_voice_display_status();
2759 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2760 // want to include the mouse pointer which is drawn in the flip
2762 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2763 debrief_check_buttons();
2764 debrief_do_keys(new_k);
2767 // blit help overlay if active
2768 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2772 // dont let dude skip 3-09. hack.
2773 if(Game_mode & GM_CAMPAIGN_MODE){
2774 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2775 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2776 Debrief_skip_popup_already_shown = 1;
2781 // maybe show skip mission popup
2782 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)) {
2783 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
2784 XSTR("Advance To The Next Mission", 1474),
2785 XSTR("Don't Show Me This Again", 1475),
2786 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
2787 switch (popup_choice) {
2789 // stay on this mission, so proceed to normal debrief
2790 // in other words, do nothing.
2793 // skip this mission
2794 mission_campaign_skip_to_next();
2795 gameseq_post_event(GS_EVENT_START_GAME);
2798 // dont show this again
2799 Player->show_skip_popup = 0;
2803 Debrief_skip_popup_already_shown = 1;
2806 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
2807 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
2808 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
2809 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
2811 Debrief_should_show_popup = 0;
2815 void debrief_rebuild_player_list()
2819 debrief_multi_list_info *list;
2821 Multi_list_size = 0; // number of net players to choose from
2823 for ( i=0; i<MAX_PLAYERS; i++ ) {
2824 np = &Net_players[i];
2825 // remember not to include the standalone.
2826 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
2827 list = &Multi_list[Multi_list_size++];
2828 list->net_player_index = i;
2829 strcpy(list->callsign, np->player->callsign);
2831 // make sure to leave some room to blit the team indicator
2832 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
2837 void debrief_handle_player_drop()
2839 debrief_rebuild_player_list();
2842 void debrief_disable_accept()