2 * $Logfile: /Freespace2/code/MissionUI/MissionDebrief.cpp $
7 * C module for running the debriefing
10 * Revision 1.3 2002/05/26 22:06:17 relnev
11 * makefile: disable stand_gui for now.
13 * rest: staticize some globals
15 * Revision 1.2 2002/05/07 03:16:46 theoddone33
16 * The Great Newline Fix
18 * Revision 1.1.1.1 2002/05/03 03:28:10 root
22 * 57 10/29/99 10:40p Jefff
23 * hack to make german medal names display without actually changing them
25 * 56 10/13/99 3:26p Jefff
26 * fixed unnumbered XSTRs
28 * 55 10/06/99 10:28a Jefff
31 * 54 9/30/99 5:57p Jefff
32 * show upsell at end of campaign in OEM builds
34 * 53 9/15/99 3:42a Jefff
37 * 52 9/14/99 4:35a Dave
38 * Argh. Added all kinds of code to handle potential crashes in debriefing
41 * 51 9/14/99 3:26a Dave
42 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
43 * respawn-too-early problem. Made a few crash points safe.
45 * 50 9/14/99 12:51a Jefff
47 * 49 9/13/99 6:01p Jefff
48 * fixed wrong promotion voice mapping for sm1-08
50 * 48 9/13/99 11:15a Jefff
51 * clear out award text bug fixed
53 * 47 9/13/99 12:17p Andsager
54 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
57 * 46 9/07/99 9:35p Jefff
58 * fixed bug where award text was not getting cleared properly between
61 * 45 9/07/99 6:56p Jefff
62 * a few adjustments to loop detection
64 * 44 9/07/99 1:54p Jefff
65 * skip mission cleanup
67 * 43 9/06/99 9:45p Jefff
68 * skip mission support
70 * 42 9/06/99 6:38p Dave
71 * Improved CD detection code.
73 * 41 9/03/99 1:32a Dave
74 * CD checking by act. Added support to play 2 cutscenes in a row
75 * seamlessly. Fixed super low level cfile bug related to files in the
76 * root directory of a CD. Added cheat code to set campaign mission # in
79 * 40 9/02/99 3:45p Jefff
80 * forgot to remove some debug code. doh.
82 * 39 9/02/99 3:41p Jefff
83 * changed badge voice handling to be similar to promotion voice handling
85 * 38 9/01/99 4:41p Jefff
86 * fixed stoopid text color bug
88 * 37 8/31/99 11:54a Jefff
89 * minor debrief music tweak
91 * 36 8/27/99 9:57a Dave
92 * Enabled standard cheat codes. Allow player to continue in a campaing
93 * after using cheat codes.
95 * 35 8/27/99 12:04a Dave
96 * Campaign loop screen.
98 * 34 8/26/99 8:49p Jefff
99 * Updated medals screen and about everything that ever touches medals in
100 * one way or another. Sheesh.
102 * 33 8/20/99 4:20p Jefff
103 * hack for choosing the correct promotion voice
105 * 32 8/16/99 4:05p Dave
106 * Big honking checkin.
108 * 31 8/16/99 9:49a Jefff
109 * mission title length fix in multi
111 * 30 8/11/99 5:33p Jefff
112 * added 3rd debrief music track
114 * 29 8/10/99 7:28p Jefff
115 * shuffled some text around
117 * 28 8/04/99 5:36p Andsager
118 * Show upsell screens at end of demo campaign before returning to main
121 * 27 8/04/99 2:07p Jefff
122 * mission title no longer overwrites popup
124 * 26 8/02/99 5:37p Jefff
126 * 25 8/02/99 4:52p Jefff
127 * negative feedback sound when recommendations button pressed and
130 * 24 7/21/99 6:21p Jefff
131 * added hotkeys to the "you cannot accept" popup
133 * 23 6/15/99 12:04p Anoop
134 * Added a warning for running out of debrief text lines.
136 * 22 6/09/99 2:17p Dave
137 * Fixed up pleasewait bitmap rendering.
139 * 21 6/01/99 6:07p Dave
140 * New loading/pause/please wait bar.
142 * 20 5/22/99 6:05p Dave
143 * Fixed a few localization # problems.
145 * 19 5/22/99 5:35p Dave
146 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
148 * 18 3/20/99 3:47p Andsager
149 * Fix crash with no mission loop description.
151 * 17 2/23/99 2:29p Dave
152 * First run of oldschool dogfight mode.
154 * 16 2/21/99 6:01p Dave
155 * Fixed standalone WSS packets.
157 * 15 2/11/99 3:08p Dave
158 * PXO refresh button. Very preliminary squad war support.
160 * 14 1/30/99 5:08p Dave
161 * More new hi-res stuff.Support for nice D3D textures.
163 * 13 1/29/99 2:08a Dave
164 * Fixed beam weapon collisions with players. Reduced size of scoring
165 * struct for multiplayer. Disabled PXO.
167 * 12 1/14/99 5:15p Neilk
168 * changed credits, command debrief interfaces to high resolution support
170 * 11 1/13/99 2:11p Andsager
171 * change default debriefing string text
173 * 10 12/17/98 4:50p Andsager
174 * Added debrief_assemble_optional_mission_popup_text() for single and
177 * 9 12/12/98 3:17p Andsager
178 * Clean up mission eval, goal, event and mission scoring.
180 * 8 12/10/98 10:19a Andsager
181 * Fix mission loop assert
183 * 7 12/10/98 9:59a Andsager
184 * Fix some bugs with mission loops
186 * 6 12/09/98 1:56p Andsager
187 * Initial checkin of mission loop
189 * 5 11/05/98 4:18p Dave
190 * First run nebula support. Beefed up localization a bit. Removed all
191 * conditional compiles for foreign versions. Modified mission file
194 * 4 10/23/98 3:51p Dave
195 * Full support for tstrings.tbl and foreign languages. All that remains
196 * is to make it active in Fred.
198 * 3 10/13/98 9:28a Dave
199 * Started neatening up freespace.h. Many variables renamed and
200 * reorganized. Added AlphaColors.[h,cpp]
202 * 2 10/07/98 10:53a Dave
205 * 1 10/07/98 10:49a Dave
207 * 178 9/17/98 3:08p Dave
208 * PXO to non-pxo game warning popup. Player icon stuff in create and join
209 * game screens. Upped server count refresh time in PXO to 35 secs (from
212 * 177 7/07/98 1:46p Dave
213 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
216 * 175 6/09/98 10:31a Hoffoss
217 * Created index numbers for all xstr() references. Any new xstr() stuff
218 * added from here on out should be added to the end if the list. The
219 * current list count can be found in FreeSpace.cpp (search for
222 * 174 6/07/98 3:26p Lawrance
223 * Fix bug with cut-off popup text
225 * 173 6/05/98 9:54a Lawrance
228 * 172 6/01/98 11:43a John
229 * JAS & MK: Classified all strings for localization.
231 * 171 5/27/98 1:24p Allender
232 * make targeting dots work (as well as other targeting features) properly
233 * in multiplayer. Don't query for CD when entering debrief in
236 * 170 5/26/98 11:10a Lawrance
237 * Fix bug where window controls get disabled when F1 pressed twice
239 * 169 5/24/98 12:55a Mike
240 * Prevent Assert() when no debriefing text for a stage.
242 * 168 5/23/98 10:38p Lawrance
243 * Avoid doing a cfile refresh when running debug
245 * 167 5/23/98 6:49p Lawrance
246 * Fix problems with refreshing the file list when a CD is inserted
248 * 166 5/21/98 6:57p Lawrance
249 * Don't prompt for the CD if voice not found
251 * 165 5/20/98 2:24a Dave
252 * Fixed server side voice muting. Tweaked multi debrief/endgame
253 * sequencing a bit. Much friendlier for stats tossing/accepting now.
255 * 164 5/19/98 8:35p Dave
256 * Revamp PXO channel listing system. Send campaign goals/events to
257 * clients for evaluation. Made lock button pressable on all screens.
259 * 163 5/19/98 11:13a Hoffoss
260 * Fixed bug where wrong wings award was being displayed in debriefing.
262 * 162 5/19/98 12:28a Mike
265 * 161 5/18/98 8:08p Hoffoss
266 * Moved placement of 'More' text.
268 * 160 5/18/98 3:50p Dan
269 * AL: Pick correct traitor debriefing voice file
271 * 159 5/17/98 6:32p Dave
272 * Make sure clients/servers aren't kicked out of the debriefing when team
273 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
274 * xfer/pilot info popup stuff.
276 * 158 5/16/98 9:14p Allender
277 * fix scoring ckise fir training missions to actually count medals, but
278 * nothing else. Code used to Assert when wings were granted then taken
279 * away because they were actually never granted in scoring structure
281 * 157 5/15/98 5:15p Dave
282 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
283 * status for team vs. team. Put in asserts to check for invalid team vs.
286 * 156 5/15/98 4:36p Allender
287 * fixed minor bug with wings
289 * 155 5/15/98 4:12p Allender
290 * removed redbook code. Put back in ingame join timer. Major fixups for
291 * stats in multiplayer. Pass correct score, medals, etc when leaving
292 * game. Be sure clients display medals, badges, etc.
294 * 154 5/15/98 2:25p Jasen
295 * temporarily disable granting of promotion and badges for clients
297 * 153 5/15/98 10:57a Allender
298 * fixed client side debriefings
300 * 152 5/15/98 10:36a Dave
301 * Removed 2 bogus bitmap drawing Int3()'s
303 * 151 5/14/98 2:44p Hoffoss
304 * Added wings awarding to debrief screen.
306 * 150 5/13/98 9:11p Lawrance
307 * Make 'replay mission' popup warn users about the loss of mission stats.
312 #include "missiondebrief.h"
313 #include "missionbriefcommon.h"
314 #include "missionscreencommon.h"
315 #include "missiongoals.h"
316 #include "missionpause.h"
317 #include "freespace.h"
318 #include "gamesequence.h"
326 #include "audiostr.h"
329 #include "contexthelp.h"
335 #include "multimsgs.h"
336 #include "multiutil.h"
337 #include "multiteamselect.h"
339 #include "eventmusic.h"
343 #include "multi_pinfo.h"
344 #include "contexthelp.h"
345 #include "multi_kick.h"
346 #include "multi_campaign.h"
347 #include "alphacolors.h"
348 #include "localize.h"
349 #include "multi_endgame.h"
352 #define MAX_TOTAL_DEBRIEF_LINES 200
354 #define TEXT_TYPE_NORMAL 1
355 #define TEXT_TYPE_RECOMMENDATION 2
357 #define DEBRIEF_NUM_STATS_PAGES 4
358 #define DEBRIEF_MISSION_STATS 0
359 #define DEBRIEF_MISSION_KILLS 1
360 #define DEBRIEF_ALLTIME_STATS 2
361 #define DEBRIEF_ALLTIME_KILLS 3
363 // 3rd coord is max width in pixels
364 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
373 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
382 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
387 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
396 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
405 #define MULTI_LIST_TEAM_OFFSET 16
407 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
412 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
421 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
431 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
440 // 0=x, 1=y, 2=width of the field
441 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
450 // 0=x, 1=y, 2=height of the field
451 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
461 // 1 = without medal (text will use medal space)
462 #define DB_WITH_MEDAL 0
463 #define DB_WITHOUT_MEDAL 1
464 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
473 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
474 "DebriefSingle", // GR_640
475 "2_DebriefSingle" // GR_1024
477 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
478 "DebriefMulti", // GR_640
479 "2_DebriefMulti" // GR_1024
481 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
482 "Debrief-m", // GR_640
483 "2_Debrief-m" // GR_1024
486 #define NUM_BUTTONS 18
489 #define DEBRIEF_TAB 0
491 #define TEXT_SCROLL_UP 2
492 #define TEXT_SCROLL_DOWN 3
493 #define REPLAY_MISSION 4
494 #define RECOMMENDATIONS 5
495 #define FIRST_STAGE 6
499 #define MULTI_PINFO_POPUP 10
500 #define MULTI_KICK 11
501 #define MEDALS_BUTTON 12
502 #define PLAYER_SCROLL_UP 13
503 #define PLAYER_SCROLL_DOWN 14
504 #define HELP_BUTTON 15
505 #define OPTIONS_BUTTON 16
506 #define ACCEPT_BUTTON 17
511 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
512 "PleaseWait", // GR_640
513 "2_PleaseWait" // GR_1024
519 char text[NAME_LENGTH+1]; // name of ship type with a colon
520 int num; // how many ships of this type player has killed
521 } debrief_stats_kill_info;
524 int net_player_index; // index into Net_players[] array
525 int rank_bitmap; // bitmap id for rank
526 char callsign[CALLSIGN_LEN];
527 } debrief_multi_list_info;
529 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
531 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
532 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
533 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
534 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
535 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
536 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
537 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
538 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
539 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
540 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
541 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
542 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
543 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
544 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
545 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
546 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
547 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
548 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
551 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
552 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
553 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
554 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
555 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
556 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
557 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
558 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
559 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
560 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
561 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
562 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
563 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
564 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
565 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
566 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
567 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
568 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
573 #define NUM_DEBRIEF_TEXT 10
574 #define MP_TEXT_INDEX_1 4
575 #define MP_TEXT_INDEX_2 5
576 #define MP_TEXT_INDEX_3 6
577 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
579 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
580 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
581 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
582 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
583 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
584 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
585 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
586 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
587 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
588 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
591 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
592 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
593 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
594 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
595 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
596 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
597 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
598 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
599 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
600 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
605 char Debrief_current_callsign[CALLSIGN_LEN+10];
606 player *Debrief_player;
608 static UI_WINDOW Debrief_ui_window;
609 static UI_BUTTON List_region;
610 static int Background_bitmap; // bitmap for the background of the debriefing
611 static int Award_bg_bitmap;
612 static int Debrief_multi_loading_bitmap;
613 static int Rank_bitmap;
614 static int Medal_bitmap;
615 static int Badge_bitmap;
616 static int Wings_bitmap;
617 static int Crest_bitmap;
618 //static int Rank_text_bitmap;
619 //static int Medal_text_bitmap;
620 //static int Badge_text_bitmap;
622 static int Debrief_accepted;
623 static int Turned_traitor;
624 static int Must_replay_mission;
626 static int Current_mode;
628 static int Recommend_active;
629 static int Award_active;
630 static int Text_offset;
631 static int Num_text_lines = 0;
632 static int Num_debrief_lines = 0;
633 static int Num_normal_debrief_lines = 0;
634 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
635 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
637 static int Debrief_inited = 0;
638 static int New_stage;
639 static int Current_stage;
640 static int Num_stages;
641 static int Num_debrief_stages;
642 static int Stage_voice;
644 static int Multi_list_size;
645 static int Multi_list_offset;
647 int Debrief_multi_stages_loaded = 0;
648 int Debrief_multi_voice_loaded = 0;
650 // static int Debrief_voice_ask_for_cd;
652 // voice id's for debriefing text
653 static int Debrief_voices[MAX_DEBRIEF_STAGES];
655 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
656 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
657 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
659 // pointer used for getting to debriefing information
660 debriefing Traitor_debriefing; // used when player is a traitor
662 // pointers to the active stages for this debriefing
663 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
664 static debrief_stage Promotion_stage, Badge_stage;
665 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
666 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
667 int Multi_list_select;
669 // flag indicating if we should display info for the given player (in multiplayer)
670 int Debrief_should_show_popup = 1;
672 // already shown skip mission popup?
673 static int Debrief_skip_popup_already_shown = 0;
675 void debrief_text_init();
676 void debrief_accept(int ok_to_post_start_game_event = 1);
677 void debrief_kick_selected_player();
680 // promotion voice selection stuff
681 #define NUM_VOLITION_CAMPAIGNS 1
683 char campaign_name[32];
685 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
687 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
688 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
692 // data for which voice goes w/ which mission
693 typedef struct voice_map {
694 char mission_file[32];
698 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
699 { // FreeSpace2 campaign
731 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
733 { "loop1-1.fs2", 4 },
734 { "loop1-2.fs2", 4 },
735 { "loop1-3.fs2", 5 },
736 { "loop2-1.fs2", 4 },
741 #define DB_AWARD_WINGS 0
742 #define DB_AWARD_MEDAL 1
743 #define DB_AWARD_SOC 2
744 #define DB_AWARD_RANK 3
745 #define DB_AWARD_BADGE 4
746 #define DB_AWARD_BG 5
747 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
766 #define AWARD_TEXT_MAX_LINES 5
767 #define AWARD_TEXT_MAX_LINE_LENGTH 128
768 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
769 int Debrief_award_text_num_lines = 0;
773 // prototypes, you know you love 'em
774 void debrief_add_award_text(char *str);
775 void debrief_award_text_clear();
780 char *debrief_tooltip_handler(char *str)
782 if (!stricmp(str, NOX("@.Medal"))) {
784 return XSTR( "Medal", 435);
787 } else if (!stricmp(str, NOX("@.Rank"))) {
789 return XSTR( "Rank", 436);
792 } else if (!stricmp(str, NOX("@.Badge"))) {
794 return XSTR( "Badge", 437);
797 } else if (!stricmp(str, NOX("@Medal"))) {
798 if (Medal_bitmap >= 0){
799 return Medals[Player->stats.m_medal_earned].name;
802 } else if (!stricmp(str, NOX("@Rank"))) {
803 if (Rank_bitmap >= 0){
804 return Ranks[Promoted].name;
807 } else if (!stricmp(str, NOX("@Badge"))) {
808 if (Badge_bitmap >= 0){
809 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
816 // initialize the array of handles to the different voice streams
817 void debrief_voice_init()
821 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
822 Debrief_voices[i] = -1;
826 void debrief_load_voice_file(int voice_num, char *name)
828 int load_attempts = 0;
831 if ( load_attempts++ > 5 ) {
835 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
836 if ( Debrief_voices[voice_num] >= 0 ) {
840 // Don't bother to ask for the CD in multiplayer
841 if ( Game_mode & GM_MULTIPLAYER ) {
845 // couldn't load voice, ask user to insert CD (if necessary)
847 // if ( Debrief_voice_ask_for_cd ) {
848 // if ( game_do_cd_check() == 0 ) {
849 // Debrief_voice_ask_for_cd = 0;
856 // open and pre-load the stream buffers for the different voice streams
857 void debrief_voice_load_all()
861 // Debrief_voice_ask_for_cd = 1;
863 for ( i=0; i<Num_debrief_stages; i++ ) {
864 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
867 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
868 debrief_load_voice_file(i, Debrief_stages[i]->voice);
869 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
874 // close all the briefing voice streams
875 void debrief_voice_unload_all()
879 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
880 if ( Debrief_voices[i] != -1 ) {
881 audiostream_close_file(Debrief_voices[i], 0);
882 Debrief_voices[i] = -1;
887 // start playback of the voice for a particular briefing stage
888 void debrief_voice_play()
890 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
894 // no more stages? We are done then.
895 if (Stage_voice >= Num_debrief_stages){
899 // if in delayed start, see if delay has elapsed and start voice if so
900 if (Debrief_cue_voice) {
901 if (!timestamp_elapsed(Debrief_cue_voice)){
905 Stage_voice++; // move up to next voice
906 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
907 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
908 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
914 // see if voice is still playing. If so, do nothing yet.
915 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
919 // set voice to play in a little while from now.
920 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
923 // stop playback of the voice for a particular briefing stage
924 void debrief_voice_stop()
926 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
929 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
933 // function to deal with inserting possible promition and badge stages into the debriefing
935 void debrief_multi_fixup_stages()
939 // possibly insert the badge stage first, them the promotion stage since they are
940 // inserted at the front of the debrief stages.
941 if ( Badge_bitmap >= 0 ) {
942 // move all stages forward one. Don't
943 for ( i = Num_debrief_stages; i > 0; i-- ) {
944 Debrief_stages[i] = Debrief_stages[i-1];
946 Debrief_stages[0] = &Badge_stage;
947 Num_debrief_stages++;
950 if ( Promoted >= 0) {
951 // move all stages forward one
952 for ( i = Num_debrief_stages; i > 0; i-- ) {
953 Debrief_stages[i] = Debrief_stages[i-1];
955 Debrief_stages[0] = &Promotion_stage;
956 Num_debrief_stages++;
961 // function called from multiplayer clients to set up the debriefing information for them
962 // (sent from the server).
963 void debrief_set_multi_clients( int stage_count, int active_stages[] )
967 // set up the right briefing for this guy
968 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
969 Debriefing = &Debriefings[Net_player->p_info.team];
971 Debriefing = &Debriefings[0];
974 // see if this client was promoted -- if so, then add the first stage.
975 Num_debrief_stages = 0;
977 // set the pointers to the debriefings for this client
978 for (i = 0; i < stage_count; i++) {
979 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
982 Debrief_multi_stages_loaded = 1;
985 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
986 // information to all clients after leaving this screen.
987 void debrief_multi_server_stuff()
989 debriefing *debriefp;
991 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
992 int i, j, num_stages, stage_count[MAX_TEAMS];
994 memset( stage_active, 0, sizeof(stage_active) );
996 for (i=0; i<Num_teams; i++) {
997 debriefp = &Debriefings[i];
999 stages[i] = stage_active[i];
1000 for (j=0; j<debriefp->num_stages; j++) {
1001 if ( eval_sexp(debriefp->stages[j].formula) ) {
1002 stage_active[i][num_stages] = j;
1007 stage_count[i] = num_stages;
1010 // if we're in campaign mode, evaluate campaign stuff
1011 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1012 multi_campaign_eval_debrief();
1015 // send the information to all clients.
1016 send_debrief_info( stage_count, stages );
1020 // --------------------------------------------------------------------------------------
1021 // debrief_set_stages_and_multi_stuff()
1023 // Set up the active stages for this debriefing
1025 // returns: number of active debriefing stages
1027 int debrief_set_stages_and_multi_stuff()
1030 debriefing *debriefp;
1032 if ( MULTIPLAYER_CLIENT ) {
1036 Num_debrief_stages = 0;
1038 if ( Game_mode & GM_MULTIPLAYER ) {
1039 debrief_multi_server_stuff();
1042 // check to see if player is a traitor (looking at his team). If so, use the special
1043 // traitor debriefing. Only done in single player
1044 debriefp = Debriefing;
1045 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1046 if (Player_ship->team == TEAM_TRAITOR)
1047 debriefp = &Traitor_debriefing;
1050 Num_debrief_stages = 0;
1051 if (Promoted >= 0) {
1052 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1055 if (Badge_bitmap >= 0) {
1056 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1059 for (i=0; i<debriefp->num_stages; i++) {
1060 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1061 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1065 return Num_debrief_stages;
1068 // init the buttons that are specific to the debriefing screen
1069 void debrief_buttons_init()
1074 for ( i=0; i<NUM_BUTTONS; i++ ) {
1075 b = &Buttons[gr_screen.res][i];
1076 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1077 // set up callback for when a mouse first goes over a button
1078 b->button.set_highlight_action( common_play_highlight_sound );
1079 b->button.set_bmaps(b->filename);
1080 b->button.link_hotspot(b->hotspot);
1084 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1085 // multiplayer specific text
1086 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1087 // only add if in multiplayer mode
1088 if(Game_mode & GM_MULTIPLAYER){
1089 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1094 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1098 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1099 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1100 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1101 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1102 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1103 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1104 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1105 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1107 // if in multiplayer, disable the button for all players except the host
1108 // also disable for squad war matches
1109 if(Game_mode & GM_MULTIPLAYER){
1110 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1111 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1116 // --------------------------------------------------------------------------------------
1117 // debrief_ui_init()
1119 void debrief_ui_init()
1121 // init ship selection masks and buttons
1122 common_set_interface_palette("DebriefPalette"); // set the interface palette
1123 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1124 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1125 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1126 debrief_buttons_init();
1128 // load in help overlay bitmap
1129 help_overlay_load(DEBRIEFING_OVERLAY);
1130 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1132 if ( Game_mode & GM_MULTIPLAYER ) {
1133 // close down any old instances of the chatbox
1136 // create the new one
1138 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1139 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);
1142 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1145 if ( Background_bitmap < 0 ) {
1146 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1149 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1150 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1153 // sets Promotion_stage.voice
1154 // defaults to number 9 (Petrarch) for non-volition missions
1155 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1156 void debrief_choose_promotion_voice()
1160 if(Campaign.current_mission < 0){
1161 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1165 // search thru all official campaigns for our current campaign
1166 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1167 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1168 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1169 // now search thru the mission filenames,
1170 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1171 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1172 // found it! set the persona and bail
1173 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1181 // default to petrarch
1182 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1185 // sets Promotion_stage.voice
1186 // defaults to number 9 (Petrarch) for non-volition missions
1187 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1188 void debrief_choose_badge_voice()
1192 if(Campaign.current_mission < 0){
1193 // default to petrarch
1194 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1197 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1198 // search thru all official campaigns for our current campaign
1199 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1200 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1201 // now search thru the mission filenames,
1202 for (j=0; j<Campaign.num_missions; j++) {
1203 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1204 // found it! set the persona and bail
1205 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1213 // default to petrarch
1214 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1218 void debrief_award_init()
1230 // be sure there are no old award texts floating around
1231 debrief_award_text_clear();
1233 // handle medal earned
1234 if (Player->stats.m_medal_earned != -1) {
1235 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1237 if ( Player->stats.medals[13] > 1 ) {
1242 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1243 Wings_bitmap = bm_load(buf);
1245 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1246 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1248 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1249 Medal_bitmap = bm_load(buf);
1252 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1255 // handle promotions
1256 if ( Player->stats.m_promotion_earned != -1 ) {
1257 Promoted = Player->stats.m_promotion_earned;
1258 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1259 Rank_bitmap = bm_load(buf);
1261 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1262 Promotion_stage.new_recommendation_text = NULL;
1264 // choose appropriate promotion voice for this mission
1265 debrief_choose_promotion_voice();
1267 debrief_add_award_text(Ranks[Promoted].name);
1270 // handle badge earned
1271 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1272 if ( Player->stats.m_badge_earned != -1 ) {
1273 i = Player->stats.m_badge_earned;
1274 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1275 Badge_bitmap = bm_load(buf);
1277 Badge_stage.new_text = Badge_info[i].promotion_text;
1278 Badge_stage.new_recommendation_text = NULL;
1280 // choose appropriate voice
1281 debrief_choose_badge_voice();
1283 debrief_add_award_text(Medals[Badge_index[i]].name);
1286 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1293 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1294 // mission a traitor. The same debriefing always gets played
1295 void debrief_traitor_init()
1297 static int inited = 0;
1300 debriefing *debrief;
1301 debrief_stage *stagep;
1305 if ((rval = setjmp(parse_abort)) != 0) {
1306 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1309 read_file_text("traitor.tbl");
1313 // open localization
1316 // simplied form of the debriefing stuff.
1317 debrief = &Traitor_debriefing;
1318 required_string("#Debriefing_info");
1320 required_string("$Num stages:");
1321 stuff_int(&debrief->num_stages);
1322 Assert(debrief->num_stages == 1);
1325 stagep = &debrief->stages[stage_num++];
1326 required_string("$Formula:");
1327 stagep->formula = get_sexp_main();
1328 required_string("$multi text");
1329 if ( Fred_running ) {
1330 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1332 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1334 required_string("$Voice:");
1335 char traitor_voice_file[NAME_LENGTH];
1336 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1338 // DKA 9/13/99 Only 1 traitor msg for FS2
1339 // if ( Player->on_bastion ) {
1340 // strcpy(stagep->voice, NOX("3_"));
1342 // strcpy(stagep->voice, NOX("1_"));
1345 strcat(stagep->voice, traitor_voice_file);
1347 required_string("$Recommendation text:");
1348 if ( Fred_running ) {
1349 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1351 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1355 // close localization
1359 // disable the accept button if in single player and I am a traitor
1360 Debrief_accepted = 0;
1361 Turned_traitor = Must_replay_mission = 0;
1362 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1363 if (Player_ship->team == TEAM_TRAITOR){
1367 if (Campaign.next_mission == Campaign.current_mission){
1368 Must_replay_mission = 1;
1372 if (Turned_traitor || Must_replay_mission) {
1373 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1375 // kill off any stats
1376 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1377 scoring_level_init( &Player->stats );
1381 // initialization for listing of players in game
1382 void debrief_multi_list_init()
1384 Multi_list_size = 0; // number of net players to choose from
1385 Multi_list_offset = 0;
1387 Multi_list_select = -1;
1389 if ( !(Game_mode & GM_MULTIPLAYER) )
1392 debrief_rebuild_player_list();
1394 // switch stats display to this newly selected player
1395 set_player_stats(Multi_list[0].net_player_index);
1396 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1397 Debrief_player = Player;
1400 void debrief_multi_list_scroll_up()
1402 // if we're at the beginning of the list, don't do anything
1403 if(Multi_list_offset == 0){
1404 gamesnd_play_iface(SND_GENERAL_FAIL);
1408 // otherwise scroll up
1409 Multi_list_offset--;
1410 gamesnd_play_iface(SND_USER_SELECT);
1413 void debrief_multi_list_scroll_down()
1415 // if we can scroll down no further
1416 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1417 gamesnd_play_iface(SND_GENERAL_FAIL);
1420 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1421 gamesnd_play_iface(SND_GENERAL_FAIL);
1425 // otherwise scroll down
1426 Multi_list_offset++;
1427 gamesnd_play_iface(SND_USER_SELECT);
1430 // draw the connected net players
1431 void debrief_multi_list_draw()
1433 int y, z, font_height,idx;
1434 char str[CALLSIGN_LEN+5];
1437 font_height = gr_get_font_height();
1439 // if we currently have no item picked, pick a reasonable one
1440 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1441 // select the entry which corresponds to the local player
1442 Multi_list_select = 0;
1443 for(idx=0;idx<Multi_list_size;idx++){
1444 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1445 Multi_list_select = idx;
1447 // switch stats display to this newly selected player
1448 set_player_stats(Multi_list[idx].net_player_index);
1449 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1450 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1456 // draw the list itself
1458 z = Multi_list_offset;
1459 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1460 np = &Net_players[Multi_list[z].net_player_index];
1462 if (z >= Multi_list_size){
1465 // set the proper text color for the highlight
1466 if(np->flags & NETINFO_FLAG_GAME_HOST){
1467 if(Multi_list_select == z){
1468 gr_set_color_fast(&Color_text_active_hi);
1470 gr_set_color_fast(&Color_bright);
1473 if(Multi_list_select == z){
1474 gr_set_color_fast(&Color_text_active);
1476 gr_set_color_fast(&Color_text_normal);
1480 // blit the proper indicator - skipping observers
1481 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1482 if(Netgame.type_flags & NG_TYPE_TEAM){
1484 if(np->p_info.team == 0){
1485 // draw his "selected" icon
1486 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1487 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1488 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1490 // draw his "normal" icon
1491 else if(Multi_common_icons[MICON_TEAM0] != -1){
1492 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1493 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1495 } else if(np->p_info.team == 1){
1496 // draw his "selected" icon
1497 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1498 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1499 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1501 // draw his "normal" icon
1502 else if(Multi_common_icons[MICON_TEAM1] != -1){
1503 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1504 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1508 // draw the team 0 selected icon
1509 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1510 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1511 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1516 strcpy(str,Multi_list[z].callsign);
1517 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)){
1518 strcat(str,XSTR( "(O)", 438));
1522 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1529 void debrief_kick_selected_player()
1531 if(Multi_list_select >= 0){
1532 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1533 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1537 // get optional mission popup text
1538 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1540 Assert(buffer != NULL);
1543 if (mission_loop_desc == NULL) {
1544 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1545 mprintf(("No mission loop description avail"));
1547 strcpy(buffer, mission_loop_desc);
1550 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1553 // what to do when the accept button is hit
1554 void debrief_accept(int ok_to_post_start_game_event)
1558 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1562 if (Game_mode & GM_MULTIPLAYER) {
1566 if (Player_ship->team == TEAM_TRAITOR){
1567 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1568 }/* else if (Cheats_enabled) {
1569 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1571 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1574 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1576 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1577 } else if ( z == 1 ) {
1578 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1584 Debrief_accepted = 1;
1585 // save mission stats
1586 if (Game_mode & GM_MULTIPLAYER) {
1587 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1588 // as well as doing stats transfers, etc.
1589 multi_debrief_accept_hit();
1593 int play_commit_sound = 1;
1594 // only write the player's stats if he's accepted
1596 // if we are just playing a single mission, then don't do many of the things
1597 // that need to be done. Nothing much should happen when just playing a single
1598 // mission that isn't in a campaign.
1599 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1601 // check for possible mission loop
1602 // check for (1) mission loop available, (2) dont have to repeat last mission
1603 if(!(Game_mode & GM_MULTIPLAYER)){
1604 int cur = Campaign.current_mission;
1605 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1606 if (Campaign.missions[cur].has_mission_loop) {
1607 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1610 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1613 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1615 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1617 Campaign.loop_enabled = 1;
1618 Campaign.next_mission = Campaign.loop_mission;
1627 if(ok_to_post_start_game_event){
1628 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1630 play_commit_sound = 0;
1633 // continue as normal
1636 mission_campaign_mission_over();
1638 // check to see if we are out of the loop now
1639 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1640 Campaign.loop_enabled = 0;
1643 // check if campaign is over
1644 if ( Campaign.next_mission == -1 ) {
1645 #if defined(FS2_DEMO) || defined(OEM_BUILD)
1646 gameseq_post_event(GS_EVENT_END_DEMO);
1648 gameseq_post_event(GS_EVENT_MAIN_MENU);
1651 if ( ok_to_post_start_game_event ) {
1653 if(game_do_cd_mission_check(Game_current_mission_filename)){
1654 gameseq_post_event(GS_EVENT_START_GAME);
1656 gameseq_post_event(GS_EVENT_MAIN_MENU);
1659 play_commit_sound = 0;
1664 gameseq_post_event(GS_EVENT_MAIN_MENU);
1667 if ( play_commit_sound ) {
1668 gamesnd_play_iface(SND_COMMIT_PRESSED);
1675 void debrief_next_tab()
1677 New_mode = Current_mode + 1;
1678 if (New_mode >= NUM_TABS)
1682 void debrief_prev_tab()
1684 New_mode = Current_mode - 1;
1686 New_mode = NUM_TABS - 1;
1689 // --------------------------------------------------------------------------------------
1690 // debrief_next_stage()
1692 void debrief_next_stage()
1694 if (Current_stage < Num_stages - 1) {
1695 New_stage = Current_stage + 1;
1696 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1699 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1702 // --------------------------------------------------------------------------------------
1703 // debrief_prev_stage()
1705 void debrief_prev_stage()
1707 if (Current_stage) {
1708 New_stage = Current_stage - 1;
1709 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1712 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1715 // --------------------------------------------------------------------------------------
1716 // debrief_first_stage()
1717 void debrief_first_stage()
1719 if (Current_stage) {
1721 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1724 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1727 // --------------------------------------------------------------------------------------
1728 // debrief_last_stage()
1729 void debrief_last_stage()
1731 if (Current_stage != Num_stages - 1) {
1732 New_stage = Num_stages - 1;
1733 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1736 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1739 // draw what stage number the debriefing is on
1740 void debrief_render_stagenum()
1748 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1749 gr_get_string_size(&w, NULL, buf);
1750 gr_set_color_fast(&Color_bright_blue);
1751 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1752 gr_set_color_fast(&Color_white);
1755 // render the mission time at the specified y location
1756 void debrief_render_mission_time(int y_loc)
1760 game_format_time(Missiontime, time_str);
1761 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1762 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1765 // render out the debriefing text to the scroll window
1766 void debrief_render()
1768 int y, z, font_height;
1770 if ( Num_stages <= 0 )
1773 font_height = gr_get_font_height();
1775 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]);
1778 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1779 if (z >= Num_text_lines)
1782 if (Text_type[z] == TEXT_TYPE_NORMAL)
1783 gr_set_color_fast(&Color_white);
1785 gr_set_color_fast(&Color_bright_red);
1788 gr_string(0, y, Text[z]);
1797 // render out the stats info to the scroll window
1799 void debrief_stats_render()
1801 int i, y, font_height;
1803 gr_set_color_fast(&Color_blue);
1804 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]);
1805 gr_string(0, 0, Debrief_current_callsign);
1806 font_height = gr_get_font_height();
1809 switch ( Current_stage ) {
1810 case DEBRIEF_MISSION_STATS:
1811 i = Current_stage - 1;
1815 gr_set_color_fast(&Color_white);
1817 // display mission completion time
1818 debrief_render_mission_time(y);
1821 show_stats_label(i, 0, y, font_height);
1822 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1824 case DEBRIEF_ALLTIME_STATS:
1825 i = Current_stage - 1;
1829 gr_set_color_fast(&Color_white);
1830 show_stats_label(i, 0, y, font_height);
1831 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1834 case DEBRIEF_ALLTIME_KILLS:
1835 case DEBRIEF_MISSION_KILLS:
1836 gr_set_color_fast(&Color_white);
1838 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1839 if (i >= Num_text_lines)
1843 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1844 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
1846 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
1849 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
1850 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
1857 if (Num_text_lines == 2) {
1858 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1859 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
1861 gr_printf(0, y, XSTR( "(No ship kills)", 450));
1874 // do action for when the replay button is pressed
1875 void debrief_replay_pressed()
1877 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
1879 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));
1886 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
1887 gamesnd_play_iface(SND_COMMIT_PRESSED);
1890 // -------------------------------------------------------------------
1891 // debrief_redraw_pressed_buttons()
1893 // Redraw any debriefing buttons that are pressed down. This function is needed
1894 // since we sometimes need to draw pressed buttons last to ensure the entire
1895 // button gets drawn (and not overlapped by other buttons)
1897 void debrief_redraw_pressed_buttons()
1902 for ( i=0; i<NUM_BUTTONS; i++ ) {
1903 b = &Buttons[gr_screen.res][i].button;
1904 // don't draw the recommendations button if we're in stats mode
1905 if ( b->button_down() ) {
1911 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
1913 void debrief_button_pressed(int num)
1917 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
1918 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
1919 if (num != Current_mode){
1920 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1925 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
1926 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
1927 if (num != Current_mode){
1928 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1933 case TEXT_SCROLL_UP:
1936 gamesnd_play_iface(SND_SCROLL);
1938 gamesnd_play_iface(SND_GENERAL_FAIL);
1942 case TEXT_SCROLL_DOWN:
1943 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
1945 gamesnd_play_iface(SND_SCROLL);
1947 gamesnd_play_iface(SND_GENERAL_FAIL);
1951 case REPLAY_MISSION:
1952 if(Game_mode & GM_MULTIPLAYER){
1953 multi_debrief_replay_hit();
1955 debrief_replay_pressed();
1959 case RECOMMENDATIONS:
1960 gamesnd_play_iface(SND_USER_SELECT);
1961 Recommend_active = !Recommend_active;
1962 debrief_text_init();
1966 debrief_first_stage();
1970 debrief_prev_stage();
1974 debrief_next_stage();
1978 debrief_last_stage();
1982 gamesnd_play_iface(SND_HELP_PRESSED);
1983 launch_context_help();
1986 case OPTIONS_BUTTON:
1987 gamesnd_play_iface(SND_SWITCH_SCREENS);
1988 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
1996 gamesnd_play_iface(SND_SWITCH_SCREENS);
1997 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2000 case PLAYER_SCROLL_UP:
2001 debrief_multi_list_scroll_up();
2004 case PLAYER_SCROLL_DOWN:
2005 debrief_multi_list_scroll_down();
2008 case MULTI_PINFO_POPUP:
2009 Debrief_should_show_popup = 1;
2013 debrief_kick_selected_player();
2018 void debrief_setup_ship_kill_stats(int stage_num)
2022 debrief_stats_kill_info *kill_info;
2024 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2025 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2028 Assert(Debrief_player != NULL);
2030 // kill_ar points to an array of MAX_SHIP_TYPE ints
2031 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2032 kill_arr = Debrief_player->stats.m_okKills;
2034 kill_arr = Debrief_player->stats.kills;
2038 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2040 // code used to add in mission kills, but the new system assumes that the player will accept, so
2041 // all time stats already have mission stats added in.
2042 if ( kill_arr[i] <= 0 ){
2047 kill_info = &Debrief_stats_kills[Num_text_lines++];
2049 kill_info->num = kill_arr[i];
2051 strcpy(kill_info->text, Ship_info[i].name);
2052 strcat(kill_info->text, NOX(":"));
2055 Num_text_lines += 2;
2058 // Iterate through the debriefing buttons, checking if they are pressed
2059 void debrief_check_buttons()
2063 for ( i=0; i<NUM_BUTTONS; i++ ) {
2064 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2065 debrief_button_pressed(i);
2069 if ( !(Game_mode & GM_MULTIPLAYER) )
2072 if (List_region.pressed()) {
2073 List_region.get_mouse_pos(NULL, &y);
2074 z = Multi_list_offset + y / gr_get_font_height();
2075 if ((z >= 0) && (z < Multi_list_size)) {
2076 // switch stats display to this newly selected player
2077 set_player_stats(Multi_list[z].net_player_index);
2078 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2079 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2080 Multi_list_select = z;
2081 debrief_setup_ship_kill_stats(Current_stage);
2082 gamesnd_play_iface(SND_USER_SELECT);
2086 // if the player was double clicked on - we should popup a player info popup
2088 if (List_region.double_clicked()) {
2089 Debrief_should_show_popup = 1;
2094 void debrief_text_stage_init(char *src, int type)
2096 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2097 char line[MAX_DEBRIEF_LINE_LEN];
2098 char *p_str[MAX_DEBRIEF_LINES];
2100 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2101 Assert(n_lines >= 0);
2103 // if you hit this, you proba
2104 if(n_lines >= MAX_DEBRIEF_LINES){
2105 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2108 for ( i=0; i<n_lines; i++ ) {
2109 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2110 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2111 strncpy(line, p_str[i], n_chars[i]);
2112 line[n_chars[i]] = 0;
2113 drop_white_space(line);
2114 Text_type[Num_text_lines] = type;
2115 Text[Num_text_lines++] = strdup(line);
2121 void debrief_free_text()
2125 for (i=0; i<Num_debrief_lines; i++)
2129 Num_debrief_lines = 0;
2132 // setup the debriefing text lines for rendering
2133 void debrief_text_init()
2138 // release old text lines first
2139 debrief_free_text();
2140 Num_text_lines = Text_offset = 0;
2142 if (Current_mode == DEBRIEF_TAB) {
2143 for (i=0; i<Num_debrief_stages; i++) {
2145 Text[Num_text_lines++] = NULL; // add a blank line between stages
2147 src = Debrief_stages[i]->new_text;
2149 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2151 if (Recommend_active) {
2152 src = Debrief_stages[i]->new_recommendation_text;
2153 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2154 src = XSTR( "We have no recommendations for you.", 1054);
2157 Text[Num_text_lines++] = NULL;
2158 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2164 Num_debrief_lines = Num_text_lines;
2168 // not in debriefing mode, must be in stats mode
2170 debrief_setup_ship_kill_stats(Current_stage);
2174 // --------------------------------------------------------------------------------------
2178 Assert(!Debrief_inited);
2179 // Campaign.loop_enabled = 0;
2180 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2182 // set up the right briefing for this guy
2183 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2184 Debriefing = &Debriefings[Net_player->p_info.team];
2186 Debriefing = &Debriefings[0];
2189 // no longer is mission
2190 Game_mode &= ~(GM_IN_MISSION);
2194 New_mode = DEBRIEF_TAB;
2195 Recommend_active = Award_active = 0;
2200 Debrief_cue_voice = 0;
2201 Num_text_lines = Num_debrief_lines = 0;
2202 Debrief_first_voice_flag = 1;
2204 Debrief_multi_voice_loaded = 0;
2206 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2207 // MUST store goals and events first - may be used to evaluate next mission
2208 // store goals and events
2209 mission_campaign_store_goals_and_events();
2211 // evaluate next mission
2212 mission_campaign_eval_next_mission();
2215 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2217 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2218 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2221 // call scoring level close for my stats. Needed for award_init. The stats will
2222 // be backed out if used chooses to replace them.
2223 scoring_level_close();
2225 debrief_ui_init(); // init UI items
2226 debrief_award_init();
2228 debrief_voice_init();
2229 debrief_multi_list_init();
2230 // rank_bitmaps_clear();
2231 // rank_bitmaps_load();
2233 strcpy(Debrief_current_callsign, Player->callsign);
2234 Debrief_player = Player;
2235 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2237 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2238 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2239 // info directly from the server.
2240 if ( !MULTIPLAYER_CLIENT ) {
2241 debrief_set_stages_and_multi_stuff();
2243 if ( Num_debrief_stages <= 0 ) {
2244 Num_debrief_stages = 0;
2246 debrief_voice_load_all();
2249 // multiplayer client may have already received their debriefing info. If they have not,
2250 // then set the num debrief stages to 0
2251 if ( !Debrief_multi_stages_loaded ) {
2252 Num_debrief_stages = 0;
2257 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2258 common_music_init(SCORE_DEBRIEF_SUCCESS);
2260 common_music_init(SCORE_DEBRIEF_FAIL);
2264 // start up the appropriate music
2265 if (Campaign.next_mission == Campaign.current_mission) {
2266 // you failed the mission because you suck, so you get the suck music
2267 common_music_init(SCORE_DEBRIEF_FAIL);
2268 } else if (mission_goals_met()) {
2269 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2270 common_music_init(SCORE_DEBRIEF_SUCCESS);
2272 // you somehow passed the mission, so you get a little something for your efforts.
2273 common_music_init(SCORE_DEBRIEF_AVERAGE);
2276 if (Campaign.next_mission == Campaign.current_mission) {
2277 // better luck next time, increase his retries
2278 Player->failures_this_session++;
2280 // clear his retries info regardless of whether or not he accepts
2281 Player->failures_this_session = 0;
2284 if (Game_mode & GM_MULTIPLAYER) {
2285 multi_debrief_init();
2287 // if i'm not the host of the game, disable the multi kick button
2288 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2289 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2292 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2293 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2294 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2295 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2296 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2297 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2298 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2299 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2302 if (!Award_active) {
2303 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2304 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2307 Debrief_skip_popup_already_shown = 0;
2312 // --------------------------------------------------------------------------------------
2314 void debrief_close()
2318 Assert(Debrief_inited);
2320 // if the mission wasn't accepted, clear out my stats
2321 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2322 // are a little bit different
2323 if (Game_mode & GM_MULTIPLAYER) {
2324 // if stats weren't accepted, backout my own stats
2325 if (multi_debrief_stats_accept_code() != 1) {
2326 if(MULTIPLAYER_MASTER){
2327 for(idx=0; idx<MAX_PLAYERS; idx++){
2328 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2329 scoring_backout_accept(&Net_players[idx].player->stats);
2333 scoring_backout_accept( &Player->stats );
2338 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2339 scoring_backout_accept( &Player->stats );
2343 // if dude passed the misson and accepted, reset his show skip popup flag
2344 if (Debrief_accepted) {
2345 Player->show_skip_popup = 1;
2348 if (Num_debrief_lines) {
2349 for (i=0; i<Num_debrief_lines; i++){
2356 // unload the overlay bitmap
2357 // help_overlay_unload(DEBRIEFING_OVERLAY);
2359 // clear out award text
2360 Debrief_award_text_num_lines = 0;
2362 debrief_voice_unload_all();
2363 common_music_close();
2366 // rank_bitmaps_release();
2369 if (Background_bitmap >= 0){
2370 bm_unload(Background_bitmap);
2373 if (Award_bg_bitmap >= 0){
2374 bm_unload(Award_bg_bitmap);
2377 if (Rank_bitmap >= 0){
2378 bm_unload(Rank_bitmap);
2381 if (Medal_bitmap >= 0){
2382 bm_unload(Medal_bitmap);
2385 if (Badge_bitmap >= 0){
2386 bm_unload(Badge_bitmap);
2389 if (Wings_bitmap >= 0) {
2390 bm_unload(Wings_bitmap);
2393 if (Crest_bitmap >= 0) {
2394 bm_unload(Crest_bitmap);
2397 Debrief_ui_window.destroy();
2398 common_free_interface_palette(); // restore game palette
2401 if (Game_mode & GM_MULTIPLAYER){
2402 multi_debrief_close();
2410 // handle keypresses in debriefing
2411 void debrief_do_keys(int new_k)
2418 case KEY_SHIFTED | KEY_TAB:
2426 // multiplayer accept popup is a little bit different
2427 if (Game_mode & GM_MULTIPLAYER) {
2428 multi_debrief_esc_hit();
2430 // display the normal debrief popup
2432 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2433 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2434 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2435 if (choice == 1) { // accept and continue on
2437 gameseq_post_event(GS_EVENT_MAIN_MENU);
2443 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2444 // need to popup saying that mission was a failure and must be replayed
2445 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));
2450 // Return to Main Hall
2451 gameseq_post_event(GS_EVENT_END_GAME);
2461 void debrief_draw_award_text()
2463 int start_y, curr_y, i, x, sw;
2464 int fh = gr_get_font_height();
2465 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];
2467 // vertically centered within field
2468 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);
2472 for (i=0; i<Debrief_award_text_num_lines; i++) {
2473 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2474 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2475 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2476 gr_set_color_fast(&Color_white);
2477 gr_string(x, curr_y, Debrief_award_text[i]);
2479 // adjust y pos, including a little extra between the "pairs"
2481 if ((i == 1) || (i == 3)) {
2482 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2487 // clears out text array so we dont have old award text showing up on new awards.
2488 void debrief_award_text_clear() {
2491 Debrief_award_text_num_lines = 0;
2492 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2493 //Debrief_award_text[i][0] = 0;
2494 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2498 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2499 void debrief_add_award_text(char *str)
2501 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2502 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2507 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];
2510 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2512 // maybe translate for displaying
2514 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2517 Debrief_award_text_num_lines++;
2519 // if its too long, split once ONLY
2520 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2521 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2522 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2523 if (line2 != NULL) {
2524 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2526 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2530 // called once per frame to drive all the input reading and rendering
2531 void debrief_do_frame(float frametime)
2534 char *please_wait_str = XSTR("Please Wait", 1242);
2538 Assert(Debrief_inited);
2540 // first thing is to load the files
2541 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2542 // draw the background, etc
2543 GR_MAYBE_CLEAR_RES(Background_bitmap);
2544 if (Background_bitmap >= 0) {
2545 gr_set_bitmap(Background_bitmap);
2549 Debrief_ui_window.draw();
2551 if ( Debrief_multi_loading_bitmap > -1 ){
2552 gr_set_bitmap(Debrief_multi_loading_bitmap);
2553 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2556 // draw "Please Wait"
2557 gr_set_color_fast(&Color_normal);
2559 gr_get_string_size(&str_w, &str_h, please_wait_str);
2560 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2565 // make sure we run the debrief do frame
2566 if (Game_mode & GM_MULTIPLAYER) {
2567 multi_debrief_do_frame();
2572 int keypress = game_check_key();
2573 if(keypress == KEY_ESC){
2575 multi_quit_game(PROMPT_CLIENT);
2581 // if multiplayer client, and not loaded voice, then load it
2582 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2583 debrief_multi_fixup_stages();
2584 debrief_voice_load_all();
2585 Debrief_multi_voice_loaded = 1;
2588 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2589 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2590 Debrief_ui_window.set_ignore_gadgets(1);
2593 k = chatbox_process();
2594 if ( Game_mode & GM_NORMAL ) {
2595 new_k = Debrief_ui_window.process(k);
2597 new_k = Debrief_ui_window.process(k, 0);
2600 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2601 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2602 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2603 Debrief_ui_window.set_ignore_gadgets(0);
2609 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2610 Debrief_ui_window.set_ignore_gadgets(0);
2613 // don't show pilot info popup by default
2614 Debrief_should_show_popup = 0;
2616 // see if the mode has changed and handle it if so.
2617 if ( Current_mode != New_mode ) {
2618 debrief_voice_stop();
2619 Current_mode = New_mode;
2622 if (New_mode == DEBRIEF_TAB) {
2624 Debrief_cue_voice = 0;
2626 if (Debrief_first_voice_flag) {
2627 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2628 Debrief_first_voice_flag = 0;
2631 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2635 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2636 Current_stage = New_stage;
2637 debrief_text_init();
2640 debrief_voice_play();
2643 if (Game_mode & GM_MULTIPLAYER) {
2644 multi_debrief_do_frame();
2647 // Now do all the rendering for the frame
2648 GR_MAYBE_CLEAR_RES(Background_bitmap);
2649 if (Background_bitmap >= 0) {
2650 gr_set_bitmap(Background_bitmap);
2654 // draw the damn awarded stuff, G
2655 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2656 gr_set_bitmap(Award_bg_bitmap);
2657 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2658 if (Rank_bitmap >= 0) {
2659 gr_set_bitmap(Rank_bitmap);
2660 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2663 if (Medal_bitmap >= 0) {
2664 gr_set_bitmap(Medal_bitmap);
2665 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2668 if (Badge_bitmap >= 0) {
2669 gr_set_bitmap(Badge_bitmap);
2670 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2673 if (Wings_bitmap >= 0) {
2674 gr_set_bitmap(Wings_bitmap);
2675 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2678 if (Crest_bitmap >= 0) {
2679 gr_set_bitmap(Crest_bitmap);
2680 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2683 // draw medal/badge/rank labels
2684 debrief_draw_award_text();
2686 /* if (Rank_text_bitmap >= 0) {
2687 gr_set_bitmap(Rank_text_bitmap);
2688 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2692 if (Medal_text_bitmap >= 0) {
2693 gr_set_bitmap(Medal_text_bitmap);
2694 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2697 if (Badge_text_bitmap >= 0) {
2698 gr_set_bitmap(Badge_text_bitmap);
2699 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2704 Debrief_ui_window.draw();
2705 debrief_redraw_pressed_buttons();
2706 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2707 if (Recommend_active && (Current_mode != STATS_TAB)) {
2708 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2711 // draw the title of the mission
2712 gr_set_color_fast(&Color_bright_white);
2713 strcpy(buf, The_mission.name);
2714 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2715 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2717 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2718 gr_set_color_fast(&Color_normal);
2719 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);
2722 // draw the screen-specific text
2723 switch (Current_mode) {
2725 if ( Num_debrief_stages <= 0 ) {
2726 gr_set_color_fast(&Color_white);
2727 Assert( Game_current_mission_filename != NULL );
2728 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);
2737 debrief_stats_render();
2741 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2744 gr_set_color_fast(&Color_red);
2745 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2746 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));
2749 debrief_render_stagenum();
2750 debrief_multi_list_draw();
2752 // render some extra stuff in multiplayer
2753 if (Game_mode & GM_MULTIPLAYER) {
2754 // render the chatbox last
2758 Debrief_ui_window.draw_tooltip();
2760 // render the status indicator for the voice system
2761 multi_common_voice_display_status();
2764 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2765 // want to include the mouse pointer which is drawn in the flip
2767 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2768 debrief_check_buttons();
2769 debrief_do_keys(new_k);
2772 // blit help overlay if active
2773 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2777 // dont let dude skip 3-09. hack.
2778 if(Game_mode & GM_CAMPAIGN_MODE){
2779 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2780 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2781 Debrief_skip_popup_already_shown = 1;
2786 // maybe show skip mission popup
2787 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)) {
2788 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
2789 XSTR("Advance To The Next Mission", 1474),
2790 XSTR("Don't Show Me This Again", 1475),
2791 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
2792 switch (popup_choice) {
2794 // stay on this mission, so proceed to normal debrief
2795 // in other words, do nothing.
2798 // skip this mission
2799 mission_campaign_skip_to_next();
2800 gameseq_post_event(GS_EVENT_START_GAME);
2803 // dont show this again
2804 Player->show_skip_popup = 0;
2808 Debrief_skip_popup_already_shown = 1;
2811 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
2812 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
2813 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
2814 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
2816 Debrief_should_show_popup = 0;
2820 void debrief_rebuild_player_list()
2824 debrief_multi_list_info *list;
2826 Multi_list_size = 0; // number of net players to choose from
2828 for ( i=0; i<MAX_PLAYERS; i++ ) {
2829 np = &Net_players[i];
2830 // remember not to include the standalone.
2831 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
2832 list = &Multi_list[Multi_list_size++];
2833 list->net_player_index = i;
2834 strcpy(list->callsign, np->player->callsign);
2836 // make sure to leave some room to blit the team indicator
2837 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
2842 void debrief_handle_player_drop()
2844 debrief_rebuild_player_list();
2847 void debrief_disable_accept()