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.6 2002/07/13 06:46:48 theoddone33
21 * Revision 1.5 2002/06/09 04:41:23 relnev
22 * added copyright header
24 * Revision 1.4 2002/06/02 04:26:34 relnev
27 * Revision 1.3 2002/05/26 22:06:17 relnev
28 * makefile: disable stand_gui for now.
30 * rest: staticize some globals
32 * Revision 1.2 2002/05/07 03:16:46 theoddone33
33 * The Great Newline Fix
35 * Revision 1.1.1.1 2002/05/03 03:28:10 root
39 * 57 10/29/99 10:40p Jefff
40 * hack to make german medal names display without actually changing them
42 * 56 10/13/99 3:26p Jefff
43 * fixed unnumbered XSTRs
45 * 55 10/06/99 10:28a Jefff
48 * 54 9/30/99 5:57p Jefff
49 * show upsell at end of campaign in OEM builds
51 * 53 9/15/99 3:42a Jefff
54 * 52 9/14/99 4:35a Dave
55 * Argh. Added all kinds of code to handle potential crashes in debriefing
58 * 51 9/14/99 3:26a Dave
59 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
60 * respawn-too-early problem. Made a few crash points safe.
62 * 50 9/14/99 12:51a Jefff
64 * 49 9/13/99 6:01p Jefff
65 * fixed wrong promotion voice mapping for sm1-08
67 * 48 9/13/99 11:15a Jefff
68 * clear out award text bug fixed
70 * 47 9/13/99 12:17p Andsager
71 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
74 * 46 9/07/99 9:35p Jefff
75 * fixed bug where award text was not getting cleared properly between
78 * 45 9/07/99 6:56p Jefff
79 * a few adjustments to loop detection
81 * 44 9/07/99 1:54p Jefff
82 * skip mission cleanup
84 * 43 9/06/99 9:45p Jefff
85 * skip mission support
87 * 42 9/06/99 6:38p Dave
88 * Improved CD detection code.
90 * 41 9/03/99 1:32a Dave
91 * CD checking by act. Added support to play 2 cutscenes in a row
92 * seamlessly. Fixed super low level cfile bug related to files in the
93 * root directory of a CD. Added cheat code to set campaign mission # in
96 * 40 9/02/99 3:45p Jefff
97 * forgot to remove some debug code. doh.
99 * 39 9/02/99 3:41p Jefff
100 * changed badge voice handling to be similar to promotion voice handling
102 * 38 9/01/99 4:41p Jefff
103 * fixed stoopid text color bug
105 * 37 8/31/99 11:54a Jefff
106 * minor debrief music tweak
108 * 36 8/27/99 9:57a Dave
109 * Enabled standard cheat codes. Allow player to continue in a campaing
110 * after using cheat codes.
112 * 35 8/27/99 12:04a Dave
113 * Campaign loop screen.
115 * 34 8/26/99 8:49p Jefff
116 * Updated medals screen and about everything that ever touches medals in
117 * one way or another. Sheesh.
119 * 33 8/20/99 4:20p Jefff
120 * hack for choosing the correct promotion voice
122 * 32 8/16/99 4:05p Dave
123 * Big honking checkin.
125 * 31 8/16/99 9:49a Jefff
126 * mission title length fix in multi
128 * 30 8/11/99 5:33p Jefff
129 * added 3rd debrief music track
131 * 29 8/10/99 7:28p Jefff
132 * shuffled some text around
134 * 28 8/04/99 5:36p Andsager
135 * Show upsell screens at end of demo campaign before returning to main
138 * 27 8/04/99 2:07p Jefff
139 * mission title no longer overwrites popup
141 * 26 8/02/99 5:37p Jefff
143 * 25 8/02/99 4:52p Jefff
144 * negative feedback sound when recommendations button pressed and
147 * 24 7/21/99 6:21p Jefff
148 * added hotkeys to the "you cannot accept" popup
150 * 23 6/15/99 12:04p Anoop
151 * Added a warning for running out of debrief text lines.
153 * 22 6/09/99 2:17p Dave
154 * Fixed up pleasewait bitmap rendering.
156 * 21 6/01/99 6:07p Dave
157 * New loading/pause/please wait bar.
159 * 20 5/22/99 6:05p Dave
160 * Fixed a few localization # problems.
162 * 19 5/22/99 5:35p Dave
163 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
165 * 18 3/20/99 3:47p Andsager
166 * Fix crash with no mission loop description.
168 * 17 2/23/99 2:29p Dave
169 * First run of oldschool dogfight mode.
171 * 16 2/21/99 6:01p Dave
172 * Fixed standalone WSS packets.
174 * 15 2/11/99 3:08p Dave
175 * PXO refresh button. Very preliminary squad war support.
177 * 14 1/30/99 5:08p Dave
178 * More new hi-res stuff.Support for nice D3D textures.
180 * 13 1/29/99 2:08a Dave
181 * Fixed beam weapon collisions with players. Reduced size of scoring
182 * struct for multiplayer. Disabled PXO.
184 * 12 1/14/99 5:15p Neilk
185 * changed credits, command debrief interfaces to high resolution support
187 * 11 1/13/99 2:11p Andsager
188 * change default debriefing string text
190 * 10 12/17/98 4:50p Andsager
191 * Added debrief_assemble_optional_mission_popup_text() for single and
194 * 9 12/12/98 3:17p Andsager
195 * Clean up mission eval, goal, event and mission scoring.
197 * 8 12/10/98 10:19a Andsager
198 * Fix mission loop assert
200 * 7 12/10/98 9:59a Andsager
201 * Fix some bugs with mission loops
203 * 6 12/09/98 1:56p Andsager
204 * Initial checkin of mission loop
206 * 5 11/05/98 4:18p Dave
207 * First run nebula support. Beefed up localization a bit. Removed all
208 * conditional compiles for foreign versions. Modified mission file
211 * 4 10/23/98 3:51p Dave
212 * Full support for tstrings.tbl and foreign languages. All that remains
213 * is to make it active in Fred.
215 * 3 10/13/98 9:28a Dave
216 * Started neatening up freespace.h. Many variables renamed and
217 * reorganized. Added AlphaColors.[h,cpp]
219 * 2 10/07/98 10:53a Dave
222 * 1 10/07/98 10:49a Dave
224 * 178 9/17/98 3:08p Dave
225 * PXO to non-pxo game warning popup. Player icon stuff in create and join
226 * game screens. Upped server count refresh time in PXO to 35 secs (from
229 * 177 7/07/98 1:46p Dave
230 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
233 * 175 6/09/98 10:31a Hoffoss
234 * Created index numbers for all xstr() references. Any new xstr() stuff
235 * added from here on out should be added to the end if the list. The
236 * current list count can be found in FreeSpace.cpp (search for
239 * 174 6/07/98 3:26p Lawrance
240 * Fix bug with cut-off popup text
242 * 173 6/05/98 9:54a Lawrance
245 * 172 6/01/98 11:43a John
246 * JAS & MK: Classified all strings for localization.
248 * 171 5/27/98 1:24p Allender
249 * make targeting dots work (as well as other targeting features) properly
250 * in multiplayer. Don't query for CD when entering debrief in
253 * 170 5/26/98 11:10a Lawrance
254 * Fix bug where window controls get disabled when F1 pressed twice
256 * 169 5/24/98 12:55a Mike
257 * Prevent Assert() when no debriefing text for a stage.
259 * 168 5/23/98 10:38p Lawrance
260 * Avoid doing a cfile refresh when running debug
262 * 167 5/23/98 6:49p Lawrance
263 * Fix problems with refreshing the file list when a CD is inserted
265 * 166 5/21/98 6:57p Lawrance
266 * Don't prompt for the CD if voice not found
268 * 165 5/20/98 2:24a Dave
269 * Fixed server side voice muting. Tweaked multi debrief/endgame
270 * sequencing a bit. Much friendlier for stats tossing/accepting now.
272 * 164 5/19/98 8:35p Dave
273 * Revamp PXO channel listing system. Send campaign goals/events to
274 * clients for evaluation. Made lock button pressable on all screens.
276 * 163 5/19/98 11:13a Hoffoss
277 * Fixed bug where wrong wings award was being displayed in debriefing.
279 * 162 5/19/98 12:28a Mike
282 * 161 5/18/98 8:08p Hoffoss
283 * Moved placement of 'More' text.
285 * 160 5/18/98 3:50p Dan
286 * AL: Pick correct traitor debriefing voice file
288 * 159 5/17/98 6:32p Dave
289 * Make sure clients/servers aren't kicked out of the debriefing when team
290 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
291 * xfer/pilot info popup stuff.
293 * 158 5/16/98 9:14p Allender
294 * fix scoring ckise fir training missions to actually count medals, but
295 * nothing else. Code used to Assert when wings were granted then taken
296 * away because they were actually never granted in scoring structure
298 * 157 5/15/98 5:15p Dave
299 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
300 * status for team vs. team. Put in asserts to check for invalid team vs.
303 * 156 5/15/98 4:36p Allender
304 * fixed minor bug with wings
306 * 155 5/15/98 4:12p Allender
307 * removed redbook code. Put back in ingame join timer. Major fixups for
308 * stats in multiplayer. Pass correct score, medals, etc when leaving
309 * game. Be sure clients display medals, badges, etc.
311 * 154 5/15/98 2:25p Jasen
312 * temporarily disable granting of promotion and badges for clients
314 * 153 5/15/98 10:57a Allender
315 * fixed client side debriefings
317 * 152 5/15/98 10:36a Dave
318 * Removed 2 bogus bitmap drawing Int3()'s
320 * 151 5/14/98 2:44p Hoffoss
321 * Added wings awarding to debrief screen.
323 * 150 5/13/98 9:11p Lawrance
324 * Make 'replay mission' popup warn users about the loss of mission stats.
329 #include "missiondebrief.h"
330 #include "missionbriefcommon.h"
331 #include "missionscreencommon.h"
332 #include "missiongoals.h"
333 #include "missionpause.h"
334 #include "freespace.h"
335 #include "gamesequence.h"
343 #include "audiostr.h"
346 #include "contexthelp.h"
352 #include "multimsgs.h"
353 #include "multiutil.h"
354 #include "multiteamselect.h"
356 #include "eventmusic.h"
360 #include "multi_pinfo.h"
361 #include "contexthelp.h"
362 #include "multi_kick.h"
363 #include "multi_campaign.h"
364 #include "alphacolors.h"
365 #include "localize.h"
366 #include "multi_endgame.h"
369 #define MAX_TOTAL_DEBRIEF_LINES 200
371 #define TEXT_TYPE_NORMAL 1
372 #define TEXT_TYPE_RECOMMENDATION 2
374 #define DEBRIEF_NUM_STATS_PAGES 4
375 #define DEBRIEF_MISSION_STATS 0
376 #define DEBRIEF_MISSION_KILLS 1
377 #define DEBRIEF_ALLTIME_STATS 2
378 #define DEBRIEF_ALLTIME_KILLS 3
380 // 3rd coord is max width in pixels
381 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
390 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
399 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
404 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
413 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
422 #define MULTI_LIST_TEAM_OFFSET 16
424 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
429 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
438 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
448 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
457 // 0=x, 1=y, 2=width of the field
458 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
467 // 0=x, 1=y, 2=height of the field
468 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
478 // 1 = without medal (text will use medal space)
479 #define DB_WITH_MEDAL 0
480 #define DB_WITHOUT_MEDAL 1
481 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
490 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
491 "DebriefSingle", // GR_640
492 "2_DebriefSingle" // GR_1024
494 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
495 "DebriefMulti", // GR_640
496 "2_DebriefMulti" // GR_1024
498 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
499 "Debrief-m", // GR_640
500 "2_Debrief-m" // GR_1024
503 #define NUM_BUTTONS 18
506 #define DEBRIEF_TAB 0
508 #define TEXT_SCROLL_UP 2
509 #define TEXT_SCROLL_DOWN 3
510 #define REPLAY_MISSION 4
511 #define RECOMMENDATIONS 5
512 #define FIRST_STAGE 6
516 #define MULTI_PINFO_POPUP 10
517 #define MULTI_KICK 11
518 #define MEDALS_BUTTON 12
519 #define PLAYER_SCROLL_UP 13
520 #define PLAYER_SCROLL_DOWN 14
521 #define HELP_BUTTON 15
522 #define OPTIONS_BUTTON 16
523 #define ACCEPT_BUTTON 17
528 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
529 "PleaseWait", // GR_640
530 "2_PleaseWait" // GR_1024
536 char text[NAME_LENGTH+1]; // name of ship type with a colon
537 int num; // how many ships of this type player has killed
538 } debrief_stats_kill_info;
541 int net_player_index; // index into Net_players[] array
542 int rank_bitmap; // bitmap id for rank
543 char callsign[CALLSIGN_LEN];
544 } debrief_multi_list_info;
546 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
548 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
549 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
550 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
551 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
552 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
553 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
554 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
555 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
556 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
557 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
558 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
559 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
560 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
561 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
562 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
563 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
564 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
565 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
568 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
569 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
570 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
571 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
572 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
573 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
574 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
575 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
576 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
577 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
578 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
579 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
580 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
581 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
582 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
583 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
584 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
585 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
590 #define NUM_DEBRIEF_TEXT 10
591 #define MP_TEXT_INDEX_1 4
592 #define MP_TEXT_INDEX_2 5
593 #define MP_TEXT_INDEX_3 6
594 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
596 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
597 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
598 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
599 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
600 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
601 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
602 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
603 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
604 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
605 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
608 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
609 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
610 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
611 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
612 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
613 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
614 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
615 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
616 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
617 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
622 char Debrief_current_callsign[CALLSIGN_LEN+10];
623 player *Debrief_player;
625 static UI_WINDOW Debrief_ui_window;
626 static UI_BUTTON List_region;
627 static int Background_bitmap; // bitmap for the background of the debriefing
628 static int Award_bg_bitmap;
629 static int Debrief_multi_loading_bitmap;
630 static int Rank_bitmap;
631 static int Medal_bitmap;
632 static int Badge_bitmap;
633 static int Wings_bitmap;
634 static int Crest_bitmap;
635 //static int Rank_text_bitmap;
636 //static int Medal_text_bitmap;
637 //static int Badge_text_bitmap;
639 static int Debrief_accepted;
640 static int Turned_traitor;
641 static int Must_replay_mission;
643 static int Current_mode;
645 static int Recommend_active;
646 static int Award_active;
647 static int Text_offset;
648 static int Num_text_lines = 0;
649 static int Num_debrief_lines = 0;
650 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
651 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
653 static int Debrief_inited = 0;
654 static int New_stage;
655 static int Current_stage;
656 static int Num_stages;
657 static int Num_debrief_stages;
658 static int Stage_voice;
660 static int Multi_list_size;
661 static int Multi_list_offset;
663 int Debrief_multi_stages_loaded = 0;
664 int Debrief_multi_voice_loaded = 0;
666 // static int Debrief_voice_ask_for_cd;
668 // voice id's for debriefing text
669 static int Debrief_voices[MAX_DEBRIEF_STAGES];
671 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
672 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
673 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
675 // pointer used for getting to debriefing information
676 debriefing Traitor_debriefing; // used when player is a traitor
678 // pointers to the active stages for this debriefing
679 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
680 static debrief_stage Promotion_stage, Badge_stage;
681 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
682 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
683 int Multi_list_select;
685 // flag indicating if we should display info for the given player (in multiplayer)
686 int Debrief_should_show_popup = 1;
688 // already shown skip mission popup?
689 static int Debrief_skip_popup_already_shown = 0;
691 void debrief_text_init();
692 void debrief_accept(int ok_to_post_start_game_event = 1);
693 void debrief_kick_selected_player();
696 // promotion voice selection stuff
697 #define NUM_VOLITION_CAMPAIGNS 1
699 char campaign_name[32];
701 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
703 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
704 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
708 // data for which voice goes w/ which mission
709 typedef struct voice_map {
710 char mission_file[32];
714 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
715 { // FreeSpace2 campaign
747 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
749 { "loop1-1.fs2", 4 },
750 { "loop1-2.fs2", 4 },
751 { "loop1-3.fs2", 5 },
752 { "loop2-1.fs2", 4 },
757 #define DB_AWARD_WINGS 0
758 #define DB_AWARD_MEDAL 1
759 #define DB_AWARD_SOC 2
760 #define DB_AWARD_RANK 3
761 #define DB_AWARD_BADGE 4
762 #define DB_AWARD_BG 5
763 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
782 #define AWARD_TEXT_MAX_LINES 5
783 #define AWARD_TEXT_MAX_LINE_LENGTH 128
784 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
785 int Debrief_award_text_num_lines = 0;
789 // prototypes, you know you love 'em
790 void debrief_add_award_text(char *str);
791 void debrief_award_text_clear();
796 char *debrief_tooltip_handler(char *str)
798 if (!stricmp(str, NOX("@.Medal"))) {
800 return XSTR( "Medal", 435);
803 } else if (!stricmp(str, NOX("@.Rank"))) {
805 return XSTR( "Rank", 436);
808 } else if (!stricmp(str, NOX("@.Badge"))) {
810 return XSTR( "Badge", 437);
813 } else if (!stricmp(str, NOX("@Medal"))) {
814 if (Medal_bitmap >= 0){
815 return Medals[Player->stats.m_medal_earned].name;
818 } else if (!stricmp(str, NOX("@Rank"))) {
819 if (Rank_bitmap >= 0){
820 return Ranks[Promoted].name;
823 } else if (!stricmp(str, NOX("@Badge"))) {
824 if (Badge_bitmap >= 0){
825 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
832 // initialize the array of handles to the different voice streams
833 void debrief_voice_init()
837 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
838 Debrief_voices[i] = -1;
842 void debrief_load_voice_file(int voice_num, char *name)
844 int load_attempts = 0;
847 if ( load_attempts++ > 5 ) {
851 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
852 if ( Debrief_voices[voice_num] >= 0 ) {
856 // Don't bother to ask for the CD in multiplayer
857 if ( Game_mode & GM_MULTIPLAYER ) {
861 // couldn't load voice, ask user to insert CD (if necessary)
863 // if ( Debrief_voice_ask_for_cd ) {
864 // if ( game_do_cd_check() == 0 ) {
865 // Debrief_voice_ask_for_cd = 0;
872 // open and pre-load the stream buffers for the different voice streams
873 void debrief_voice_load_all()
877 // Debrief_voice_ask_for_cd = 1;
879 for ( i=0; i<Num_debrief_stages; i++ ) {
880 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
883 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
884 debrief_load_voice_file(i, Debrief_stages[i]->voice);
885 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
890 // close all the briefing voice streams
891 void debrief_voice_unload_all()
895 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
896 if ( Debrief_voices[i] != -1 ) {
897 audiostream_close_file(Debrief_voices[i], 0);
898 Debrief_voices[i] = -1;
903 // start playback of the voice for a particular briefing stage
904 void debrief_voice_play()
906 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
910 // no more stages? We are done then.
911 if (Stage_voice >= Num_debrief_stages){
915 // if in delayed start, see if delay has elapsed and start voice if so
916 if (Debrief_cue_voice) {
917 if (!timestamp_elapsed(Debrief_cue_voice)){
921 Stage_voice++; // move up to next voice
922 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
923 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
924 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
930 // see if voice is still playing. If so, do nothing yet.
931 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
935 // set voice to play in a little while from now.
936 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
939 // stop playback of the voice for a particular briefing stage
940 void debrief_voice_stop()
942 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
945 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
949 // function to deal with inserting possible promition and badge stages into the debriefing
951 void debrief_multi_fixup_stages()
955 // possibly insert the badge stage first, them the promotion stage since they are
956 // inserted at the front of the debrief stages.
957 if ( Badge_bitmap >= 0 ) {
958 // move all stages forward one. Don't
959 for ( i = Num_debrief_stages; i > 0; i-- ) {
960 Debrief_stages[i] = Debrief_stages[i-1];
962 Debrief_stages[0] = &Badge_stage;
963 Num_debrief_stages++;
966 if ( Promoted >= 0) {
967 // move all stages forward one
968 for ( i = Num_debrief_stages; i > 0; i-- ) {
969 Debrief_stages[i] = Debrief_stages[i-1];
971 Debrief_stages[0] = &Promotion_stage;
972 Num_debrief_stages++;
977 // function called from multiplayer clients to set up the debriefing information for them
978 // (sent from the server).
979 void debrief_set_multi_clients( int stage_count, int active_stages[] )
983 // set up the right briefing for this guy
984 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
985 Debriefing = &Debriefings[Net_player->p_info.team];
987 Debriefing = &Debriefings[0];
990 // see if this client was promoted -- if so, then add the first stage.
991 Num_debrief_stages = 0;
993 // set the pointers to the debriefings for this client
994 for (i = 0; i < stage_count; i++) {
995 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
998 Debrief_multi_stages_loaded = 1;
1001 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
1002 // information to all clients after leaving this screen.
1003 void debrief_multi_server_stuff()
1005 debriefing *debriefp;
1007 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1008 int i, j, num_stages, stage_count[MAX_TEAMS];
1010 memset( stage_active, 0, sizeof(stage_active) );
1012 for (i=0; i<Num_teams; i++) {
1013 debriefp = &Debriefings[i];
1015 stages[i] = stage_active[i];
1016 for (j=0; j<debriefp->num_stages; j++) {
1017 if ( eval_sexp(debriefp->stages[j].formula) ) {
1018 stage_active[i][num_stages] = j;
1023 stage_count[i] = num_stages;
1026 // if we're in campaign mode, evaluate campaign stuff
1027 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1028 multi_campaign_eval_debrief();
1031 // send the information to all clients.
1032 send_debrief_info( stage_count, stages );
1036 // --------------------------------------------------------------------------------------
1037 // debrief_set_stages_and_multi_stuff()
1039 // Set up the active stages for this debriefing
1041 // returns: number of active debriefing stages
1043 int debrief_set_stages_and_multi_stuff()
1046 debriefing *debriefp;
1048 if ( MULTIPLAYER_CLIENT ) {
1052 Num_debrief_stages = 0;
1054 if ( Game_mode & GM_MULTIPLAYER ) {
1055 debrief_multi_server_stuff();
1058 // check to see if player is a traitor (looking at his team). If so, use the special
1059 // traitor debriefing. Only done in single player
1060 debriefp = Debriefing;
1061 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1062 if (Player_ship->team == TEAM_TRAITOR)
1063 debriefp = &Traitor_debriefing;
1066 Num_debrief_stages = 0;
1067 if (Promoted >= 0) {
1068 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1071 if (Badge_bitmap >= 0) {
1072 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1075 for (i=0; i<debriefp->num_stages; i++) {
1076 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1077 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1081 return Num_debrief_stages;
1084 // init the buttons that are specific to the debriefing screen
1085 void debrief_buttons_init()
1090 for ( i=0; i<NUM_BUTTONS; i++ ) {
1091 b = &Buttons[gr_screen.res][i];
1092 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1093 // set up callback for when a mouse first goes over a button
1094 b->button.set_highlight_action( common_play_highlight_sound );
1095 b->button.set_bmaps(b->filename);
1096 b->button.link_hotspot(b->hotspot);
1100 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1101 // multiplayer specific text
1102 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1103 // only add if in multiplayer mode
1104 if(Game_mode & GM_MULTIPLAYER){
1105 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1110 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1114 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1115 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1116 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1117 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1118 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1119 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1120 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1121 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1123 // if in multiplayer, disable the button for all players except the host
1124 // also disable for squad war matches
1125 if(Game_mode & GM_MULTIPLAYER){
1126 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1127 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1132 // --------------------------------------------------------------------------------------
1133 // debrief_ui_init()
1135 void debrief_ui_init()
1137 // init ship selection masks and buttons
1138 common_set_interface_palette("DebriefPalette"); // set the interface palette
1139 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1140 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1141 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1142 debrief_buttons_init();
1144 // load in help overlay bitmap
1145 help_overlay_load(DEBRIEFING_OVERLAY);
1146 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1148 if ( Game_mode & GM_MULTIPLAYER ) {
1149 // close down any old instances of the chatbox
1152 // create the new one
1154 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1155 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);
1158 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1161 if ( Background_bitmap < 0 ) {
1162 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1165 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1166 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1169 // sets Promotion_stage.voice
1170 // defaults to number 9 (Petrarch) for non-volition missions
1171 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1172 void debrief_choose_promotion_voice()
1176 if(Campaign.current_mission < 0){
1177 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1181 // search thru all official campaigns for our current campaign
1182 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1183 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1184 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1185 // now search thru the mission filenames,
1186 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1187 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1188 // found it! set the persona and bail
1189 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1197 // default to petrarch
1198 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1201 // sets Promotion_stage.voice
1202 // defaults to number 9 (Petrarch) for non-volition missions
1203 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1204 void debrief_choose_badge_voice()
1208 if(Campaign.current_mission < 0){
1209 // default to petrarch
1210 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1213 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1214 // search thru all official campaigns for our current campaign
1215 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1216 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1217 // now search thru the mission filenames,
1218 for (j=0; j<Campaign.num_missions; j++) {
1219 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1220 // found it! set the persona and bail
1221 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1229 // default to petrarch
1230 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1234 void debrief_award_init()
1246 // be sure there are no old award texts floating around
1247 debrief_award_text_clear();
1249 // handle medal earned
1250 if (Player->stats.m_medal_earned != -1) {
1251 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1253 if ( Player->stats.medals[13] > 1 ) {
1258 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1259 Wings_bitmap = bm_load(buf);
1261 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1262 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1264 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1265 Medal_bitmap = bm_load(buf);
1268 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1271 // handle promotions
1272 if ( Player->stats.m_promotion_earned != -1 ) {
1273 Promoted = Player->stats.m_promotion_earned;
1274 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1275 Rank_bitmap = bm_load(buf);
1277 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1278 Promotion_stage.new_recommendation_text = NULL;
1280 // choose appropriate promotion voice for this mission
1281 debrief_choose_promotion_voice();
1283 debrief_add_award_text(Ranks[Promoted].name);
1286 // handle badge earned
1287 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1288 if ( Player->stats.m_badge_earned != -1 ) {
1289 i = Player->stats.m_badge_earned;
1290 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1291 Badge_bitmap = bm_load(buf);
1293 Badge_stage.new_text = Badge_info[i].promotion_text;
1294 Badge_stage.new_recommendation_text = NULL;
1296 // choose appropriate voice
1297 debrief_choose_badge_voice();
1299 debrief_add_award_text(Medals[Badge_index[i]].name);
1302 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1309 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1310 // mission a traitor. The same debriefing always gets played
1311 void debrief_traitor_init()
1313 static int inited = 0;
1316 debriefing *debrief;
1317 debrief_stage *stagep;
1321 if ((rval = setjmp(parse_abort)) != 0) {
1322 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1325 read_file_text("traitor.tbl");
1329 // open localization
1332 // simplied form of the debriefing stuff.
1333 debrief = &Traitor_debriefing;
1334 required_string("#Debriefing_info");
1336 required_string("$Num stages:");
1337 stuff_int(&debrief->num_stages);
1338 Assert(debrief->num_stages == 1);
1341 stagep = &debrief->stages[stage_num++];
1342 required_string("$Formula:");
1343 stagep->formula = get_sexp_main();
1344 required_string("$multi text");
1345 if ( Fred_running ) {
1346 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1348 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1350 required_string("$Voice:");
1351 char traitor_voice_file[NAME_LENGTH];
1352 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1354 // DKA 9/13/99 Only 1 traitor msg for FS2
1355 // if ( Player->on_bastion ) {
1356 // strcpy(stagep->voice, NOX("3_"));
1358 // strcpy(stagep->voice, NOX("1_"));
1361 strcat(stagep->voice, traitor_voice_file);
1363 required_string("$Recommendation text:");
1364 if ( Fred_running ) {
1365 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1367 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1371 // close localization
1375 // disable the accept button if in single player and I am a traitor
1376 Debrief_accepted = 0;
1377 Turned_traitor = Must_replay_mission = 0;
1378 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1379 if (Player_ship->team == TEAM_TRAITOR){
1383 if (Campaign.next_mission == Campaign.current_mission){
1384 Must_replay_mission = 1;
1388 if (Turned_traitor || Must_replay_mission) {
1389 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1391 // kill off any stats
1392 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1393 scoring_level_init( &Player->stats );
1397 // initialization for listing of players in game
1398 void debrief_multi_list_init()
1400 Multi_list_size = 0; // number of net players to choose from
1401 Multi_list_offset = 0;
1403 Multi_list_select = -1;
1405 if ( !(Game_mode & GM_MULTIPLAYER) )
1408 debrief_rebuild_player_list();
1410 // switch stats display to this newly selected player
1411 set_player_stats(Multi_list[0].net_player_index);
1412 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1413 Debrief_player = Player;
1416 void debrief_multi_list_scroll_up()
1418 // if we're at the beginning of the list, don't do anything
1419 if(Multi_list_offset == 0){
1420 gamesnd_play_iface(SND_GENERAL_FAIL);
1424 // otherwise scroll up
1425 Multi_list_offset--;
1426 gamesnd_play_iface(SND_USER_SELECT);
1429 void debrief_multi_list_scroll_down()
1431 // if we can scroll down no further
1432 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1433 gamesnd_play_iface(SND_GENERAL_FAIL);
1436 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1437 gamesnd_play_iface(SND_GENERAL_FAIL);
1441 // otherwise scroll down
1442 Multi_list_offset++;
1443 gamesnd_play_iface(SND_USER_SELECT);
1446 // draw the connected net players
1447 void debrief_multi_list_draw()
1449 int y, z, font_height,idx;
1450 char str[CALLSIGN_LEN+5];
1453 font_height = gr_get_font_height();
1455 // if we currently have no item picked, pick a reasonable one
1456 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1457 // select the entry which corresponds to the local player
1458 Multi_list_select = 0;
1459 for(idx=0;idx<Multi_list_size;idx++){
1460 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1461 Multi_list_select = idx;
1463 // switch stats display to this newly selected player
1464 set_player_stats(Multi_list[idx].net_player_index);
1465 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1466 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1472 // draw the list itself
1474 z = Multi_list_offset;
1475 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1476 np = &Net_players[Multi_list[z].net_player_index];
1478 if (z >= Multi_list_size){
1481 // set the proper text color for the highlight
1482 if(np->flags & NETINFO_FLAG_GAME_HOST){
1483 if(Multi_list_select == z){
1484 gr_set_color_fast(&Color_text_active_hi);
1486 gr_set_color_fast(&Color_bright);
1489 if(Multi_list_select == z){
1490 gr_set_color_fast(&Color_text_active);
1492 gr_set_color_fast(&Color_text_normal);
1496 // blit the proper indicator - skipping observers
1497 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1498 if(Netgame.type_flags & NG_TYPE_TEAM){
1500 if(np->p_info.team == 0){
1501 // draw his "selected" icon
1502 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1503 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1504 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1506 // draw his "normal" icon
1507 else if(Multi_common_icons[MICON_TEAM0] != -1){
1508 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1509 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1511 } else if(np->p_info.team == 1){
1512 // draw his "selected" icon
1513 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1514 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1515 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1517 // draw his "normal" icon
1518 else if(Multi_common_icons[MICON_TEAM1] != -1){
1519 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1520 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1524 // draw the team 0 selected icon
1525 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1526 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1527 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1532 strcpy(str,Multi_list[z].callsign);
1533 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)){
1534 strcat(str,XSTR( "(O)", 438));
1538 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1545 void debrief_kick_selected_player()
1547 if(Multi_list_select >= 0){
1548 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1549 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1553 // get optional mission popup text
1554 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1556 Assert(buffer != NULL);
1559 if (mission_loop_desc == NULL) {
1560 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1561 mprintf(("No mission loop description avail"));
1563 strcpy(buffer, mission_loop_desc);
1566 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1569 // what to do when the accept button is hit
1570 void debrief_accept(int ok_to_post_start_game_event)
1574 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1578 if (Game_mode & GM_MULTIPLAYER) {
1582 if (Player_ship->team == TEAM_TRAITOR){
1583 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1584 }/* else if (Cheats_enabled) {
1585 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1587 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1590 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1592 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1593 } else if ( z == 1 ) {
1594 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1600 Debrief_accepted = 1;
1601 // save mission stats
1602 if (Game_mode & GM_MULTIPLAYER) {
1603 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1604 // as well as doing stats transfers, etc.
1605 multi_debrief_accept_hit();
1609 int play_commit_sound = 1;
1610 // only write the player's stats if he's accepted
1612 // if we are just playing a single mission, then don't do many of the things
1613 // that need to be done. Nothing much should happen when just playing a single
1614 // mission that isn't in a campaign.
1615 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1617 // check for possible mission loop
1618 // check for (1) mission loop available, (2) dont have to repeat last mission
1619 if(!(Game_mode & GM_MULTIPLAYER)){
1620 int cur = Campaign.current_mission;
1621 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1622 if (Campaign.missions[cur].has_mission_loop) {
1623 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1626 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1629 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1631 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1633 Campaign.loop_enabled = 1;
1634 Campaign.next_mission = Campaign.loop_mission;
1643 if(ok_to_post_start_game_event){
1644 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1646 play_commit_sound = 0;
1649 // continue as normal
1652 mission_campaign_mission_over();
1654 // check to see if we are out of the loop now
1655 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1656 Campaign.loop_enabled = 0;
1659 // check if campaign is over
1660 if ( Campaign.next_mission == -1 ) {
1661 #if defined(FS2_DEMO) || defined(OEM_BUILD)
1662 gameseq_post_event(GS_EVENT_END_DEMO);
1664 gameseq_post_event(GS_EVENT_MAIN_MENU);
1667 if ( ok_to_post_start_game_event ) {
1669 if(game_do_cd_mission_check(Game_current_mission_filename)){
1670 gameseq_post_event(GS_EVENT_START_GAME);
1672 gameseq_post_event(GS_EVENT_MAIN_MENU);
1675 play_commit_sound = 0;
1680 gameseq_post_event(GS_EVENT_MAIN_MENU);
1683 if ( play_commit_sound ) {
1684 gamesnd_play_iface(SND_COMMIT_PRESSED);
1691 void debrief_next_tab()
1693 New_mode = Current_mode + 1;
1694 if (New_mode >= NUM_TABS)
1698 void debrief_prev_tab()
1700 New_mode = Current_mode - 1;
1702 New_mode = NUM_TABS - 1;
1705 // --------------------------------------------------------------------------------------
1706 // debrief_next_stage()
1708 void debrief_next_stage()
1710 if (Current_stage < Num_stages - 1) {
1711 New_stage = Current_stage + 1;
1712 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1715 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1718 // --------------------------------------------------------------------------------------
1719 // debrief_prev_stage()
1721 void debrief_prev_stage()
1723 if (Current_stage) {
1724 New_stage = Current_stage - 1;
1725 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1728 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1731 // --------------------------------------------------------------------------------------
1732 // debrief_first_stage()
1733 void debrief_first_stage()
1735 if (Current_stage) {
1737 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1740 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1743 // --------------------------------------------------------------------------------------
1744 // debrief_last_stage()
1745 void debrief_last_stage()
1747 if (Current_stage != Num_stages - 1) {
1748 New_stage = Num_stages - 1;
1749 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1752 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1755 // draw what stage number the debriefing is on
1756 void debrief_render_stagenum()
1764 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1765 gr_get_string_size(&w, NULL, buf);
1766 gr_set_color_fast(&Color_bright_blue);
1767 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1768 gr_set_color_fast(&Color_white);
1771 // render the mission time at the specified y location
1772 void debrief_render_mission_time(int y_loc)
1776 game_format_time(Missiontime, time_str);
1777 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1778 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1781 // render out the debriefing text to the scroll window
1782 void debrief_render()
1784 int y, z, font_height;
1786 if ( Num_stages <= 0 )
1789 font_height = gr_get_font_height();
1791 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]);
1794 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1795 if (z >= Num_text_lines)
1798 if (Text_type[z] == TEXT_TYPE_NORMAL)
1799 gr_set_color_fast(&Color_white);
1801 gr_set_color_fast(&Color_bright_red);
1804 gr_string(0, y, Text[z]);
1813 // render out the stats info to the scroll window
1815 void debrief_stats_render()
1817 int i, y, font_height;
1819 gr_set_color_fast(&Color_blue);
1820 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]);
1821 gr_string(0, 0, Debrief_current_callsign);
1822 font_height = gr_get_font_height();
1825 switch ( Current_stage ) {
1826 case DEBRIEF_MISSION_STATS:
1827 i = Current_stage - 1;
1831 gr_set_color_fast(&Color_white);
1833 // display mission completion time
1834 debrief_render_mission_time(y);
1837 show_stats_label(i, 0, y, font_height);
1838 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1840 case DEBRIEF_ALLTIME_STATS:
1841 i = Current_stage - 1;
1845 gr_set_color_fast(&Color_white);
1846 show_stats_label(i, 0, y, font_height);
1847 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1850 case DEBRIEF_ALLTIME_KILLS:
1851 case DEBRIEF_MISSION_KILLS:
1852 gr_set_color_fast(&Color_white);
1854 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1855 if (i >= Num_text_lines)
1859 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1860 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
1862 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
1865 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
1866 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
1873 if (Num_text_lines == 2) {
1874 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1875 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
1877 gr_printf(0, y, XSTR( "(No ship kills)", 450));
1890 // do action for when the replay button is pressed
1891 void debrief_replay_pressed()
1893 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
1895 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));
1902 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
1903 gamesnd_play_iface(SND_COMMIT_PRESSED);
1906 // -------------------------------------------------------------------
1907 // debrief_redraw_pressed_buttons()
1909 // Redraw any debriefing buttons that are pressed down. This function is needed
1910 // since we sometimes need to draw pressed buttons last to ensure the entire
1911 // button gets drawn (and not overlapped by other buttons)
1913 void debrief_redraw_pressed_buttons()
1918 for ( i=0; i<NUM_BUTTONS; i++ ) {
1919 b = &Buttons[gr_screen.res][i].button;
1920 // don't draw the recommendations button if we're in stats mode
1921 if ( b->button_down() ) {
1927 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
1929 void debrief_button_pressed(int num)
1933 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
1934 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
1935 if (num != Current_mode){
1936 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1941 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
1942 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
1943 if (num != Current_mode){
1944 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1949 case TEXT_SCROLL_UP:
1952 gamesnd_play_iface(SND_SCROLL);
1954 gamesnd_play_iface(SND_GENERAL_FAIL);
1958 case TEXT_SCROLL_DOWN:
1959 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
1961 gamesnd_play_iface(SND_SCROLL);
1963 gamesnd_play_iface(SND_GENERAL_FAIL);
1967 case REPLAY_MISSION:
1968 if(Game_mode & GM_MULTIPLAYER){
1969 multi_debrief_replay_hit();
1971 debrief_replay_pressed();
1975 case RECOMMENDATIONS:
1976 gamesnd_play_iface(SND_USER_SELECT);
1977 Recommend_active = !Recommend_active;
1978 debrief_text_init();
1982 debrief_first_stage();
1986 debrief_prev_stage();
1990 debrief_next_stage();
1994 debrief_last_stage();
1998 gamesnd_play_iface(SND_HELP_PRESSED);
1999 launch_context_help();
2002 case OPTIONS_BUTTON:
2003 gamesnd_play_iface(SND_SWITCH_SCREENS);
2004 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2012 gamesnd_play_iface(SND_SWITCH_SCREENS);
2013 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2016 case PLAYER_SCROLL_UP:
2017 debrief_multi_list_scroll_up();
2020 case PLAYER_SCROLL_DOWN:
2021 debrief_multi_list_scroll_down();
2024 case MULTI_PINFO_POPUP:
2025 Debrief_should_show_popup = 1;
2029 debrief_kick_selected_player();
2034 void debrief_setup_ship_kill_stats(int stage_num)
2038 debrief_stats_kill_info *kill_info;
2040 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2041 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2044 Assert(Debrief_player != NULL);
2046 // kill_ar points to an array of MAX_SHIP_TYPE ints
2047 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2048 kill_arr = Debrief_player->stats.m_okKills;
2050 kill_arr = Debrief_player->stats.kills;
2054 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2056 // code used to add in mission kills, but the new system assumes that the player will accept, so
2057 // all time stats already have mission stats added in.
2058 if ( kill_arr[i] <= 0 ){
2063 kill_info = &Debrief_stats_kills[Num_text_lines++];
2065 kill_info->num = kill_arr[i];
2067 strcpy(kill_info->text, Ship_info[i].name);
2068 strcat(kill_info->text, NOX(":"));
2071 Num_text_lines += 2;
2074 // Iterate through the debriefing buttons, checking if they are pressed
2075 void debrief_check_buttons()
2079 for ( i=0; i<NUM_BUTTONS; i++ ) {
2080 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2081 debrief_button_pressed(i);
2085 if ( !(Game_mode & GM_MULTIPLAYER) )
2088 if (List_region.pressed()) {
2089 List_region.get_mouse_pos(NULL, &y);
2090 z = Multi_list_offset + y / gr_get_font_height();
2091 if ((z >= 0) && (z < Multi_list_size)) {
2092 // switch stats display to this newly selected player
2093 set_player_stats(Multi_list[z].net_player_index);
2094 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2095 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2096 Multi_list_select = z;
2097 debrief_setup_ship_kill_stats(Current_stage);
2098 gamesnd_play_iface(SND_USER_SELECT);
2102 // if the player was double clicked on - we should popup a player info popup
2104 if (List_region.double_clicked()) {
2105 Debrief_should_show_popup = 1;
2110 void debrief_text_stage_init(char *src, int type)
2112 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2113 char line[MAX_DEBRIEF_LINE_LEN];
2114 char *p_str[MAX_DEBRIEF_LINES];
2116 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2117 Assert(n_lines >= 0);
2119 // if you hit this, you proba
2120 if(n_lines >= MAX_DEBRIEF_LINES){
2121 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2124 for ( i=0; i<n_lines; i++ ) {
2125 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2126 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2127 strncpy(line, p_str[i], n_chars[i]);
2128 line[n_chars[i]] = 0;
2129 drop_white_space(line);
2130 Text_type[Num_text_lines] = type;
2131 Text[Num_text_lines++] = strdup(line);
2137 void debrief_free_text()
2141 for (i=0; i<Num_debrief_lines; i++)
2145 Num_debrief_lines = 0;
2148 // setup the debriefing text lines for rendering
2149 void debrief_text_init()
2154 // release old text lines first
2155 debrief_free_text();
2156 Num_text_lines = Text_offset = 0;
2158 if (Current_mode == DEBRIEF_TAB) {
2159 for (i=0; i<Num_debrief_stages; i++) {
2161 Text[Num_text_lines++] = NULL; // add a blank line between stages
2163 src = Debrief_stages[i]->new_text;
2165 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2167 if (Recommend_active) {
2168 src = Debrief_stages[i]->new_recommendation_text;
2169 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2170 src = XSTR( "We have no recommendations for you.", 1054);
2173 Text[Num_text_lines++] = NULL;
2174 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2180 Num_debrief_lines = Num_text_lines;
2184 // not in debriefing mode, must be in stats mode
2186 debrief_setup_ship_kill_stats(Current_stage);
2190 // --------------------------------------------------------------------------------------
2194 Assert(!Debrief_inited);
2195 // Campaign.loop_enabled = 0;
2196 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2198 // set up the right briefing for this guy
2199 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2200 Debriefing = &Debriefings[Net_player->p_info.team];
2202 Debriefing = &Debriefings[0];
2205 // no longer is mission
2206 Game_mode &= ~(GM_IN_MISSION);
2210 New_mode = DEBRIEF_TAB;
2211 Recommend_active = Award_active = 0;
2216 Debrief_cue_voice = 0;
2217 Num_text_lines = Num_debrief_lines = 0;
2218 Debrief_first_voice_flag = 1;
2220 Debrief_multi_voice_loaded = 0;
2222 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2223 // MUST store goals and events first - may be used to evaluate next mission
2224 // store goals and events
2225 mission_campaign_store_goals_and_events();
2227 // evaluate next mission
2228 mission_campaign_eval_next_mission();
2231 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2233 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2234 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2237 // call scoring level close for my stats. Needed for award_init. The stats will
2238 // be backed out if used chooses to replace them.
2239 scoring_level_close();
2241 debrief_ui_init(); // init UI items
2242 debrief_award_init();
2244 debrief_voice_init();
2245 debrief_multi_list_init();
2246 // rank_bitmaps_clear();
2247 // rank_bitmaps_load();
2249 strcpy(Debrief_current_callsign, Player->callsign);
2250 Debrief_player = Player;
2251 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2253 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2254 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2255 // info directly from the server.
2256 if ( !MULTIPLAYER_CLIENT ) {
2257 debrief_set_stages_and_multi_stuff();
2259 if ( Num_debrief_stages <= 0 ) {
2260 Num_debrief_stages = 0;
2262 debrief_voice_load_all();
2265 // multiplayer client may have already received their debriefing info. If they have not,
2266 // then set the num debrief stages to 0
2267 if ( !Debrief_multi_stages_loaded ) {
2268 Num_debrief_stages = 0;
2273 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2274 common_music_init(SCORE_DEBRIEF_SUCCESS);
2276 common_music_init(SCORE_DEBRIEF_FAIL);
2280 // start up the appropriate music
2281 if (Campaign.next_mission == Campaign.current_mission) {
2282 // you failed the mission because you suck, so you get the suck music
2283 common_music_init(SCORE_DEBRIEF_FAIL);
2284 } else if (mission_goals_met()) {
2285 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2286 common_music_init(SCORE_DEBRIEF_SUCCESS);
2288 // you somehow passed the mission, so you get a little something for your efforts.
2289 common_music_init(SCORE_DEBRIEF_AVERAGE);
2292 if (Campaign.next_mission == Campaign.current_mission) {
2293 // better luck next time, increase his retries
2294 Player->failures_this_session++;
2296 // clear his retries info regardless of whether or not he accepts
2297 Player->failures_this_session = 0;
2300 if (Game_mode & GM_MULTIPLAYER) {
2301 multi_debrief_init();
2303 // if i'm not the host of the game, disable the multi kick button
2304 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2305 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2308 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2309 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2310 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2311 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2312 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2313 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2314 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2315 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2318 if (!Award_active) {
2319 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2320 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2323 Debrief_skip_popup_already_shown = 0;
2328 // --------------------------------------------------------------------------------------
2330 void debrief_close()
2334 Assert(Debrief_inited);
2336 // if the mission wasn't accepted, clear out my stats
2337 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2338 // are a little bit different
2339 if (Game_mode & GM_MULTIPLAYER) {
2340 // if stats weren't accepted, backout my own stats
2341 if (multi_debrief_stats_accept_code() != 1) {
2342 if(MULTIPLAYER_MASTER){
2343 for(idx=0; idx<MAX_PLAYERS; idx++){
2344 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2345 scoring_backout_accept(&Net_players[idx].player->stats);
2349 scoring_backout_accept( &Player->stats );
2354 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2355 scoring_backout_accept( &Player->stats );
2359 // if dude passed the misson and accepted, reset his show skip popup flag
2360 if (Debrief_accepted) {
2361 Player->show_skip_popup = 1;
2364 if (Num_debrief_lines) {
2365 for (i=0; i<Num_debrief_lines; i++){
2372 // unload the overlay bitmap
2373 // help_overlay_unload(DEBRIEFING_OVERLAY);
2375 // clear out award text
2376 Debrief_award_text_num_lines = 0;
2378 debrief_voice_unload_all();
2379 common_music_close();
2382 // rank_bitmaps_release();
2385 if (Background_bitmap >= 0){
2386 bm_unload(Background_bitmap);
2389 if (Award_bg_bitmap >= 0){
2390 bm_unload(Award_bg_bitmap);
2393 if (Rank_bitmap >= 0){
2394 bm_unload(Rank_bitmap);
2397 if (Medal_bitmap >= 0){
2398 bm_unload(Medal_bitmap);
2401 if (Badge_bitmap >= 0){
2402 bm_unload(Badge_bitmap);
2405 if (Wings_bitmap >= 0) {
2406 bm_unload(Wings_bitmap);
2409 if (Crest_bitmap >= 0) {
2410 bm_unload(Crest_bitmap);
2413 Debrief_ui_window.destroy();
2414 common_free_interface_palette(); // restore game palette
2417 if (Game_mode & GM_MULTIPLAYER){
2418 multi_debrief_close();
2426 // handle keypresses in debriefing
2427 void debrief_do_keys(int new_k)
2434 case KEY_SHIFTED | KEY_TAB:
2442 // multiplayer accept popup is a little bit different
2443 if (Game_mode & GM_MULTIPLAYER) {
2444 multi_debrief_esc_hit();
2446 // display the normal debrief popup
2448 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2449 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2450 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2451 if (choice == 1) { // accept and continue on
2453 gameseq_post_event(GS_EVENT_MAIN_MENU);
2459 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2460 // need to popup saying that mission was a failure and must be replayed
2461 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));
2466 // Return to Main Hall
2467 gameseq_post_event(GS_EVENT_END_GAME);
2477 void debrief_draw_award_text()
2479 int start_y, curr_y, i, x, sw;
2480 int fh = gr_get_font_height();
2481 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];
2483 // vertically centered within field
2484 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);
2488 for (i=0; i<Debrief_award_text_num_lines; i++) {
2489 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2490 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2491 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2492 gr_set_color_fast(&Color_white);
2493 gr_string(x, curr_y, Debrief_award_text[i]);
2495 // adjust y pos, including a little extra between the "pairs"
2497 if ((i == 1) || (i == 3)) {
2498 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2503 // clears out text array so we dont have old award text showing up on new awards.
2504 void debrief_award_text_clear() {
2507 Debrief_award_text_num_lines = 0;
2508 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2509 //Debrief_award_text[i][0] = 0;
2510 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2514 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2515 void debrief_add_award_text(char *str)
2517 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2518 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2523 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];
2526 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2528 // maybe translate for displaying
2530 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2533 Debrief_award_text_num_lines++;
2535 // if its too long, split once ONLY
2536 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2537 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2538 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2539 if (line2 != NULL) {
2540 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2542 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2546 // called once per frame to drive all the input reading and rendering
2547 void debrief_do_frame(float frametime)
2550 char *please_wait_str = XSTR("Please Wait", 1242);
2554 Assert(Debrief_inited);
2556 // first thing is to load the files
2557 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2558 // draw the background, etc
2559 GR_MAYBE_CLEAR_RES(Background_bitmap);
2560 if (Background_bitmap >= 0) {
2561 gr_set_bitmap(Background_bitmap);
2565 Debrief_ui_window.draw();
2567 if ( Debrief_multi_loading_bitmap > -1 ){
2568 gr_set_bitmap(Debrief_multi_loading_bitmap);
2569 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2572 // draw "Please Wait"
2573 gr_set_color_fast(&Color_normal);
2575 gr_get_string_size(&str_w, &str_h, please_wait_str);
2576 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2581 // make sure we run the debrief do frame
2582 if (Game_mode & GM_MULTIPLAYER) {
2583 multi_debrief_do_frame();
2588 int keypress = game_check_key();
2589 if(keypress == KEY_ESC){
2591 multi_quit_game(PROMPT_CLIENT);
2597 // if multiplayer client, and not loaded voice, then load it
2598 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2599 debrief_multi_fixup_stages();
2600 debrief_voice_load_all();
2601 Debrief_multi_voice_loaded = 1;
2604 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2605 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2606 Debrief_ui_window.set_ignore_gadgets(1);
2609 k = chatbox_process();
2610 if ( Game_mode & GM_NORMAL ) {
2611 new_k = Debrief_ui_window.process(k);
2613 new_k = Debrief_ui_window.process(k, 0);
2616 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2617 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2618 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2619 Debrief_ui_window.set_ignore_gadgets(0);
2625 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2626 Debrief_ui_window.set_ignore_gadgets(0);
2629 // don't show pilot info popup by default
2630 Debrief_should_show_popup = 0;
2632 // see if the mode has changed and handle it if so.
2633 if ( Current_mode != New_mode ) {
2634 debrief_voice_stop();
2635 Current_mode = New_mode;
2638 if (New_mode == DEBRIEF_TAB) {
2640 Debrief_cue_voice = 0;
2642 if (Debrief_first_voice_flag) {
2643 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2644 Debrief_first_voice_flag = 0;
2647 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2651 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2652 Current_stage = New_stage;
2653 debrief_text_init();
2656 debrief_voice_play();
2659 if (Game_mode & GM_MULTIPLAYER) {
2660 multi_debrief_do_frame();
2663 // Now do all the rendering for the frame
2664 GR_MAYBE_CLEAR_RES(Background_bitmap);
2665 if (Background_bitmap >= 0) {
2666 gr_set_bitmap(Background_bitmap);
2670 // draw the damn awarded stuff, G
2671 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2672 gr_set_bitmap(Award_bg_bitmap);
2673 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2674 if (Rank_bitmap >= 0) {
2675 gr_set_bitmap(Rank_bitmap);
2676 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2679 if (Medal_bitmap >= 0) {
2680 gr_set_bitmap(Medal_bitmap);
2681 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2684 if (Badge_bitmap >= 0) {
2685 gr_set_bitmap(Badge_bitmap);
2686 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2689 if (Wings_bitmap >= 0) {
2690 gr_set_bitmap(Wings_bitmap);
2691 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2694 if (Crest_bitmap >= 0) {
2695 gr_set_bitmap(Crest_bitmap);
2696 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2699 // draw medal/badge/rank labels
2700 debrief_draw_award_text();
2702 /* if (Rank_text_bitmap >= 0) {
2703 gr_set_bitmap(Rank_text_bitmap);
2704 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2708 if (Medal_text_bitmap >= 0) {
2709 gr_set_bitmap(Medal_text_bitmap);
2710 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2713 if (Badge_text_bitmap >= 0) {
2714 gr_set_bitmap(Badge_text_bitmap);
2715 gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2720 Debrief_ui_window.draw();
2721 debrief_redraw_pressed_buttons();
2722 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2723 if (Recommend_active && (Current_mode != STATS_TAB)) {
2724 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2727 // draw the title of the mission
2728 gr_set_color_fast(&Color_bright_white);
2729 strcpy(buf, The_mission.name);
2730 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2731 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2733 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2734 gr_set_color_fast(&Color_normal);
2735 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);
2738 // draw the screen-specific text
2739 switch (Current_mode) {
2741 if ( Num_debrief_stages <= 0 ) {
2742 gr_set_color_fast(&Color_white);
2743 Assert( Game_current_mission_filename != NULL );
2744 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);
2753 debrief_stats_render();
2757 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2760 gr_set_color_fast(&Color_red);
2761 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2762 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));
2765 debrief_render_stagenum();
2766 debrief_multi_list_draw();
2768 // render some extra stuff in multiplayer
2769 if (Game_mode & GM_MULTIPLAYER) {
2770 // render the chatbox last
2774 Debrief_ui_window.draw_tooltip();
2776 // render the status indicator for the voice system
2777 multi_common_voice_display_status();
2780 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2781 // want to include the mouse pointer which is drawn in the flip
2783 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2784 debrief_check_buttons();
2785 debrief_do_keys(new_k);
2788 // blit help overlay if active
2789 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2793 // dont let dude skip 3-09. hack.
2794 if(Game_mode & GM_CAMPAIGN_MODE){
2795 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2796 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2797 Debrief_skip_popup_already_shown = 1;
2802 // maybe show skip mission popup
2803 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)) {
2804 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
2805 XSTR("Advance To The Next Mission", 1474),
2806 XSTR("Don't Show Me This Again", 1475),
2807 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
2808 switch (popup_choice) {
2810 // stay on this mission, so proceed to normal debrief
2811 // in other words, do nothing.
2814 // skip this mission
2815 mission_campaign_skip_to_next();
2816 gameseq_post_event(GS_EVENT_START_GAME);
2819 // dont show this again
2820 Player->show_skip_popup = 0;
2824 Debrief_skip_popup_already_shown = 1;
2827 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
2828 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
2829 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
2830 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
2832 Debrief_should_show_popup = 0;
2836 void debrief_rebuild_player_list()
2840 debrief_multi_list_info *list;
2842 Multi_list_size = 0; // number of net players to choose from
2844 for ( i=0; i<MAX_PLAYERS; i++ ) {
2845 np = &Net_players[i];
2846 // remember not to include the standalone.
2847 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
2848 list = &Multi_list[Multi_list_size++];
2849 list->net_player_index = i;
2850 strcpy(list->callsign, np->player->callsign);
2852 // make sure to leave some room to blit the team indicator
2853 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
2858 void debrief_handle_player_drop()
2860 debrief_rebuild_player_list();
2863 void debrief_disable_accept()