2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/MissionUI/MissionDebrief.cpp $
15 * C module for running the debriefing
18 * Revision 1.5 2002/06/09 04:41:23 relnev
19 * added copyright header
21 * Revision 1.4 2002/06/02 04:26:34 relnev
24 * Revision 1.3 2002/05/26 22:06:17 relnev
25 * makefile: disable stand_gui for now.
27 * rest: staticize some globals
29 * Revision 1.2 2002/05/07 03:16:46 theoddone33
30 * The Great Newline Fix
32 * Revision 1.1.1.1 2002/05/03 03:28:10 root
36 * 57 10/29/99 10:40p Jefff
37 * hack to make german medal names display without actually changing them
39 * 56 10/13/99 3:26p Jefff
40 * fixed unnumbered XSTRs
42 * 55 10/06/99 10:28a Jefff
45 * 54 9/30/99 5:57p Jefff
46 * show upsell at end of campaign in OEM builds
48 * 53 9/15/99 3:42a Jefff
51 * 52 9/14/99 4:35a Dave
52 * Argh. Added all kinds of code to handle potential crashes in debriefing
55 * 51 9/14/99 3:26a Dave
56 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
57 * respawn-too-early problem. Made a few crash points safe.
59 * 50 9/14/99 12:51a Jefff
61 * 49 9/13/99 6:01p Jefff
62 * fixed wrong promotion voice mapping for sm1-08
64 * 48 9/13/99 11:15a Jefff
65 * clear out award text bug fixed
67 * 47 9/13/99 12:17p Andsager
68 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
71 * 46 9/07/99 9:35p Jefff
72 * fixed bug where award text was not getting cleared properly between
75 * 45 9/07/99 6:56p Jefff
76 * a few adjustments to loop detection
78 * 44 9/07/99 1:54p Jefff
79 * skip mission cleanup
81 * 43 9/06/99 9:45p Jefff
82 * skip mission support
84 * 42 9/06/99 6:38p Dave
85 * Improved CD detection code.
87 * 41 9/03/99 1:32a Dave
88 * CD checking by act. Added support to play 2 cutscenes in a row
89 * seamlessly. Fixed super low level cfile bug related to files in the
90 * root directory of a CD. Added cheat code to set campaign mission # in
93 * 40 9/02/99 3:45p Jefff
94 * forgot to remove some debug code. doh.
96 * 39 9/02/99 3:41p Jefff
97 * changed badge voice handling to be similar to promotion voice handling
99 * 38 9/01/99 4:41p Jefff
100 * fixed stoopid text color bug
102 * 37 8/31/99 11:54a Jefff
103 * minor debrief music tweak
105 * 36 8/27/99 9:57a Dave
106 * Enabled standard cheat codes. Allow player to continue in a campaing
107 * after using cheat codes.
109 * 35 8/27/99 12:04a Dave
110 * Campaign loop screen.
112 * 34 8/26/99 8:49p Jefff
113 * Updated medals screen and about everything that ever touches medals in
114 * one way or another. Sheesh.
116 * 33 8/20/99 4:20p Jefff
117 * hack for choosing the correct promotion voice
119 * 32 8/16/99 4:05p Dave
120 * Big honking checkin.
122 * 31 8/16/99 9:49a Jefff
123 * mission title length fix in multi
125 * 30 8/11/99 5:33p Jefff
126 * added 3rd debrief music track
128 * 29 8/10/99 7:28p Jefff
129 * shuffled some text around
131 * 28 8/04/99 5:36p Andsager
132 * Show upsell screens at end of demo campaign before returning to main
135 * 27 8/04/99 2:07p Jefff
136 * mission title no longer overwrites popup
138 * 26 8/02/99 5:37p Jefff
140 * 25 8/02/99 4:52p Jefff
141 * negative feedback sound when recommendations button pressed and
144 * 24 7/21/99 6:21p Jefff
145 * added hotkeys to the "you cannot accept" popup
147 * 23 6/15/99 12:04p Anoop
148 * Added a warning for running out of debrief text lines.
150 * 22 6/09/99 2:17p Dave
151 * Fixed up pleasewait bitmap rendering.
153 * 21 6/01/99 6:07p Dave
154 * New loading/pause/please wait bar.
156 * 20 5/22/99 6:05p Dave
157 * Fixed a few localization # problems.
159 * 19 5/22/99 5:35p Dave
160 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
162 * 18 3/20/99 3:47p Andsager
163 * Fix crash with no mission loop description.
165 * 17 2/23/99 2:29p Dave
166 * First run of oldschool dogfight mode.
168 * 16 2/21/99 6:01p Dave
169 * Fixed standalone WSS packets.
171 * 15 2/11/99 3:08p Dave
172 * PXO refresh button. Very preliminary squad war support.
174 * 14 1/30/99 5:08p Dave
175 * More new hi-res stuff.Support for nice D3D textures.
177 * 13 1/29/99 2:08a Dave
178 * Fixed beam weapon collisions with players. Reduced size of scoring
179 * struct for multiplayer. Disabled PXO.
181 * 12 1/14/99 5:15p Neilk
182 * changed credits, command debrief interfaces to high resolution support
184 * 11 1/13/99 2:11p Andsager
185 * change default debriefing string text
187 * 10 12/17/98 4:50p Andsager
188 * Added debrief_assemble_optional_mission_popup_text() for single and
191 * 9 12/12/98 3:17p Andsager
192 * Clean up mission eval, goal, event and mission scoring.
194 * 8 12/10/98 10:19a Andsager
195 * Fix mission loop assert
197 * 7 12/10/98 9:59a Andsager
198 * Fix some bugs with mission loops
200 * 6 12/09/98 1:56p Andsager
201 * Initial checkin of mission loop
203 * 5 11/05/98 4:18p Dave
204 * First run nebula support. Beefed up localization a bit. Removed all
205 * conditional compiles for foreign versions. Modified mission file
208 * 4 10/23/98 3:51p Dave
209 * Full support for tstrings.tbl and foreign languages. All that remains
210 * is to make it active in Fred.
212 * 3 10/13/98 9:28a Dave
213 * Started neatening up freespace.h. Many variables renamed and
214 * reorganized. Added AlphaColors.[h,cpp]
216 * 2 10/07/98 10:53a Dave
219 * 1 10/07/98 10:49a Dave
221 * 178 9/17/98 3:08p Dave
222 * PXO to non-pxo game warning popup. Player icon stuff in create and join
223 * game screens. Upped server count refresh time in PXO to 35 secs (from
226 * 177 7/07/98 1:46p Dave
227 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
230 * 175 6/09/98 10:31a Hoffoss
231 * Created index numbers for all xstr() references. Any new xstr() stuff
232 * added from here on out should be added to the end if the list. The
233 * current list count can be found in FreeSpace.cpp (search for
236 * 174 6/07/98 3:26p Lawrance
237 * Fix bug with cut-off popup text
239 * 173 6/05/98 9:54a Lawrance
242 * 172 6/01/98 11:43a John
243 * JAS & MK: Classified all strings for localization.
245 * 171 5/27/98 1:24p Allender
246 * make targeting dots work (as well as other targeting features) properly
247 * in multiplayer. Don't query for CD when entering debrief in
250 * 170 5/26/98 11:10a Lawrance
251 * Fix bug where window controls get disabled when F1 pressed twice
253 * 169 5/24/98 12:55a Mike
254 * Prevent Assert() when no debriefing text for a stage.
256 * 168 5/23/98 10:38p Lawrance
257 * Avoid doing a cfile refresh when running debug
259 * 167 5/23/98 6:49p Lawrance
260 * Fix problems with refreshing the file list when a CD is inserted
262 * 166 5/21/98 6:57p Lawrance
263 * Don't prompt for the CD if voice not found
265 * 165 5/20/98 2:24a Dave
266 * Fixed server side voice muting. Tweaked multi debrief/endgame
267 * sequencing a bit. Much friendlier for stats tossing/accepting now.
269 * 164 5/19/98 8:35p Dave
270 * Revamp PXO channel listing system. Send campaign goals/events to
271 * clients for evaluation. Made lock button pressable on all screens.
273 * 163 5/19/98 11:13a Hoffoss
274 * Fixed bug where wrong wings award was being displayed in debriefing.
276 * 162 5/19/98 12:28a Mike
279 * 161 5/18/98 8:08p Hoffoss
280 * Moved placement of 'More' text.
282 * 160 5/18/98 3:50p Dan
283 * AL: Pick correct traitor debriefing voice file
285 * 159 5/17/98 6:32p Dave
286 * Make sure clients/servers aren't kicked out of the debriefing when team
287 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
288 * xfer/pilot info popup stuff.
290 * 158 5/16/98 9:14p Allender
291 * fix scoring ckise fir training missions to actually count medals, but
292 * nothing else. Code used to Assert when wings were granted then taken
293 * away because they were actually never granted in scoring structure
295 * 157 5/15/98 5:15p Dave
296 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
297 * status for team vs. team. Put in asserts to check for invalid team vs.
300 * 156 5/15/98 4:36p Allender
301 * fixed minor bug with wings
303 * 155 5/15/98 4:12p Allender
304 * removed redbook code. Put back in ingame join timer. Major fixups for
305 * stats in multiplayer. Pass correct score, medals, etc when leaving
306 * game. Be sure clients display medals, badges, etc.
308 * 154 5/15/98 2:25p Jasen
309 * temporarily disable granting of promotion and badges for clients
311 * 153 5/15/98 10:57a Allender
312 * fixed client side debriefings
314 * 152 5/15/98 10:36a Dave
315 * Removed 2 bogus bitmap drawing Int3()'s
317 * 151 5/14/98 2:44p Hoffoss
318 * Added wings awarding to debrief screen.
320 * 150 5/13/98 9:11p Lawrance
321 * Make 'replay mission' popup warn users about the loss of mission stats.
326 #include "missiondebrief.h"
327 #include "missionbriefcommon.h"
328 #include "missionscreencommon.h"
329 #include "missiongoals.h"
330 #include "missionpause.h"
331 #include "freespace.h"
332 #include "gamesequence.h"
340 #include "audiostr.h"
343 #include "contexthelp.h"
349 #include "multimsgs.h"
350 #include "multiutil.h"
351 #include "multiteamselect.h"
353 #include "eventmusic.h"
357 #include "multi_pinfo.h"
358 #include "contexthelp.h"
359 #include "multi_kick.h"
360 #include "multi_campaign.h"
361 #include "alphacolors.h"
362 #include "localize.h"
363 #include "multi_endgame.h"
366 #define MAX_TOTAL_DEBRIEF_LINES 200
368 #define TEXT_TYPE_NORMAL 1
369 #define TEXT_TYPE_RECOMMENDATION 2
371 #define DEBRIEF_NUM_STATS_PAGES 4
372 #define DEBRIEF_MISSION_STATS 0
373 #define DEBRIEF_MISSION_KILLS 1
374 #define DEBRIEF_ALLTIME_STATS 2
375 #define DEBRIEF_ALLTIME_KILLS 3
377 // 3rd coord is max width in pixels
378 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
387 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
396 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
401 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
410 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
419 #define MULTI_LIST_TEAM_OFFSET 16
421 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
426 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
435 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
445 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
454 // 0=x, 1=y, 2=width of the field
455 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
464 // 0=x, 1=y, 2=height of the field
465 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
475 // 1 = without medal (text will use medal space)
476 #define DB_WITH_MEDAL 0
477 #define DB_WITHOUT_MEDAL 1
478 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
487 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
488 "DebriefSingle", // GR_640
489 "2_DebriefSingle" // GR_1024
491 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
492 "DebriefMulti", // GR_640
493 "2_DebriefMulti" // GR_1024
495 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
496 "Debrief-m", // GR_640
497 "2_Debrief-m" // GR_1024
500 #define NUM_BUTTONS 18
503 #define DEBRIEF_TAB 0
505 #define TEXT_SCROLL_UP 2
506 #define TEXT_SCROLL_DOWN 3
507 #define REPLAY_MISSION 4
508 #define RECOMMENDATIONS 5
509 #define FIRST_STAGE 6
513 #define MULTI_PINFO_POPUP 10
514 #define MULTI_KICK 11
515 #define MEDALS_BUTTON 12
516 #define PLAYER_SCROLL_UP 13
517 #define PLAYER_SCROLL_DOWN 14
518 #define HELP_BUTTON 15
519 #define OPTIONS_BUTTON 16
520 #define ACCEPT_BUTTON 17
525 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
526 "PleaseWait", // GR_640
527 "2_PleaseWait" // GR_1024
533 char text[NAME_LENGTH+1]; // name of ship type with a colon
534 int num; // how many ships of this type player has killed
535 } debrief_stats_kill_info;
538 int net_player_index; // index into Net_players[] array
539 int rank_bitmap; // bitmap id for rank
540 char callsign[CALLSIGN_LEN];
541 } debrief_multi_list_info;
543 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
545 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
546 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
547 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
548 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
549 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
550 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
551 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
552 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
553 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
554 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
555 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
556 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
557 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
558 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
559 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
560 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
561 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
562 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
565 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
566 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
567 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
568 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
569 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
570 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
571 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
572 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
573 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
574 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
575 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
576 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
577 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
578 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
579 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
580 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
581 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
582 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
587 #define NUM_DEBRIEF_TEXT 10
588 #define MP_TEXT_INDEX_1 4
589 #define MP_TEXT_INDEX_2 5
590 #define MP_TEXT_INDEX_3 6
591 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
593 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
594 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
595 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
596 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
597 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
598 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
599 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
600 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
601 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
602 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
605 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
606 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
607 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
608 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
609 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
610 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
611 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
612 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
613 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
614 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
619 char Debrief_current_callsign[CALLSIGN_LEN+10];
620 player *Debrief_player;
622 static UI_WINDOW Debrief_ui_window;
623 static UI_BUTTON List_region;
624 static int Background_bitmap; // bitmap for the background of the debriefing
625 static int Award_bg_bitmap;
626 static int Debrief_multi_loading_bitmap;
627 static int Rank_bitmap;
628 static int Medal_bitmap;
629 static int Badge_bitmap;
630 static int Wings_bitmap;
631 static int Crest_bitmap;
632 //static int Rank_text_bitmap;
633 //static int Medal_text_bitmap;
634 //static int Badge_text_bitmap;
636 static int Debrief_accepted;
637 static int Turned_traitor;
638 static int Must_replay_mission;
640 static int Current_mode;
642 static int Recommend_active;
643 static int Award_active;
644 static int Text_offset;
645 static int Num_text_lines = 0;
646 static int Num_debrief_lines = 0;
647 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
648 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
650 static int Debrief_inited = 0;
651 static int New_stage;
652 static int Current_stage;
653 static int Num_stages;
654 static int Num_debrief_stages;
655 static int Stage_voice;
657 static int Multi_list_size;
658 static int Multi_list_offset;
660 int Debrief_multi_stages_loaded = 0;
661 int Debrief_multi_voice_loaded = 0;
663 // static int Debrief_voice_ask_for_cd;
665 // voice id's for debriefing text
666 static int Debrief_voices[MAX_DEBRIEF_STAGES];
668 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
669 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
670 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
672 // pointer used for getting to debriefing information
673 debriefing Traitor_debriefing; // used when player is a traitor
675 // pointers to the active stages for this debriefing
676 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
677 static debrief_stage Promotion_stage, Badge_stage;
678 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
679 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
680 int Multi_list_select;
682 // flag indicating if we should display info for the given player (in multiplayer)
683 int Debrief_should_show_popup = 1;
685 // already shown skip mission popup?
686 static int Debrief_skip_popup_already_shown = 0;
688 void debrief_text_init();
689 void debrief_accept(int ok_to_post_start_game_event = 1);
690 void debrief_kick_selected_player();
693 // promotion voice selection stuff
694 #define NUM_VOLITION_CAMPAIGNS 1
696 char campaign_name[32];
698 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
700 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
701 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
705 // data for which voice goes w/ which mission
706 typedef struct voice_map {
707 char mission_file[32];
711 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
712 { // FreeSpace2 campaign
744 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
746 { "loop1-1.fs2", 4 },
747 { "loop1-2.fs2", 4 },
748 { "loop1-3.fs2", 5 },
749 { "loop2-1.fs2", 4 },
754 #define DB_AWARD_WINGS 0
755 #define DB_AWARD_MEDAL 1
756 #define DB_AWARD_SOC 2
757 #define DB_AWARD_RANK 3
758 #define DB_AWARD_BADGE 4
759 #define DB_AWARD_BG 5
760 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
779 #define AWARD_TEXT_MAX_LINES 5
780 #define AWARD_TEXT_MAX_LINE_LENGTH 128
781 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
782 int Debrief_award_text_num_lines = 0;
786 // prototypes, you know you love 'em
787 void debrief_add_award_text(char *str);
788 void debrief_award_text_clear();
793 char *debrief_tooltip_handler(char *str)
795 if (!stricmp(str, NOX("@.Medal"))) {
797 return XSTR( "Medal", 435);
800 } else if (!stricmp(str, NOX("@.Rank"))) {
802 return XSTR( "Rank", 436);
805 } else if (!stricmp(str, NOX("@.Badge"))) {
807 return XSTR( "Badge", 437);
810 } else if (!stricmp(str, NOX("@Medal"))) {
811 if (Medal_bitmap >= 0){
812 return Medals[Player->stats.m_medal_earned].name;
815 } else if (!stricmp(str, NOX("@Rank"))) {
816 if (Rank_bitmap >= 0){
817 return Ranks[Promoted].name;
820 } else if (!stricmp(str, NOX("@Badge"))) {
821 if (Badge_bitmap >= 0){
822 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
829 // initialize the array of handles to the different voice streams
830 void debrief_voice_init()
834 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
835 Debrief_voices[i] = -1;
839 void debrief_load_voice_file(int voice_num, char *name)
841 int load_attempts = 0;
844 if ( load_attempts++ > 5 ) {
848 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
849 if ( Debrief_voices[voice_num] >= 0 ) {
853 // Don't bother to ask for the CD in multiplayer
854 if ( Game_mode & GM_MULTIPLAYER ) {
858 // couldn't load voice, ask user to insert CD (if necessary)
860 // if ( Debrief_voice_ask_for_cd ) {
861 // if ( game_do_cd_check() == 0 ) {
862 // Debrief_voice_ask_for_cd = 0;
869 // open and pre-load the stream buffers for the different voice streams
870 void debrief_voice_load_all()
874 // Debrief_voice_ask_for_cd = 1;
876 for ( i=0; i<Num_debrief_stages; i++ ) {
877 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
880 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
881 debrief_load_voice_file(i, Debrief_stages[i]->voice);
882 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
887 // close all the briefing voice streams
888 void debrief_voice_unload_all()
892 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
893 if ( Debrief_voices[i] != -1 ) {
894 audiostream_close_file(Debrief_voices[i], 0);
895 Debrief_voices[i] = -1;
900 // start playback of the voice for a particular briefing stage
901 void debrief_voice_play()
903 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
907 // no more stages? We are done then.
908 if (Stage_voice >= Num_debrief_stages){
912 // if in delayed start, see if delay has elapsed and start voice if so
913 if (Debrief_cue_voice) {
914 if (!timestamp_elapsed(Debrief_cue_voice)){
918 Stage_voice++; // move up to next voice
919 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
920 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
921 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
927 // see if voice is still playing. If so, do nothing yet.
928 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
932 // set voice to play in a little while from now.
933 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
936 // stop playback of the voice for a particular briefing stage
937 void debrief_voice_stop()
939 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
942 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
946 // function to deal with inserting possible promition and badge stages into the debriefing
948 void debrief_multi_fixup_stages()
952 // possibly insert the badge stage first, them the promotion stage since they are
953 // inserted at the front of the debrief stages.
954 if ( Badge_bitmap >= 0 ) {
955 // move all stages forward one. Don't
956 for ( i = Num_debrief_stages; i > 0; i-- ) {
957 Debrief_stages[i] = Debrief_stages[i-1];
959 Debrief_stages[0] = &Badge_stage;
960 Num_debrief_stages++;
963 if ( Promoted >= 0) {
964 // move all stages forward one
965 for ( i = Num_debrief_stages; i > 0; i-- ) {
966 Debrief_stages[i] = Debrief_stages[i-1];
968 Debrief_stages[0] = &Promotion_stage;
969 Num_debrief_stages++;
974 // function called from multiplayer clients to set up the debriefing information for them
975 // (sent from the server).
976 void debrief_set_multi_clients( int stage_count, int active_stages[] )
980 // set up the right briefing for this guy
981 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
982 Debriefing = &Debriefings[Net_player->p_info.team];
984 Debriefing = &Debriefings[0];
987 // see if this client was promoted -- if so, then add the first stage.
988 Num_debrief_stages = 0;
990 // set the pointers to the debriefings for this client
991 for (i = 0; i < stage_count; i++) {
992 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
995 Debrief_multi_stages_loaded = 1;
998 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
999 // information to all clients after leaving this screen.
1000 void debrief_multi_server_stuff()
1002 debriefing *debriefp;
1004 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1005 int i, j, num_stages, stage_count[MAX_TEAMS];
1007 memset( stage_active, 0, sizeof(stage_active) );
1009 for (i=0; i<Num_teams; i++) {
1010 debriefp = &Debriefings[i];
1012 stages[i] = stage_active[i];
1013 for (j=0; j<debriefp->num_stages; j++) {
1014 if ( eval_sexp(debriefp->stages[j].formula) ) {
1015 stage_active[i][num_stages] = j;
1020 stage_count[i] = num_stages;
1023 // if we're in campaign mode, evaluate campaign stuff
1024 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1025 multi_campaign_eval_debrief();
1028 // send the information to all clients.
1029 send_debrief_info( stage_count, stages );
1033 // --------------------------------------------------------------------------------------
1034 // debrief_set_stages_and_multi_stuff()
1036 // Set up the active stages for this debriefing
1038 // returns: number of active debriefing stages
1040 int debrief_set_stages_and_multi_stuff()
1043 debriefing *debriefp;
1045 if ( MULTIPLAYER_CLIENT ) {
1049 Num_debrief_stages = 0;
1051 if ( Game_mode & GM_MULTIPLAYER ) {
1052 debrief_multi_server_stuff();
1055 // check to see if player is a traitor (looking at his team). If so, use the special
1056 // traitor debriefing. Only done in single player
1057 debriefp = Debriefing;
1058 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1059 if (Player_ship->team == TEAM_TRAITOR)
1060 debriefp = &Traitor_debriefing;
1063 Num_debrief_stages = 0;
1064 if (Promoted >= 0) {
1065 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1068 if (Badge_bitmap >= 0) {
1069 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1072 for (i=0; i<debriefp->num_stages; i++) {
1073 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1074 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1078 return Num_debrief_stages;
1081 // init the buttons that are specific to the debriefing screen
1082 void debrief_buttons_init()
1087 for ( i=0; i<NUM_BUTTONS; i++ ) {
1088 b = &Buttons[gr_screen.res][i];
1089 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1090 // set up callback for when a mouse first goes over a button
1091 b->button.set_highlight_action( common_play_highlight_sound );
1092 b->button.set_bmaps(b->filename);
1093 b->button.link_hotspot(b->hotspot);
1097 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1098 // multiplayer specific text
1099 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1100 // only add if in multiplayer mode
1101 if(Game_mode & GM_MULTIPLAYER){
1102 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1107 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1111 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1112 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1113 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1114 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1115 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1116 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1117 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1118 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1120 // if in multiplayer, disable the button for all players except the host
1121 // also disable for squad war matches
1122 if(Game_mode & GM_MULTIPLAYER){
1123 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1124 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1129 // --------------------------------------------------------------------------------------
1130 // debrief_ui_init()
1132 void debrief_ui_init()
1134 // init ship selection masks and buttons
1135 common_set_interface_palette("DebriefPalette"); // set the interface palette
1136 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1137 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1138 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1139 debrief_buttons_init();
1141 // load in help overlay bitmap
1142 help_overlay_load(DEBRIEFING_OVERLAY);
1143 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1145 if ( Game_mode & GM_MULTIPLAYER ) {
1146 // close down any old instances of the chatbox
1149 // create the new one
1151 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1152 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);
1155 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1158 if ( Background_bitmap < 0 ) {
1159 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1162 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1163 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1166 // sets Promotion_stage.voice
1167 // defaults to number 9 (Petrarch) for non-volition missions
1168 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1169 void debrief_choose_promotion_voice()
1173 if(Campaign.current_mission < 0){
1174 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1178 // search thru all official campaigns for our current campaign
1179 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1180 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1181 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1182 // now search thru the mission filenames,
1183 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1184 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1185 // found it! set the persona and bail
1186 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1194 // default to petrarch
1195 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1198 // sets Promotion_stage.voice
1199 // defaults to number 9 (Petrarch) for non-volition missions
1200 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1201 void debrief_choose_badge_voice()
1205 if(Campaign.current_mission < 0){
1206 // default to petrarch
1207 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1210 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1211 // search thru all official campaigns for our current campaign
1212 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1213 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1214 // now search thru the mission filenames,
1215 for (j=0; j<Campaign.num_missions; j++) {
1216 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1217 // found it! set the persona and bail
1218 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1226 // default to petrarch
1227 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1231 void debrief_award_init()
1243 // be sure there are no old award texts floating around
1244 debrief_award_text_clear();
1246 // handle medal earned
1247 if (Player->stats.m_medal_earned != -1) {
1248 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1250 if ( Player->stats.medals[13] > 1 ) {
1255 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1256 Wings_bitmap = bm_load(buf);
1258 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1259 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1261 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1262 Medal_bitmap = bm_load(buf);
1265 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1268 // handle promotions
1269 if ( Player->stats.m_promotion_earned != -1 ) {
1270 Promoted = Player->stats.m_promotion_earned;
1271 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1272 Rank_bitmap = bm_load(buf);
1274 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1275 Promotion_stage.new_recommendation_text = NULL;
1277 // choose appropriate promotion voice for this mission
1278 debrief_choose_promotion_voice();
1280 debrief_add_award_text(Ranks[Promoted].name);
1283 // handle badge earned
1284 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1285 if ( Player->stats.m_badge_earned != -1 ) {
1286 i = Player->stats.m_badge_earned;
1287 sprintf(buf, NOX("%s%0.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1288 Badge_bitmap = bm_load(buf);
1290 Badge_stage.new_text = Badge_info[i].promotion_text;
1291 Badge_stage.new_recommendation_text = NULL;
1293 // choose appropriate voice
1294 debrief_choose_badge_voice();
1296 debrief_add_award_text(Medals[Badge_index[i]].name);
1299 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1306 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1307 // mission a traitor. The same debriefing always gets played
1308 void debrief_traitor_init()
1310 static int inited = 0;
1313 debriefing *debrief;
1314 debrief_stage *stagep;
1318 if ((rval = setjmp(parse_abort)) != 0) {
1319 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1322 read_file_text("traitor.tbl");
1326 // open localization
1329 // simplied form of the debriefing stuff.
1330 debrief = &Traitor_debriefing;
1331 required_string("#Debriefing_info");
1333 required_string("$Num stages:");
1334 stuff_int(&debrief->num_stages);
1335 Assert(debrief->num_stages == 1);
1338 stagep = &debrief->stages[stage_num++];
1339 required_string("$Formula:");
1340 stagep->formula = get_sexp_main();
1341 required_string("$multi text");
1342 if ( Fred_running ) {
1343 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1345 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1347 required_string("$Voice:");
1348 char traitor_voice_file[NAME_LENGTH];
1349 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1351 // DKA 9/13/99 Only 1 traitor msg for FS2
1352 // if ( Player->on_bastion ) {
1353 // strcpy(stagep->voice, NOX("3_"));
1355 // strcpy(stagep->voice, NOX("1_"));
1358 strcat(stagep->voice, traitor_voice_file);
1360 required_string("$Recommendation text:");
1361 if ( Fred_running ) {
1362 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1364 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1368 // close localization
1372 // disable the accept button if in single player and I am a traitor
1373 Debrief_accepted = 0;
1374 Turned_traitor = Must_replay_mission = 0;
1375 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1376 if (Player_ship->team == TEAM_TRAITOR){
1380 if (Campaign.next_mission == Campaign.current_mission){
1381 Must_replay_mission = 1;
1385 if (Turned_traitor || Must_replay_mission) {
1386 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1388 // kill off any stats
1389 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1390 scoring_level_init( &Player->stats );
1394 // initialization for listing of players in game
1395 void debrief_multi_list_init()
1397 Multi_list_size = 0; // number of net players to choose from
1398 Multi_list_offset = 0;
1400 Multi_list_select = -1;
1402 if ( !(Game_mode & GM_MULTIPLAYER) )
1405 debrief_rebuild_player_list();
1407 // switch stats display to this newly selected player
1408 set_player_stats(Multi_list[0].net_player_index);
1409 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1410 Debrief_player = Player;
1413 void debrief_multi_list_scroll_up()
1415 // if we're at the beginning of the list, don't do anything
1416 if(Multi_list_offset == 0){
1417 gamesnd_play_iface(SND_GENERAL_FAIL);
1421 // otherwise scroll up
1422 Multi_list_offset--;
1423 gamesnd_play_iface(SND_USER_SELECT);
1426 void debrief_multi_list_scroll_down()
1428 // if we can scroll down no further
1429 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1430 gamesnd_play_iface(SND_GENERAL_FAIL);
1433 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1434 gamesnd_play_iface(SND_GENERAL_FAIL);
1438 // otherwise scroll down
1439 Multi_list_offset++;
1440 gamesnd_play_iface(SND_USER_SELECT);
1443 // draw the connected net players
1444 void debrief_multi_list_draw()
1446 int y, z, font_height,idx;
1447 char str[CALLSIGN_LEN+5];
1450 font_height = gr_get_font_height();
1452 // if we currently have no item picked, pick a reasonable one
1453 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1454 // select the entry which corresponds to the local player
1455 Multi_list_select = 0;
1456 for(idx=0;idx<Multi_list_size;idx++){
1457 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1458 Multi_list_select = idx;
1460 // switch stats display to this newly selected player
1461 set_player_stats(Multi_list[idx].net_player_index);
1462 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1463 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1469 // draw the list itself
1471 z = Multi_list_offset;
1472 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1473 np = &Net_players[Multi_list[z].net_player_index];
1475 if (z >= Multi_list_size){
1478 // set the proper text color for the highlight
1479 if(np->flags & NETINFO_FLAG_GAME_HOST){
1480 if(Multi_list_select == z){
1481 gr_set_color_fast(&Color_text_active_hi);
1483 gr_set_color_fast(&Color_bright);
1486 if(Multi_list_select == z){
1487 gr_set_color_fast(&Color_text_active);
1489 gr_set_color_fast(&Color_text_normal);
1493 // blit the proper indicator - skipping observers
1494 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1495 if(Netgame.type_flags & NG_TYPE_TEAM){
1497 if(np->p_info.team == 0){
1498 // draw his "selected" icon
1499 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1500 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1501 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1503 // draw his "normal" icon
1504 else if(Multi_common_icons[MICON_TEAM0] != -1){
1505 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1506 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1508 } else if(np->p_info.team == 1){
1509 // draw his "selected" icon
1510 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1511 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1512 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1514 // draw his "normal" icon
1515 else if(Multi_common_icons[MICON_TEAM1] != -1){
1516 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1517 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1521 // draw the team 0 selected icon
1522 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1523 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1524 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1529 strcpy(str,Multi_list[z].callsign);
1530 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)){
1531 strcat(str,XSTR( "(O)", 438));
1535 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1542 void debrief_kick_selected_player()
1544 if(Multi_list_select >= 0){
1545 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1546 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1550 // get optional mission popup text
1551 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1553 Assert(buffer != NULL);
1556 if (mission_loop_desc == NULL) {
1557 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1558 mprintf(("No mission loop description avail"));
1560 strcpy(buffer, mission_loop_desc);
1563 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1566 // what to do when the accept button is hit
1567 void debrief_accept(int ok_to_post_start_game_event)
1571 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1575 if (Game_mode & GM_MULTIPLAYER) {
1579 if (Player_ship->team == TEAM_TRAITOR){
1580 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1581 }/* else if (Cheats_enabled) {
1582 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1584 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1587 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1589 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1590 } else if ( z == 1 ) {
1591 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1597 Debrief_accepted = 1;
1598 // save mission stats
1599 if (Game_mode & GM_MULTIPLAYER) {
1600 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1601 // as well as doing stats transfers, etc.
1602 multi_debrief_accept_hit();
1606 int play_commit_sound = 1;
1607 // only write the player's stats if he's accepted
1609 // if we are just playing a single mission, then don't do many of the things
1610 // that need to be done. Nothing much should happen when just playing a single
1611 // mission that isn't in a campaign.
1612 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1614 // check for possible mission loop
1615 // check for (1) mission loop available, (2) dont have to repeat last mission
1616 if(!(Game_mode & GM_MULTIPLAYER)){
1617 int cur = Campaign.current_mission;
1618 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1619 if (Campaign.missions[cur].has_mission_loop) {
1620 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1623 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1626 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1628 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1630 Campaign.loop_enabled = 1;
1631 Campaign.next_mission = Campaign.loop_mission;
1640 if(ok_to_post_start_game_event){
1641 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1643 play_commit_sound = 0;
1646 // continue as normal
1649 mission_campaign_mission_over();
1651 // check to see if we are out of the loop now
1652 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1653 Campaign.loop_enabled = 0;
1656 // check if campaign is over
1657 if ( Campaign.next_mission == -1 ) {
1658 #if defined(FS2_DEMO) || defined(OEM_BUILD)
1659 gameseq_post_event(GS_EVENT_END_DEMO);
1661 gameseq_post_event(GS_EVENT_MAIN_MENU);
1664 if ( ok_to_post_start_game_event ) {
1666 if(game_do_cd_mission_check(Game_current_mission_filename)){
1667 gameseq_post_event(GS_EVENT_START_GAME);
1669 gameseq_post_event(GS_EVENT_MAIN_MENU);
1672 play_commit_sound = 0;
1677 gameseq_post_event(GS_EVENT_MAIN_MENU);
1680 if ( play_commit_sound ) {
1681 gamesnd_play_iface(SND_COMMIT_PRESSED);
1688 void debrief_next_tab()
1690 New_mode = Current_mode + 1;
1691 if (New_mode >= NUM_TABS)
1695 void debrief_prev_tab()
1697 New_mode = Current_mode - 1;
1699 New_mode = NUM_TABS - 1;
1702 // --------------------------------------------------------------------------------------
1703 // debrief_next_stage()
1705 void debrief_next_stage()
1707 if (Current_stage < Num_stages - 1) {
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_prev_stage()
1718 void debrief_prev_stage()
1720 if (Current_stage) {
1721 New_stage = Current_stage - 1;
1722 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1725 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1728 // --------------------------------------------------------------------------------------
1729 // debrief_first_stage()
1730 void debrief_first_stage()
1732 if (Current_stage) {
1734 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1737 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1740 // --------------------------------------------------------------------------------------
1741 // debrief_last_stage()
1742 void debrief_last_stage()
1744 if (Current_stage != Num_stages - 1) {
1745 New_stage = Num_stages - 1;
1746 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1749 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1752 // draw what stage number the debriefing is on
1753 void debrief_render_stagenum()
1761 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1762 gr_get_string_size(&w, NULL, buf);
1763 gr_set_color_fast(&Color_bright_blue);
1764 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1765 gr_set_color_fast(&Color_white);
1768 // render the mission time at the specified y location
1769 void debrief_render_mission_time(int y_loc)
1773 game_format_time(Missiontime, time_str);
1774 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1775 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1778 // render out the debriefing text to the scroll window
1779 void debrief_render()
1781 int y, z, font_height;
1783 if ( Num_stages <= 0 )
1786 font_height = gr_get_font_height();
1788 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]);
1791 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1792 if (z >= Num_text_lines)
1795 if (Text_type[z] == TEXT_TYPE_NORMAL)
1796 gr_set_color_fast(&Color_white);
1798 gr_set_color_fast(&Color_bright_red);
1801 gr_string(0, y, Text[z]);
1810 // render out the stats info to the scroll window
1812 void debrief_stats_render()
1814 int i, y, font_height;
1816 gr_set_color_fast(&Color_blue);
1817 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]);
1818 gr_string(0, 0, Debrief_current_callsign);
1819 font_height = gr_get_font_height();
1822 switch ( Current_stage ) {
1823 case DEBRIEF_MISSION_STATS:
1824 i = Current_stage - 1;
1828 gr_set_color_fast(&Color_white);
1830 // display mission completion time
1831 debrief_render_mission_time(y);
1834 show_stats_label(i, 0, y, font_height);
1835 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1837 case DEBRIEF_ALLTIME_STATS:
1838 i = Current_stage - 1;
1842 gr_set_color_fast(&Color_white);
1843 show_stats_label(i, 0, y, font_height);
1844 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1847 case DEBRIEF_ALLTIME_KILLS:
1848 case DEBRIEF_MISSION_KILLS:
1849 gr_set_color_fast(&Color_white);
1851 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1852 if (i >= Num_text_lines)
1856 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1857 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
1859 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
1862 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
1863 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
1870 if (Num_text_lines == 2) {
1871 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1872 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
1874 gr_printf(0, y, XSTR( "(No ship kills)", 450));
1887 // do action for when the replay button is pressed
1888 void debrief_replay_pressed()
1890 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
1892 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));
1899 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
1900 gamesnd_play_iface(SND_COMMIT_PRESSED);
1903 // -------------------------------------------------------------------
1904 // debrief_redraw_pressed_buttons()
1906 // Redraw any debriefing buttons that are pressed down. This function is needed
1907 // since we sometimes need to draw pressed buttons last to ensure the entire
1908 // button gets drawn (and not overlapped by other buttons)
1910 void debrief_redraw_pressed_buttons()
1915 for ( i=0; i<NUM_BUTTONS; i++ ) {
1916 b = &Buttons[gr_screen.res][i].button;
1917 // don't draw the recommendations button if we're in stats mode
1918 if ( b->button_down() ) {
1924 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
1926 void debrief_button_pressed(int num)
1930 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
1931 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
1932 if (num != Current_mode){
1933 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1938 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
1939 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
1940 if (num != Current_mode){
1941 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1946 case TEXT_SCROLL_UP:
1949 gamesnd_play_iface(SND_SCROLL);
1951 gamesnd_play_iface(SND_GENERAL_FAIL);
1955 case TEXT_SCROLL_DOWN:
1956 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
1958 gamesnd_play_iface(SND_SCROLL);
1960 gamesnd_play_iface(SND_GENERAL_FAIL);
1964 case REPLAY_MISSION:
1965 if(Game_mode & GM_MULTIPLAYER){
1966 multi_debrief_replay_hit();
1968 debrief_replay_pressed();
1972 case RECOMMENDATIONS:
1973 gamesnd_play_iface(SND_USER_SELECT);
1974 Recommend_active = !Recommend_active;
1975 debrief_text_init();
1979 debrief_first_stage();
1983 debrief_prev_stage();
1987 debrief_next_stage();
1991 debrief_last_stage();
1995 gamesnd_play_iface(SND_HELP_PRESSED);
1996 launch_context_help();
1999 case OPTIONS_BUTTON:
2000 gamesnd_play_iface(SND_SWITCH_SCREENS);
2001 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2009 gamesnd_play_iface(SND_SWITCH_SCREENS);
2010 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2013 case PLAYER_SCROLL_UP:
2014 debrief_multi_list_scroll_up();
2017 case PLAYER_SCROLL_DOWN:
2018 debrief_multi_list_scroll_down();
2021 case MULTI_PINFO_POPUP:
2022 Debrief_should_show_popup = 1;
2026 debrief_kick_selected_player();
2031 void debrief_setup_ship_kill_stats(int stage_num)
2035 debrief_stats_kill_info *kill_info;
2037 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2038 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2041 Assert(Debrief_player != NULL);
2043 // kill_ar points to an array of MAX_SHIP_TYPE ints
2044 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2045 kill_arr = Debrief_player->stats.m_okKills;
2047 kill_arr = Debrief_player->stats.kills;
2051 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2053 // code used to add in mission kills, but the new system assumes that the player will accept, so
2054 // all time stats already have mission stats added in.
2055 if ( kill_arr[i] <= 0 ){
2060 kill_info = &Debrief_stats_kills[Num_text_lines++];
2062 kill_info->num = kill_arr[i];
2064 strcpy(kill_info->text, Ship_info[i].name);
2065 strcat(kill_info->text, NOX(":"));
2068 Num_text_lines += 2;
2071 // Iterate through the debriefing buttons, checking if they are pressed
2072 void debrief_check_buttons()
2076 for ( i=0; i<NUM_BUTTONS; i++ ) {
2077 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2078 debrief_button_pressed(i);
2082 if ( !(Game_mode & GM_MULTIPLAYER) )
2085 if (List_region.pressed()) {
2086 List_region.get_mouse_pos(NULL, &y);
2087 z = Multi_list_offset + y / gr_get_font_height();
2088 if ((z >= 0) && (z < Multi_list_size)) {
2089 // switch stats display to this newly selected player
2090 set_player_stats(Multi_list[z].net_player_index);
2091 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2092 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2093 Multi_list_select = z;
2094 debrief_setup_ship_kill_stats(Current_stage);
2095 gamesnd_play_iface(SND_USER_SELECT);
2099 // if the player was double clicked on - we should popup a player info popup
2101 if (List_region.double_clicked()) {
2102 Debrief_should_show_popup = 1;
2107 void debrief_text_stage_init(char *src, int type)
2109 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2110 char line[MAX_DEBRIEF_LINE_LEN];
2111 char *p_str[MAX_DEBRIEF_LINES];
2113 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2114 Assert(n_lines >= 0);
2116 // if you hit this, you proba
2117 if(n_lines >= MAX_DEBRIEF_LINES){
2118 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2121 for ( i=0; i<n_lines; i++ ) {
2122 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2123 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2124 strncpy(line, p_str[i], n_chars[i]);
2125 line[n_chars[i]] = 0;
2126 drop_white_space(line);
2127 Text_type[Num_text_lines] = type;
2128 Text[Num_text_lines++] = strdup(line);
2134 void debrief_free_text()
2138 for (i=0; i<Num_debrief_lines; i++)
2142 Num_debrief_lines = 0;
2145 // setup the debriefing text lines for rendering
2146 void debrief_text_init()
2151 // release old text lines first
2152 debrief_free_text();
2153 Num_text_lines = Text_offset = 0;
2155 if (Current_mode == DEBRIEF_TAB) {
2156 for (i=0; i<Num_debrief_stages; i++) {
2158 Text[Num_text_lines++] = NULL; // add a blank line between stages
2160 src = Debrief_stages[i]->new_text;
2162 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2164 if (Recommend_active) {
2165 src = Debrief_stages[i]->new_recommendation_text;
2166 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2167 src = XSTR( "We have no recommendations for you.", 1054);
2170 Text[Num_text_lines++] = NULL;
2171 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2177 Num_debrief_lines = Num_text_lines;
2181 // not in debriefing mode, must be in stats mode
2183 debrief_setup_ship_kill_stats(Current_stage);
2187 // --------------------------------------------------------------------------------------
2191 Assert(!Debrief_inited);
2192 // Campaign.loop_enabled = 0;
2193 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2195 // set up the right briefing for this guy
2196 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2197 Debriefing = &Debriefings[Net_player->p_info.team];
2199 Debriefing = &Debriefings[0];
2202 // no longer is mission
2203 Game_mode &= ~(GM_IN_MISSION);
2207 New_mode = DEBRIEF_TAB;
2208 Recommend_active = Award_active = 0;
2213 Debrief_cue_voice = 0;
2214 Num_text_lines = Num_debrief_lines = 0;
2215 Debrief_first_voice_flag = 1;
2217 Debrief_multi_voice_loaded = 0;
2219 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2220 // MUST store goals and events first - may be used to evaluate next mission
2221 // store goals and events
2222 mission_campaign_store_goals_and_events();
2224 // evaluate next mission
2225 mission_campaign_eval_next_mission();
2228 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2230 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2231 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2234 // call scoring level close for my stats. Needed for award_init. The stats will
2235 // be backed out if used chooses to replace them.
2236 scoring_level_close();
2238 debrief_ui_init(); // init UI items
2239 debrief_award_init();
2241 debrief_voice_init();
2242 debrief_multi_list_init();
2243 // rank_bitmaps_clear();
2244 // rank_bitmaps_load();
2246 strcpy(Debrief_current_callsign, Player->callsign);
2247 Debrief_player = Player;
2248 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2250 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2251 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2252 // info directly from the server.
2253 if ( !MULTIPLAYER_CLIENT ) {
2254 debrief_set_stages_and_multi_stuff();
2256 if ( Num_debrief_stages <= 0 ) {
2257 Num_debrief_stages = 0;
2259 debrief_voice_load_all();
2262 // multiplayer client may have already received their debriefing info. If they have not,
2263 // then set the num debrief stages to 0
2264 if ( !Debrief_multi_stages_loaded ) {
2265 Num_debrief_stages = 0;
2270 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2271 common_music_init(SCORE_DEBRIEF_SUCCESS);
2273 common_music_init(SCORE_DEBRIEF_FAIL);
2277 // start up the appropriate music
2278 if (Campaign.next_mission == Campaign.current_mission) {
2279 // you failed the mission because you suck, so you get the suck music
2280 common_music_init(SCORE_DEBRIEF_FAIL);
2281 } else if (mission_goals_met()) {
2282 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2283 common_music_init(SCORE_DEBRIEF_SUCCESS);
2285 // you somehow passed the mission, so you get a little something for your efforts.
2286 common_music_init(SCORE_DEBRIEF_AVERAGE);
2289 if (Campaign.next_mission == Campaign.current_mission) {
2290 // better luck next time, increase his retries
2291 Player->failures_this_session++;
2293 // clear his retries info regardless of whether or not he accepts
2294 Player->failures_this_session = 0;
2297 if (Game_mode & GM_MULTIPLAYER) {
2298 multi_debrief_init();
2300 // if i'm not the host of the game, disable the multi kick button
2301 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2302 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2305 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2306 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2307 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2308 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2309 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2310 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2311 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2312 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2315 if (!Award_active) {
2316 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2317 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2320 Debrief_skip_popup_already_shown = 0;
2325 // --------------------------------------------------------------------------------------
2327 void debrief_close()
2331 Assert(Debrief_inited);
2333 // if the mission wasn't accepted, clear out my stats
2334 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2335 // are a little bit different
2336 if (Game_mode & GM_MULTIPLAYER) {
2337 // if stats weren't accepted, backout my own stats
2338 if (multi_debrief_stats_accept_code() != 1) {
2339 if(MULTIPLAYER_MASTER){
2340 for(idx=0; idx<MAX_PLAYERS; idx++){
2341 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2342 scoring_backout_accept(&Net_players[idx].player->stats);
2346 scoring_backout_accept( &Player->stats );
2351 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2352 scoring_backout_accept( &Player->stats );
2356 // if dude passed the misson and accepted, reset his show skip popup flag
2357 if (Debrief_accepted) {
2358 Player->show_skip_popup = 1;
2361 if (Num_debrief_lines) {
2362 for (i=0; i<Num_debrief_lines; i++){
2369 // unload the overlay bitmap
2370 // help_overlay_unload(DEBRIEFING_OVERLAY);
2372 // clear out award text
2373 Debrief_award_text_num_lines = 0;
2375 debrief_voice_unload_all();
2376 common_music_close();
2379 // rank_bitmaps_release();
2382 if (Background_bitmap >= 0){
2383 bm_unload(Background_bitmap);
2386 if (Award_bg_bitmap >= 0){
2387 bm_unload(Award_bg_bitmap);
2390 if (Rank_bitmap >= 0){
2391 bm_unload(Rank_bitmap);
2394 if (Medal_bitmap >= 0){
2395 bm_unload(Medal_bitmap);
2398 if (Badge_bitmap >= 0){
2399 bm_unload(Badge_bitmap);
2402 if (Wings_bitmap >= 0) {
2403 bm_unload(Wings_bitmap);
2406 if (Crest_bitmap >= 0) {
2407 bm_unload(Crest_bitmap);
2410 Debrief_ui_window.destroy();
2411 common_free_interface_palette(); // restore game palette
2414 if (Game_mode & GM_MULTIPLAYER){
2415 multi_debrief_close();
2423 // handle keypresses in debriefing
2424 void debrief_do_keys(int new_k)
2431 case KEY_SHIFTED | KEY_TAB:
2439 // multiplayer accept popup is a little bit different
2440 if (Game_mode & GM_MULTIPLAYER) {
2441 multi_debrief_esc_hit();
2443 // display the normal debrief popup
2445 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2446 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2447 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2448 if (choice == 1) { // accept and continue on
2450 gameseq_post_event(GS_EVENT_MAIN_MENU);
2456 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2457 // need to popup saying that mission was a failure and must be replayed
2458 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));
2463 // Return to Main Hall
2464 gameseq_post_event(GS_EVENT_END_GAME);
2474 void debrief_draw_award_text()
2476 int start_y, curr_y, i, x, sw;
2477 int fh = gr_get_font_height();
2478 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];
2480 // vertically centered within field
2481 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);
2485 for (i=0; i<Debrief_award_text_num_lines; i++) {
2486 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2487 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2488 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2489 gr_set_color_fast(&Color_white);
2490 gr_string(x, curr_y, Debrief_award_text[i]);
2492 // adjust y pos, including a little extra between the "pairs"
2494 if ((i == 1) || (i == 3)) {
2495 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2500 // clears out text array so we dont have old award text showing up on new awards.
2501 void debrief_award_text_clear() {
2504 Debrief_award_text_num_lines = 0;
2505 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2506 //Debrief_award_text[i][0] = 0;
2507 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2511 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2512 void debrief_add_award_text(char *str)
2514 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2515 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2520 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];
2523 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2525 // maybe translate for displaying
2527 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2530 Debrief_award_text_num_lines++;
2532 // if its too long, split once ONLY
2533 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2534 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2535 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2536 if (line2 != NULL) {
2537 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2539 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2543 // called once per frame to drive all the input reading and rendering
2544 void debrief_do_frame(float frametime)
2547 char *please_wait_str = XSTR("Please Wait", 1242);
2551 Assert(Debrief_inited);
2553 // first thing is to load the files
2554 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2555 // draw the background, etc
2556 GR_MAYBE_CLEAR_RES(Background_bitmap);
2557 if (Background_bitmap >= 0) {
2558 gr_set_bitmap(Background_bitmap);
2562 Debrief_ui_window.draw();
2564 if ( Debrief_multi_loading_bitmap > -1 ){
2565 gr_set_bitmap(Debrief_multi_loading_bitmap);
2566 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2569 // draw "Please Wait"
2570 gr_set_color_fast(&Color_normal);
2572 gr_get_string_size(&str_w, &str_h, please_wait_str);
2573 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2578 // make sure we run the debrief do frame
2579 if (Game_mode & GM_MULTIPLAYER) {
2580 multi_debrief_do_frame();
2585 int keypress = game_check_key();
2586 if(keypress == KEY_ESC){
2588 multi_quit_game(PROMPT_CLIENT);
2594 // if multiplayer client, and not loaded voice, then load it
2595 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2596 debrief_multi_fixup_stages();
2597 debrief_voice_load_all();
2598 Debrief_multi_voice_loaded = 1;
2601 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2602 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2603 Debrief_ui_window.set_ignore_gadgets(1);
2606 k = chatbox_process();
2607 if ( Game_mode & GM_NORMAL ) {
2608 new_k = Debrief_ui_window.process(k);
2610 new_k = Debrief_ui_window.process(k, 0);
2613 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2614 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2615 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2616 Debrief_ui_window.set_ignore_gadgets(0);
2622 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2623 Debrief_ui_window.set_ignore_gadgets(0);
2626 // don't show pilot info popup by default
2627 Debrief_should_show_popup = 0;
2629 // see if the mode has changed and handle it if so.
2630 if ( Current_mode != New_mode ) {
2631 debrief_voice_stop();
2632 Current_mode = New_mode;
2635 if (New_mode == DEBRIEF_TAB) {
2637 Debrief_cue_voice = 0;
2639 if (Debrief_first_voice_flag) {
2640 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2641 Debrief_first_voice_flag = 0;
2644 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2648 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2649 Current_stage = New_stage;
2650 debrief_text_init();
2653 debrief_voice_play();
2656 if (Game_mode & GM_MULTIPLAYER) {
2657 multi_debrief_do_frame();
2660 // Now do all the rendering for the frame
2661 GR_MAYBE_CLEAR_RES(Background_bitmap);
2662 if (Background_bitmap >= 0) {
2663 gr_set_bitmap(Background_bitmap);
2667 // draw the damn awarded stuff, G
2668 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2669 gr_set_bitmap(Award_bg_bitmap);
2670 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2671 if (Rank_bitmap >= 0) {
2672 gr_set_bitmap(Rank_bitmap);
2673 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2676 if (Medal_bitmap >= 0) {
2677 gr_set_bitmap(Medal_bitmap);
2678 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2681 if (Badge_bitmap >= 0) {
2682 gr_set_bitmap(Badge_bitmap);
2683 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2686 if (Wings_bitmap >= 0) {
2687 gr_set_bitmap(Wings_bitmap);
2688 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2691 if (Crest_bitmap >= 0) {
2692 gr_set_bitmap(Crest_bitmap);
2693 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2696 // draw medal/badge/rank labels
2697 debrief_draw_award_text();
2699 /* if (Rank_text_bitmap >= 0) {
2700 gr_set_bitmap(Rank_text_bitmap);
2701 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2705 if (Medal_text_bitmap >= 0) {
2706 gr_set_bitmap(Medal_text_bitmap);
2707 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2710 if (Badge_text_bitmap >= 0) {
2711 gr_set_bitmap(Badge_text_bitmap);
2712 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2717 Debrief_ui_window.draw();
2718 debrief_redraw_pressed_buttons();
2719 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2720 if (Recommend_active && (Current_mode != STATS_TAB)) {
2721 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2724 // draw the title of the mission
2725 gr_set_color_fast(&Color_bright_white);
2726 strcpy(buf, The_mission.name);
2727 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2728 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2730 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2731 gr_set_color_fast(&Color_normal);
2732 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);
2735 // draw the screen-specific text
2736 switch (Current_mode) {
2738 if ( Num_debrief_stages <= 0 ) {
2739 gr_set_color_fast(&Color_white);
2740 Assert( Game_current_mission_filename != NULL );
2741 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);
2750 debrief_stats_render();
2754 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2757 gr_set_color_fast(&Color_red);
2758 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2759 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));
2762 debrief_render_stagenum();
2763 debrief_multi_list_draw();
2765 // render some extra stuff in multiplayer
2766 if (Game_mode & GM_MULTIPLAYER) {
2767 // render the chatbox last
2771 Debrief_ui_window.draw_tooltip();
2773 // render the status indicator for the voice system
2774 multi_common_voice_display_status();
2777 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2778 // want to include the mouse pointer which is drawn in the flip
2780 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2781 debrief_check_buttons();
2782 debrief_do_keys(new_k);
2785 // blit help overlay if active
2786 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2790 // dont let dude skip 3-09. hack.
2791 if(Game_mode & GM_CAMPAIGN_MODE){
2792 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2793 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2794 Debrief_skip_popup_already_shown = 1;
2799 // maybe show skip mission popup
2800 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)) {
2801 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
2802 XSTR("Advance To The Next Mission", 1474),
2803 XSTR("Don't Show Me This Again", 1475),
2804 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
2805 switch (popup_choice) {
2807 // stay on this mission, so proceed to normal debrief
2808 // in other words, do nothing.
2811 // skip this mission
2812 mission_campaign_skip_to_next();
2813 gameseq_post_event(GS_EVENT_START_GAME);
2816 // dont show this again
2817 Player->show_skip_popup = 0;
2821 Debrief_skip_popup_already_shown = 1;
2824 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
2825 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
2826 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
2827 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
2829 Debrief_should_show_popup = 0;
2833 void debrief_rebuild_player_list()
2837 debrief_multi_list_info *list;
2839 Multi_list_size = 0; // number of net players to choose from
2841 for ( i=0; i<MAX_PLAYERS; i++ ) {
2842 np = &Net_players[i];
2843 // remember not to include the standalone.
2844 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
2845 list = &Multi_list[Multi_list_size++];
2846 list->net_player_index = i;
2847 strcpy(list->callsign, np->player->callsign);
2849 // make sure to leave some room to blit the team indicator
2850 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
2855 void debrief_handle_player_drop()
2857 debrief_rebuild_player_list();
2860 void debrief_disable_accept()