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.10 2004/07/04 11:39:06 taylor
19 * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
21 * Revision 1.9 2003/08/03 16:10:29 taylor
22 * cleanup; compile warning fixes
24 * Revision 1.8 2003/06/03 04:00:40 taylor
25 * Polish language support (Janusz Dziemidowicz)
27 * Revision 1.7 2003/05/25 02:30:43 taylor
30 * Revision 1.6 2002/07/13 06:46:48 theoddone33
33 * Revision 1.5 2002/06/09 04:41:23 relnev
34 * added copyright header
36 * Revision 1.4 2002/06/02 04:26:34 relnev
39 * Revision 1.3 2002/05/26 22:06:17 relnev
40 * makefile: disable stand_gui for now.
42 * rest: staticize some globals
44 * Revision 1.2 2002/05/07 03:16:46 theoddone33
45 * The Great Newline Fix
47 * Revision 1.1.1.1 2002/05/03 03:28:10 root
51 * 57 10/29/99 10:40p Jefff
52 * hack to make german medal names display without actually changing them
54 * 56 10/13/99 3:26p Jefff
55 * fixed unnumbered XSTRs
57 * 55 10/06/99 10:28a Jefff
60 * 54 9/30/99 5:57p Jefff
61 * show upsell at end of campaign in OEM builds
63 * 53 9/15/99 3:42a Jefff
66 * 52 9/14/99 4:35a Dave
67 * Argh. Added all kinds of code to handle potential crashes in debriefing
70 * 51 9/14/99 3:26a Dave
71 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
72 * respawn-too-early problem. Made a few crash points safe.
74 * 50 9/14/99 12:51a Jefff
76 * 49 9/13/99 6:01p Jefff
77 * fixed wrong promotion voice mapping for sm1-08
79 * 48 9/13/99 11:15a Jefff
80 * clear out award text bug fixed
82 * 47 9/13/99 12:17p Andsager
83 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
86 * 46 9/07/99 9:35p Jefff
87 * fixed bug where award text was not getting cleared properly between
90 * 45 9/07/99 6:56p Jefff
91 * a few adjustments to loop detection
93 * 44 9/07/99 1:54p Jefff
94 * skip mission cleanup
96 * 43 9/06/99 9:45p Jefff
97 * skip mission support
99 * 42 9/06/99 6:38p Dave
100 * Improved CD detection code.
102 * 41 9/03/99 1:32a Dave
103 * CD checking by act. Added support to play 2 cutscenes in a row
104 * seamlessly. Fixed super low level cfile bug related to files in the
105 * root directory of a CD. Added cheat code to set campaign mission # in
108 * 40 9/02/99 3:45p Jefff
109 * forgot to remove some debug code. doh.
111 * 39 9/02/99 3:41p Jefff
112 * changed badge voice handling to be similar to promotion voice handling
114 * 38 9/01/99 4:41p Jefff
115 * fixed stoopid text color bug
117 * 37 8/31/99 11:54a Jefff
118 * minor debrief music tweak
120 * 36 8/27/99 9:57a Dave
121 * Enabled standard cheat codes. Allow player to continue in a campaing
122 * after using cheat codes.
124 * 35 8/27/99 12:04a Dave
125 * Campaign loop screen.
127 * 34 8/26/99 8:49p Jefff
128 * Updated medals screen and about everything that ever touches medals in
129 * one way or another. Sheesh.
131 * 33 8/20/99 4:20p Jefff
132 * hack for choosing the correct promotion voice
134 * 32 8/16/99 4:05p Dave
135 * Big honking checkin.
137 * 31 8/16/99 9:49a Jefff
138 * mission title length fix in multi
140 * 30 8/11/99 5:33p Jefff
141 * added 3rd debrief music track
143 * 29 8/10/99 7:28p Jefff
144 * shuffled some text around
146 * 28 8/04/99 5:36p Andsager
147 * Show upsell screens at end of demo campaign before returning to main
150 * 27 8/04/99 2:07p Jefff
151 * mission title no longer overwrites popup
153 * 26 8/02/99 5:37p Jefff
155 * 25 8/02/99 4:52p Jefff
156 * negative feedback sound when recommendations button pressed and
159 * 24 7/21/99 6:21p Jefff
160 * added hotkeys to the "you cannot accept" popup
162 * 23 6/15/99 12:04p Anoop
163 * Added a warning for running out of debrief text lines.
165 * 22 6/09/99 2:17p Dave
166 * Fixed up pleasewait bitmap rendering.
168 * 21 6/01/99 6:07p Dave
169 * New loading/pause/please wait bar.
171 * 20 5/22/99 6:05p Dave
172 * Fixed a few localization # problems.
174 * 19 5/22/99 5:35p Dave
175 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
177 * 18 3/20/99 3:47p Andsager
178 * Fix crash with no mission loop description.
180 * 17 2/23/99 2:29p Dave
181 * First run of oldschool dogfight mode.
183 * 16 2/21/99 6:01p Dave
184 * Fixed standalone WSS packets.
186 * 15 2/11/99 3:08p Dave
187 * PXO refresh button. Very preliminary squad war support.
189 * 14 1/30/99 5:08p Dave
190 * More new hi-res stuff.Support for nice D3D textures.
192 * 13 1/29/99 2:08a Dave
193 * Fixed beam weapon collisions with players. Reduced size of scoring
194 * struct for multiplayer. Disabled PXO.
196 * 12 1/14/99 5:15p Neilk
197 * changed credits, command debrief interfaces to high resolution support
199 * 11 1/13/99 2:11p Andsager
200 * change default debriefing string text
202 * 10 12/17/98 4:50p Andsager
203 * Added debrief_assemble_optional_mission_popup_text() for single and
206 * 9 12/12/98 3:17p Andsager
207 * Clean up mission eval, goal, event and mission scoring.
209 * 8 12/10/98 10:19a Andsager
210 * Fix mission loop assert
212 * 7 12/10/98 9:59a Andsager
213 * Fix some bugs with mission loops
215 * 6 12/09/98 1:56p Andsager
216 * Initial checkin of mission loop
218 * 5 11/05/98 4:18p Dave
219 * First run nebula support. Beefed up localization a bit. Removed all
220 * conditional compiles for foreign versions. Modified mission file
223 * 4 10/23/98 3:51p Dave
224 * Full support for tstrings.tbl and foreign languages. All that remains
225 * is to make it active in Fred.
227 * 3 10/13/98 9:28a Dave
228 * Started neatening up freespace.h. Many variables renamed and
229 * reorganized. Added AlphaColors.[h,cpp]
231 * 2 10/07/98 10:53a Dave
234 * 1 10/07/98 10:49a Dave
236 * 178 9/17/98 3:08p Dave
237 * PXO to non-pxo game warning popup. Player icon stuff in create and join
238 * game screens. Upped server count refresh time in PXO to 35 secs (from
241 * 177 7/07/98 1:46p Dave
242 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
245 * 175 6/09/98 10:31a Hoffoss
246 * Created index numbers for all xstr() references. Any new xstr() stuff
247 * added from here on out should be added to the end if the list. The
248 * current list count can be found in FreeSpace.cpp (search for
251 * 174 6/07/98 3:26p Lawrance
252 * Fix bug with cut-off popup text
254 * 173 6/05/98 9:54a Lawrance
257 * 172 6/01/98 11:43a John
258 * JAS & MK: Classified all strings for localization.
260 * 171 5/27/98 1:24p Allender
261 * make targeting dots work (as well as other targeting features) properly
262 * in multiplayer. Don't query for CD when entering debrief in
265 * 170 5/26/98 11:10a Lawrance
266 * Fix bug where window controls get disabled when F1 pressed twice
268 * 169 5/24/98 12:55a Mike
269 * Prevent Assert() when no debriefing text for a stage.
271 * 168 5/23/98 10:38p Lawrance
272 * Avoid doing a cfile refresh when running debug
274 * 167 5/23/98 6:49p Lawrance
275 * Fix problems with refreshing the file list when a CD is inserted
277 * 166 5/21/98 6:57p Lawrance
278 * Don't prompt for the CD if voice not found
280 * 165 5/20/98 2:24a Dave
281 * Fixed server side voice muting. Tweaked multi debrief/endgame
282 * sequencing a bit. Much friendlier for stats tossing/accepting now.
284 * 164 5/19/98 8:35p Dave
285 * Revamp PXO channel listing system. Send campaign goals/events to
286 * clients for evaluation. Made lock button pressable on all screens.
288 * 163 5/19/98 11:13a Hoffoss
289 * Fixed bug where wrong wings award was being displayed in debriefing.
291 * 162 5/19/98 12:28a Mike
294 * 161 5/18/98 8:08p Hoffoss
295 * Moved placement of 'More' text.
297 * 160 5/18/98 3:50p Dan
298 * AL: Pick correct traitor debriefing voice file
300 * 159 5/17/98 6:32p Dave
301 * Make sure clients/servers aren't kicked out of the debriefing when team
302 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
303 * xfer/pilot info popup stuff.
305 * 158 5/16/98 9:14p Allender
306 * fix scoring ckise fir training missions to actually count medals, but
307 * nothing else. Code used to Assert when wings were granted then taken
308 * away because they were actually never granted in scoring structure
310 * 157 5/15/98 5:15p Dave
311 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
312 * status for team vs. team. Put in asserts to check for invalid team vs.
315 * 156 5/15/98 4:36p Allender
316 * fixed minor bug with wings
318 * 155 5/15/98 4:12p Allender
319 * removed redbook code. Put back in ingame join timer. Major fixups for
320 * stats in multiplayer. Pass correct score, medals, etc when leaving
321 * game. Be sure clients display medals, badges, etc.
323 * 154 5/15/98 2:25p Jasen
324 * temporarily disable granting of promotion and badges for clients
326 * 153 5/15/98 10:57a Allender
327 * fixed client side debriefings
329 * 152 5/15/98 10:36a Dave
330 * Removed 2 bogus bitmap drawing Int3()'s
332 * 151 5/14/98 2:44p Hoffoss
333 * Added wings awarding to debrief screen.
335 * 150 5/13/98 9:11p Lawrance
336 * Make 'replay mission' popup warn users about the loss of mission stats.
341 #include "missiondebrief.h"
342 #include "missionbriefcommon.h"
343 #include "missionscreencommon.h"
344 #include "missiongoals.h"
345 #include "missionpause.h"
346 #include "freespace.h"
347 #include "gamesequence.h"
355 #include "audiostr.h"
358 #include "contexthelp.h"
364 #include "multimsgs.h"
365 #include "multiutil.h"
366 #include "multiteamselect.h"
368 #include "eventmusic.h"
372 #include "multi_pinfo.h"
373 #include "contexthelp.h"
374 #include "multi_kick.h"
375 #include "multi_campaign.h"
376 #include "alphacolors.h"
377 #include "localize.h"
378 #include "multi_endgame.h"
381 #define MAX_TOTAL_DEBRIEF_LINES 200
383 #define TEXT_TYPE_NORMAL 1
384 #define TEXT_TYPE_RECOMMENDATION 2
386 #define DEBRIEF_NUM_STATS_PAGES 4
387 #define DEBRIEF_MISSION_STATS 0
388 #define DEBRIEF_MISSION_KILLS 1
389 #define DEBRIEF_ALLTIME_STATS 2
390 #define DEBRIEF_ALLTIME_KILLS 3
392 // 3rd coord is max width in pixels
393 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
406 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
419 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
424 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
437 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
450 #define MULTI_LIST_TEAM_OFFSET 16
452 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
457 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
466 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
479 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
493 int Debrief_rank_coords[2] = {
497 int Debrief_badge_coords[2] = {
503 // 0=x, 1=y, 2=width of the field
504 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
513 // 0=x, 1=y, 2=height of the field
514 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
523 // the medal text in FS1 is a bitmap
524 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][2] = {
533 int Debrief_rank_text_coords[GR_NUM_RESOLUTIONS][2] = {
542 int Debrief_badge_text_coords[GR_NUM_RESOLUTIONS][2] = {
553 // 1 = without medal (text will use medal space)
554 #define DB_WITH_MEDAL 0
555 #define DB_WITHOUT_MEDAL 1
556 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
565 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
566 "DebriefSingle", // GR_640
567 "2_DebriefSingle" // GR_1024
569 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
570 "DebriefMulti", // GR_640
571 "2_DebriefMulti" // GR_1024
573 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
574 "Debrief-m", // GR_640
575 "2_Debrief-m" // GR_1024
578 #define NUM_BUTTONS 18
581 #define DEBRIEF_TAB 0
583 #define TEXT_SCROLL_UP 2
584 #define TEXT_SCROLL_DOWN 3
585 #define REPLAY_MISSION 4
586 #define RECOMMENDATIONS 5
587 #define FIRST_STAGE 6
591 #define MULTI_PINFO_POPUP 10
592 #define MULTI_KICK 11
593 #define MEDALS_BUTTON 12
594 #define PLAYER_SCROLL_UP 13
595 #define PLAYER_SCROLL_DOWN 14
596 #define HELP_BUTTON 15
597 #define OPTIONS_BUTTON 16
598 #define ACCEPT_BUTTON 17
603 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
604 "PleaseWait", // GR_640
605 "2_PleaseWait" // GR_1024
611 char text[NAME_LENGTH+1]; // name of ship type with a colon
612 int num; // how many ships of this type player has killed
613 } debrief_stats_kill_info;
616 int net_player_index; // index into Net_players[] array
617 int rank_bitmap; // bitmap id for rank
618 char callsign[CALLSIGN_LEN];
619 } debrief_multi_list_info;
621 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
624 ui_button_info("DB_00", 0, 2, -1, -1, 0), // debriefing
625 ui_button_info("DB_01", 0, 20, -1, -1, 1), // statistics
626 ui_button_info("DB_02", 0, 195, -1, -1, 2), // scroll stats up
627 ui_button_info("DB_03", 0, 232, -1, -1, 3), // scroll stats down
628 ui_button_info("DB_04", 24, 424, -1, -1, 4), // replay mission
629 ui_button_info("DB_05", 30, 451, -1, -1, 5), // recommendations
630 ui_button_info("DB_06", 211, 445, -1, -1, 6), // first page
631 ui_button_info("DB_07", 234, 445, -1, -1, 7), // prev page
632 ui_button_info("DB_08", 259, 445, -1, -1, 8), // next page
633 ui_button_info("DB_09", 283, 445, -1, -1, 9), // last page
634 ui_button_info("DB_21", 441, 384, -1, -1, 21), // pilot info
635 ui_button_info("DB_25", 511, 384, -1, -1, 25), // kick
636 ui_button_info("DB_15", 604, 224, -1, -1, 15), // medals
637 ui_button_info("DB_16", 615, 329, -1, -1, 16), // scroll pilots up
638 ui_button_info("DB_17", 615, 371, -1, -1, 17), // scroll pilots down
639 ui_button_info("DB_10", 469, 428, -1, -1, 10), // help
640 ui_button_info("DB_11", 447, 452, -1, -1, 11), // options
641 ui_button_info("DB_12", 562, 410, -1, -1, 12), // accept
643 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
644 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
645 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
646 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
647 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
648 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
649 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
650 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
651 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
652 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
653 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
654 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
655 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
656 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
657 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
658 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
659 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
660 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
664 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
665 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
666 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
667 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
668 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
669 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
670 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
671 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
672 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
673 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
674 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
675 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
676 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
677 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
678 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
679 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
680 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
681 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
687 #define NUM_DEBRIEF_TEXT 0
689 #define NUM_DEBRIEF_TEXT 10
691 #define MP_TEXT_INDEX_1 4
692 #define MP_TEXT_INDEX_2 5
693 #define MP_TEXT_INDEX_3 6
694 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
696 // not needed for FS1
698 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
699 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
700 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
701 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
702 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
703 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
704 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
705 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
706 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
707 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
711 // not needed for FS1
713 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
714 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
715 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
716 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
717 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
718 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
719 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
720 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
721 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
722 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
728 char Debrief_current_callsign[CALLSIGN_LEN+10];
729 player *Debrief_player;
731 static UI_WINDOW Debrief_ui_window;
732 static UI_BUTTON List_region;
733 static int Background_bitmap; // bitmap for the background of the debriefing
734 static int Award_bg_bitmap;
735 static int Debrief_multi_loading_bitmap;
736 static int Rank_bitmap;
737 static int Medal_bitmap;
738 static int Badge_bitmap;
739 static int Wings_bitmap;
740 static int Crest_bitmap;
742 static int Rank_text_bitmap;
743 static int Medal_text_bitmap;
744 static int Badge_text_bitmap;
747 static int Debrief_accepted;
748 static int Turned_traitor;
749 static int Must_replay_mission;
751 static int Current_mode;
753 static int Recommend_active;
754 static int Award_active;
755 static int Text_offset;
756 static int Num_text_lines = 0;
757 static int Num_debrief_lines = 0;
758 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
759 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
761 static int Debrief_inited = 0;
762 static int New_stage;
763 static int Current_stage;
764 static int Num_stages;
765 static int Num_debrief_stages;
766 static int Stage_voice;
768 static int Multi_list_size;
769 static int Multi_list_offset;
771 int Debrief_multi_stages_loaded = 0;
772 int Debrief_multi_voice_loaded = 0;
774 // static int Debrief_voice_ask_for_cd;
776 // voice id's for debriefing text
777 static int Debrief_voices[MAX_DEBRIEF_STAGES];
779 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
780 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
781 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
783 // pointer used for getting to debriefing information
784 debriefing Traitor_debriefing; // used when player is a traitor
786 // pointers to the active stages for this debriefing
787 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
788 static debrief_stage Promotion_stage, Badge_stage;
789 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
790 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
791 int Multi_list_select;
793 // flag indicating if we should display info for the given player (in multiplayer)
794 int Debrief_should_show_popup = 1;
796 // already shown skip mission popup?
797 static int Debrief_skip_popup_already_shown = 0;
799 void debrief_text_init();
800 void debrief_accept(int ok_to_post_start_game_event = 1);
801 void debrief_kick_selected_player();
804 // promotion voice selection stuff
805 #define NUM_VOLITION_CAMPAIGNS 1
807 char campaign_name[32];
809 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
811 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
812 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
816 // data for which voice goes w/ which mission
817 typedef struct voice_map {
818 char mission_file[32];
822 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
823 { // FreeSpace2 campaign
855 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
857 { "loop1-1.fs2", 4 },
858 { "loop1-2.fs2", 4 },
859 { "loop1-3.fs2", 5 },
860 { "loop2-1.fs2", 4 },
865 #define DB_AWARD_WINGS 0
866 #define DB_AWARD_MEDAL 1
868 #define DB_AWARD_RANK 2
869 #define DB_AWARD_BADGE 3
870 #define DB_AWARD_BG 4
871 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][5] = {
888 #define DB_AWARD_SOC 2
889 #define DB_AWARD_RANK 3
890 #define DB_AWARD_BADGE 4
891 #define DB_AWARD_BG 5
892 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
912 #define AWARD_TEXT_MAX_LINES 5
913 #define AWARD_TEXT_MAX_LINE_LENGTH 128
914 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
915 int Debrief_award_text_num_lines = 0;
919 // prototypes, you know you love 'em
920 void debrief_add_award_text(char *str);
921 void debrief_award_text_clear();
926 char *debrief_tooltip_handler(char *str)
928 if (!stricmp(str, NOX("@.Medal"))) {
930 return XSTR( "Medal", 435);
933 } else if (!stricmp(str, NOX("@.Rank"))) {
935 return XSTR( "Rank", 436);
938 } else if (!stricmp(str, NOX("@.Badge"))) {
940 return XSTR( "Badge", 437);
943 } else if (!stricmp(str, NOX("@Medal"))) {
944 if (Medal_bitmap >= 0){
945 return Medals[Player->stats.m_medal_earned].name;
948 } else if (!stricmp(str, NOX("@Rank"))) {
949 if (Rank_bitmap >= 0){
950 return Ranks[Promoted].name;
953 } else if (!stricmp(str, NOX("@Badge"))) {
954 if (Badge_bitmap >= 0){
955 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
962 // initialize the array of handles to the different voice streams
963 void debrief_voice_init()
967 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
968 Debrief_voices[i] = -1;
972 void debrief_load_voice_file(int voice_num, char *name)
974 int load_attempts = 0;
977 if ( load_attempts++ > 5 ) {
981 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
982 if ( Debrief_voices[voice_num] >= 0 ) {
986 // Don't bother to ask for the CD in multiplayer
987 if ( Game_mode & GM_MULTIPLAYER ) {
991 // couldn't load voice, ask user to insert CD (if necessary)
993 // if ( Debrief_voice_ask_for_cd ) {
994 // if ( game_do_cd_check() == 0 ) {
995 // Debrief_voice_ask_for_cd = 0;
1002 // open and pre-load the stream buffers for the different voice streams
1003 void debrief_voice_load_all()
1007 // Debrief_voice_ask_for_cd = 1;
1009 for ( i=0; i<Num_debrief_stages; i++ ) {
1010 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
1013 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
1014 debrief_load_voice_file(i, Debrief_stages[i]->voice);
1015 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
1020 // close all the briefing voice streams
1021 void debrief_voice_unload_all()
1025 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
1026 if ( Debrief_voices[i] != -1 ) {
1027 audiostream_close_file(Debrief_voices[i], 0);
1028 Debrief_voices[i] = -1;
1033 // start playback of the voice for a particular briefing stage
1034 void debrief_voice_play()
1036 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
1040 // no more stages? We are done then.
1041 if (Stage_voice >= Num_debrief_stages){
1045 // if in delayed start, see if delay has elapsed and start voice if so
1046 if (Debrief_cue_voice) {
1047 if (!timestamp_elapsed(Debrief_cue_voice)){
1051 Stage_voice++; // move up to next voice
1052 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
1053 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
1054 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
1060 // see if voice is still playing. If so, do nothing yet.
1061 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
1065 // set voice to play in a little while from now.
1066 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
1069 // stop playback of the voice for a particular briefing stage
1070 void debrief_voice_stop()
1072 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
1075 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
1079 // function to deal with inserting possible promition and badge stages into the debriefing
1081 void debrief_multi_fixup_stages()
1085 // possibly insert the badge stage first, them the promotion stage since they are
1086 // inserted at the front of the debrief stages.
1087 if ( Badge_bitmap >= 0 ) {
1088 // move all stages forward one. Don't
1089 for ( i = Num_debrief_stages; i > 0; i-- ) {
1090 Debrief_stages[i] = Debrief_stages[i-1];
1092 Debrief_stages[0] = &Badge_stage;
1093 Num_debrief_stages++;
1096 if ( Promoted >= 0) {
1097 // move all stages forward one
1098 for ( i = Num_debrief_stages; i > 0; i-- ) {
1099 Debrief_stages[i] = Debrief_stages[i-1];
1101 Debrief_stages[0] = &Promotion_stage;
1102 Num_debrief_stages++;
1107 // function called from multiplayer clients to set up the debriefing information for them
1108 // (sent from the server).
1109 void debrief_set_multi_clients( int stage_count, int active_stages[] )
1113 // set up the right briefing for this guy
1114 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
1115 Debriefing = &Debriefings[Net_player->p_info.team];
1117 Debriefing = &Debriefings[0];
1120 // see if this client was promoted -- if so, then add the first stage.
1121 Num_debrief_stages = 0;
1123 // set the pointers to the debriefings for this client
1124 for (i = 0; i < stage_count; i++) {
1125 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
1128 Debrief_multi_stages_loaded = 1;
1131 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
1132 // information to all clients after leaving this screen.
1133 void debrief_multi_server_stuff()
1135 debriefing *debriefp;
1137 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1138 int i, j, num_stages, stage_count[MAX_TEAMS];
1140 memset( stage_active, 0, sizeof(stage_active) );
1142 for (i=0; i<Num_teams; i++) {
1143 debriefp = &Debriefings[i];
1145 stages[i] = stage_active[i];
1146 for (j=0; j<debriefp->num_stages; j++) {
1147 if ( eval_sexp(debriefp->stages[j].formula) ) {
1148 stage_active[i][num_stages] = j;
1153 stage_count[i] = num_stages;
1156 // if we're in campaign mode, evaluate campaign stuff
1157 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1158 multi_campaign_eval_debrief();
1161 // send the information to all clients.
1162 send_debrief_info( stage_count, stages );
1166 // --------------------------------------------------------------------------------------
1167 // debrief_set_stages_and_multi_stuff()
1169 // Set up the active stages for this debriefing
1171 // returns: number of active debriefing stages
1173 int debrief_set_stages_and_multi_stuff()
1176 debriefing *debriefp;
1178 if ( MULTIPLAYER_CLIENT ) {
1182 Num_debrief_stages = 0;
1184 if ( Game_mode & GM_MULTIPLAYER ) {
1185 debrief_multi_server_stuff();
1188 // check to see if player is a traitor (looking at his team). If so, use the special
1189 // traitor debriefing. Only done in single player
1190 debriefp = Debriefing;
1191 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1192 if (Player_ship->team == TEAM_TRAITOR)
1193 debriefp = &Traitor_debriefing;
1196 Num_debrief_stages = 0;
1197 if (Promoted >= 0) {
1198 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1201 if (Badge_bitmap >= 0) {
1202 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1205 for (i=0; i<debriefp->num_stages; i++) {
1206 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1207 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1211 return Num_debrief_stages;
1214 // init the buttons that are specific to the debriefing screen
1215 void debrief_buttons_init()
1220 for ( i=0; i<NUM_BUTTONS; i++ ) {
1221 b = &Buttons[gr_screen.res][i];
1222 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1223 // set up callback for when a mouse first goes over a button
1224 b->button.set_highlight_action( common_play_highlight_sound );
1225 b->button.set_bmaps(b->filename);
1226 b->button.link_hotspot(b->hotspot);
1230 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1231 // multiplayer specific text
1232 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1233 // only add if in multiplayer mode
1234 if(Game_mode & GM_MULTIPLAYER){
1235 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1240 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1244 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1245 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1246 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1247 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1248 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1249 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1250 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1251 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1253 // if in multiplayer, disable the button for all players except the host
1254 // also disable for squad war matches
1255 if(Game_mode & GM_MULTIPLAYER){
1256 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1257 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1262 // --------------------------------------------------------------------------------------
1263 // debrief_ui_init()
1265 void debrief_ui_init()
1267 // init ship selection masks and buttons
1268 common_set_interface_palette("DebriefPalette"); // set the interface palette
1269 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1270 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1271 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1272 debrief_buttons_init();
1274 // load in help overlay bitmap
1275 help_overlay_load(DEBRIEFING_OVERLAY);
1276 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1278 if ( Game_mode & GM_MULTIPLAYER ) {
1279 // close down any old instances of the chatbox
1282 // create the new one
1284 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1285 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);
1288 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1291 if ( Background_bitmap < 0 ) {
1292 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1295 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1296 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1299 // sets Promotion_stage.voice
1300 // defaults to number 9 (Petrarch) for non-volition missions
1301 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1302 void debrief_choose_promotion_voice()
1306 if(Campaign.current_mission < 0){
1307 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1311 // search thru all official campaigns for our current campaign
1312 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1313 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1314 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1315 // now search thru the mission filenames,
1316 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1317 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1318 // found it! set the persona and bail
1319 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1327 // default to petrarch
1328 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1331 // sets Promotion_stage.voice
1332 // defaults to number 9 (Petrarch) for non-volition missions
1333 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1334 void debrief_choose_badge_voice()
1340 if(Campaign.current_mission < 0){
1342 // default to petrarch
1343 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1345 // default to FS1 guy
1346 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1350 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1352 if ( Player->on_bastion ) {
1353 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base2);
1356 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1360 // search thru all official campaigns for our current campaign
1361 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1362 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1363 // now search thru the mission filenames,
1364 for (j=0; j<Campaign.num_missions; j++) {
1365 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1366 // found it! set the persona and bail
1367 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1377 // default to petrarch
1378 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1380 // default to FS1 guy
1381 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1386 void debrief_award_init()
1398 // be sure there are no old award texts floating around
1400 debrief_award_text_clear();
1403 // handle medal earned
1404 if (Player->stats.m_medal_earned != -1) {
1405 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1407 if ( Player->stats.medals[13] > 1 ) {
1412 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1413 Wings_bitmap = bm_load(buf);
1415 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1416 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1419 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1420 Medal_bitmap = bm_load(buf);
1424 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1428 // handle promotions
1429 if ( Player->stats.m_promotion_earned != -1 ) {
1430 Promoted = Player->stats.m_promotion_earned;
1431 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1432 Rank_bitmap = bm_load(buf);
1434 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1435 Promotion_stage.new_recommendation_text = NULL;
1437 // choose appropriate promotion voice for this mission
1438 debrief_choose_promotion_voice();
1441 debrief_add_award_text(Ranks[Promoted].name);
1445 // handle badge earned
1446 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1447 if ( Player->stats.m_badge_earned != -1 ) {
1448 i = Player->stats.m_badge_earned;
1449 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1450 Badge_bitmap = bm_load(buf);
1452 Badge_stage.new_text = Badge_info[i].promotion_text;
1453 Badge_stage.new_recommendation_text = NULL;
1455 // choose appropriate voice
1456 debrief_choose_badge_voice();
1459 debrief_add_award_text(Medals[Badge_index[i]].name);
1463 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1470 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1471 // mission a traitor. The same debriefing always gets played
1472 void debrief_traitor_init()
1474 static int inited = 0;
1477 debriefing *debrief;
1478 debrief_stage *stagep;
1482 if ((rval = setjmp(parse_abort)) != 0) {
1483 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1486 read_file_text("traitor.tbl");
1490 // open localization
1493 // simplied form of the debriefing stuff.
1494 debrief = &Traitor_debriefing;
1495 required_string("#Debriefing_info");
1497 required_string("$Num stages:");
1498 stuff_int(&debrief->num_stages);
1499 Assert(debrief->num_stages == 1);
1502 stagep = &debrief->stages[stage_num++];
1503 required_string("$Formula:");
1504 stagep->formula = get_sexp_main();
1505 required_string("$multi text");
1506 if ( Fred_running ) {
1507 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1509 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1511 required_string("$Voice:");
1512 char traitor_voice_file[NAME_LENGTH];
1513 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1515 // DKA 9/13/99 Only 1 traitor msg for FS2
1517 if ( Player->on_bastion ) {
1518 strcpy(stagep->voice, NOX("3_"));
1520 strcpy(stagep->voice, NOX("1_"));
1524 strcat(stagep->voice, traitor_voice_file);
1526 required_string("$Recommendation text:");
1527 if ( Fred_running ) {
1528 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1530 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1534 // close localization
1538 // disable the accept button if in single player and I am a traitor
1539 Debrief_accepted = 0;
1540 Turned_traitor = Must_replay_mission = 0;
1541 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1542 if (Player_ship->team == TEAM_TRAITOR){
1546 if (Campaign.next_mission == Campaign.current_mission){
1547 Must_replay_mission = 1;
1551 if (Turned_traitor || Must_replay_mission) {
1552 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1554 // kill off any stats
1555 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1556 scoring_level_init( &Player->stats );
1560 // initialization for listing of players in game
1561 void debrief_multi_list_init()
1563 Multi_list_size = 0; // number of net players to choose from
1564 Multi_list_offset = 0;
1566 Multi_list_select = -1;
1568 if ( !(Game_mode & GM_MULTIPLAYER) )
1571 debrief_rebuild_player_list();
1573 // switch stats display to this newly selected player
1574 set_player_stats(Multi_list[0].net_player_index);
1575 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1576 Debrief_player = Player;
1579 void debrief_multi_list_scroll_up()
1581 // if we're at the beginning of the list, don't do anything
1582 if(Multi_list_offset == 0){
1583 gamesnd_play_iface(SND_GENERAL_FAIL);
1587 // otherwise scroll up
1588 Multi_list_offset--;
1589 gamesnd_play_iface(SND_USER_SELECT);
1592 void debrief_multi_list_scroll_down()
1594 // if we can scroll down no further
1595 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1596 gamesnd_play_iface(SND_GENERAL_FAIL);
1599 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1600 gamesnd_play_iface(SND_GENERAL_FAIL);
1604 // otherwise scroll down
1605 Multi_list_offset++;
1606 gamesnd_play_iface(SND_USER_SELECT);
1609 // draw the connected net players
1610 void debrief_multi_list_draw()
1612 int y, z, font_height,idx;
1613 char str[CALLSIGN_LEN+5];
1616 font_height = gr_get_font_height();
1618 // if we currently have no item picked, pick a reasonable one
1619 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1620 // select the entry which corresponds to the local player
1621 Multi_list_select = 0;
1622 for(idx=0;idx<Multi_list_size;idx++){
1623 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1624 Multi_list_select = idx;
1626 // switch stats display to this newly selected player
1627 set_player_stats(Multi_list[idx].net_player_index);
1628 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1629 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1635 // draw the list itself
1637 z = Multi_list_offset;
1638 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1639 np = &Net_players[Multi_list[z].net_player_index];
1641 if (z >= Multi_list_size){
1644 // set the proper text color for the highlight
1645 if(np->flags & NETINFO_FLAG_GAME_HOST){
1646 if(Multi_list_select == z){
1647 gr_set_color_fast(&Color_text_active_hi);
1649 gr_set_color_fast(&Color_bright);
1652 if(Multi_list_select == z){
1653 gr_set_color_fast(&Color_text_active);
1655 gr_set_color_fast(&Color_text_normal);
1659 // blit the proper indicator - skipping observers
1660 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1661 if(Netgame.type_flags & NG_TYPE_TEAM){
1663 if(np->p_info.team == 0){
1664 // draw his "selected" icon
1665 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1666 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1667 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1669 // draw his "normal" icon
1670 else if(Multi_common_icons[MICON_TEAM0] != -1){
1671 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1672 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1674 } else if(np->p_info.team == 1){
1675 // draw his "selected" icon
1676 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1677 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1678 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1680 // draw his "normal" icon
1681 else if(Multi_common_icons[MICON_TEAM1] != -1){
1682 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1683 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1687 // draw the team 0 selected icon
1688 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1689 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1690 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1695 strcpy(str,Multi_list[z].callsign);
1696 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)){
1697 strcat(str,XSTR( "(O)", 438));
1701 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1708 void debrief_kick_selected_player()
1710 if(Multi_list_select >= 0){
1711 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1712 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1716 // get optional mission popup text
1717 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1719 Assert(buffer != NULL);
1722 if (mission_loop_desc == NULL) {
1723 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1724 mprintf(("No mission loop description avail"));
1726 strcpy(buffer, mission_loop_desc);
1729 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1732 // what to do when the accept button is hit
1733 void debrief_accept(int ok_to_post_start_game_event)
1737 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1741 if (Game_mode & GM_MULTIPLAYER) {
1745 if (Player_ship->team == TEAM_TRAITOR){
1746 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1747 }/* else if (Cheats_enabled) {
1748 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1750 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1753 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1755 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1756 } else if ( z == 1 ) {
1757 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1763 Debrief_accepted = 1;
1764 // save mission stats
1765 if (Game_mode & GM_MULTIPLAYER) {
1766 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1767 // as well as doing stats transfers, etc.
1768 multi_debrief_accept_hit();
1772 int play_commit_sound = 1;
1773 // only write the player's stats if he's accepted
1775 // if we are just playing a single mission, then don't do many of the things
1776 // that need to be done. Nothing much should happen when just playing a single
1777 // mission that isn't in a campaign.
1778 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1780 // check for possible mission loop
1781 // check for (1) mission loop available, (2) dont have to repeat last mission
1782 if(!(Game_mode & GM_MULTIPLAYER)){
1783 int cur = Campaign.current_mission;
1784 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1785 if (Campaign.missions[cur].has_mission_loop) {
1786 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1789 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1792 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1794 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1796 Campaign.loop_enabled = 1;
1797 Campaign.next_mission = Campaign.loop_mission;
1806 if(ok_to_post_start_game_event){
1807 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1809 play_commit_sound = 0;
1812 // continue as normal
1815 mission_campaign_mission_over();
1817 // check to see if we are out of the loop now
1818 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1819 Campaign.loop_enabled = 0;
1822 // check if campaign is over
1823 if ( Campaign.next_mission == -1 ) {
1824 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
1825 gameseq_post_event(GS_EVENT_END_DEMO);
1827 gameseq_post_event(GS_EVENT_MAIN_MENU);
1830 if ( ok_to_post_start_game_event ) {
1832 if(game_do_cd_mission_check(Game_current_mission_filename)){
1833 gameseq_post_event(GS_EVENT_START_GAME);
1835 gameseq_post_event(GS_EVENT_MAIN_MENU);
1838 play_commit_sound = 0;
1843 gameseq_post_event(GS_EVENT_MAIN_MENU);
1846 if ( play_commit_sound ) {
1847 gamesnd_play_iface(SND_COMMIT_PRESSED);
1854 void debrief_next_tab()
1856 New_mode = Current_mode + 1;
1857 if (New_mode >= NUM_TABS)
1861 void debrief_prev_tab()
1863 New_mode = Current_mode - 1;
1865 New_mode = NUM_TABS - 1;
1868 // --------------------------------------------------------------------------------------
1869 // debrief_next_stage()
1871 void debrief_next_stage()
1873 if (Current_stage < Num_stages - 1) {
1874 New_stage = Current_stage + 1;
1875 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1878 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1881 // --------------------------------------------------------------------------------------
1882 // debrief_prev_stage()
1884 void debrief_prev_stage()
1886 if (Current_stage) {
1887 New_stage = Current_stage - 1;
1888 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1891 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1894 // --------------------------------------------------------------------------------------
1895 // debrief_first_stage()
1896 void debrief_first_stage()
1898 if (Current_stage) {
1900 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1903 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1906 // --------------------------------------------------------------------------------------
1907 // debrief_last_stage()
1908 void debrief_last_stage()
1910 if (Current_stage != Num_stages - 1) {
1911 New_stage = Num_stages - 1;
1912 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1915 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1918 // draw what stage number the debriefing is on
1919 void debrief_render_stagenum()
1927 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1928 gr_get_string_size(&w, NULL, buf);
1929 gr_set_color_fast(&Color_bright_blue);
1930 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1931 gr_set_color_fast(&Color_white);
1934 // render the mission time at the specified y location
1935 void debrief_render_mission_time(int y_loc)
1939 game_format_time(Missiontime, time_str);
1940 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1941 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1944 // render out the debriefing text to the scroll window
1945 void debrief_render()
1947 int y, z, font_height;
1949 if ( Num_stages <= 0 )
1952 font_height = gr_get_font_height();
1954 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]);
1957 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1958 if (z >= Num_text_lines)
1961 if (Text_type[z] == TEXT_TYPE_NORMAL)
1962 gr_set_color_fast(&Color_white);
1964 gr_set_color_fast(&Color_bright_red);
1967 gr_string(0, y, Text[z]);
1976 // render out the stats info to the scroll window
1978 void debrief_stats_render()
1980 int i, y, font_height;
1982 gr_set_color_fast(&Color_blue);
1983 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]);
1984 gr_string(0, 0, Debrief_current_callsign);
1985 font_height = gr_get_font_height();
1988 switch ( Current_stage ) {
1989 case DEBRIEF_MISSION_STATS:
1990 i = Current_stage - 1;
1994 gr_set_color_fast(&Color_white);
1996 // display mission completion time
1997 debrief_render_mission_time(y);
2000 show_stats_label(i, 0, y, font_height);
2001 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2003 case DEBRIEF_ALLTIME_STATS:
2004 i = Current_stage - 1;
2008 gr_set_color_fast(&Color_white);
2009 show_stats_label(i, 0, y, font_height);
2010 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2013 case DEBRIEF_ALLTIME_KILLS:
2014 case DEBRIEF_MISSION_KILLS:
2015 gr_set_color_fast(&Color_white);
2017 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
2018 if (i >= Num_text_lines)
2022 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2023 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
2025 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
2028 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
2029 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
2036 if (Num_text_lines == 2) {
2037 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2038 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
2040 gr_printf(0, y, XSTR( "(No ship kills)", 450));
2053 // do action for when the replay button is pressed
2054 void debrief_replay_pressed()
2056 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2058 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));
2065 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
2066 gamesnd_play_iface(SND_COMMIT_PRESSED);
2069 // -------------------------------------------------------------------
2070 // debrief_redraw_pressed_buttons()
2072 // Redraw any debriefing buttons that are pressed down. This function is needed
2073 // since we sometimes need to draw pressed buttons last to ensure the entire
2074 // button gets drawn (and not overlapped by other buttons)
2076 void debrief_redraw_pressed_buttons()
2081 for ( i=0; i<NUM_BUTTONS; i++ ) {
2082 b = &Buttons[gr_screen.res][i].button;
2083 // don't draw the recommendations button if we're in stats mode
2084 if ( b->button_down() ) {
2090 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
2092 void debrief_button_pressed(int num)
2096 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
2097 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
2098 if (num != Current_mode){
2099 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2104 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
2105 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
2106 if (num != Current_mode){
2107 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2112 case TEXT_SCROLL_UP:
2115 gamesnd_play_iface(SND_SCROLL);
2117 gamesnd_play_iface(SND_GENERAL_FAIL);
2121 case TEXT_SCROLL_DOWN:
2122 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2124 gamesnd_play_iface(SND_SCROLL);
2126 gamesnd_play_iface(SND_GENERAL_FAIL);
2130 case REPLAY_MISSION:
2131 if(Game_mode & GM_MULTIPLAYER){
2132 multi_debrief_replay_hit();
2134 debrief_replay_pressed();
2138 case RECOMMENDATIONS:
2139 gamesnd_play_iface(SND_USER_SELECT);
2140 Recommend_active = !Recommend_active;
2141 debrief_text_init();
2145 debrief_first_stage();
2149 debrief_prev_stage();
2153 debrief_next_stage();
2157 debrief_last_stage();
2161 gamesnd_play_iface(SND_HELP_PRESSED);
2162 launch_context_help();
2165 case OPTIONS_BUTTON:
2166 gamesnd_play_iface(SND_SWITCH_SCREENS);
2167 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2175 gamesnd_play_iface(SND_SWITCH_SCREENS);
2176 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2179 case PLAYER_SCROLL_UP:
2180 debrief_multi_list_scroll_up();
2183 case PLAYER_SCROLL_DOWN:
2184 debrief_multi_list_scroll_down();
2187 case MULTI_PINFO_POPUP:
2188 Debrief_should_show_popup = 1;
2192 debrief_kick_selected_player();
2197 void debrief_setup_ship_kill_stats(int stage_num)
2201 debrief_stats_kill_info *kill_info;
2203 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2204 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2207 Assert(Debrief_player != NULL);
2209 // kill_ar points to an array of MAX_SHIP_TYPE ints
2210 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2211 kill_arr = Debrief_player->stats.m_okKills;
2213 kill_arr = Debrief_player->stats.kills;
2217 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2219 // code used to add in mission kills, but the new system assumes that the player will accept, so
2220 // all time stats already have mission stats added in.
2221 if ( kill_arr[i] <= 0 ){
2226 kill_info = &Debrief_stats_kills[Num_text_lines++];
2228 kill_info->num = kill_arr[i];
2230 strcpy(kill_info->text, Ship_info[i].name);
2231 strcat(kill_info->text, NOX(":"));
2234 Num_text_lines += 2;
2237 // Iterate through the debriefing buttons, checking if they are pressed
2238 void debrief_check_buttons()
2242 for ( i=0; i<NUM_BUTTONS; i++ ) {
2243 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2244 debrief_button_pressed(i);
2248 if ( !(Game_mode & GM_MULTIPLAYER) )
2251 if (List_region.pressed()) {
2252 List_region.get_mouse_pos(NULL, &y);
2253 z = Multi_list_offset + y / gr_get_font_height();
2254 if ((z >= 0) && (z < Multi_list_size)) {
2255 // switch stats display to this newly selected player
2256 set_player_stats(Multi_list[z].net_player_index);
2257 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2258 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2259 Multi_list_select = z;
2260 debrief_setup_ship_kill_stats(Current_stage);
2261 gamesnd_play_iface(SND_USER_SELECT);
2265 // if the player was double clicked on - we should popup a player info popup
2267 if (List_region.double_clicked()) {
2268 Debrief_should_show_popup = 1;
2273 void debrief_text_stage_init(char *src, int type)
2275 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2276 char line[MAX_DEBRIEF_LINE_LEN];
2277 char *p_str[MAX_DEBRIEF_LINES];
2279 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2280 Assert(n_lines >= 0);
2282 // if you hit this, you proba
2283 if(n_lines >= MAX_DEBRIEF_LINES){
2284 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2287 for ( i=0; i<n_lines; i++ ) {
2288 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2289 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2290 strncpy(line, p_str[i], n_chars[i]);
2291 line[n_chars[i]] = 0;
2292 drop_white_space(line);
2293 Text_type[Num_text_lines] = type;
2294 Text[Num_text_lines++] = strdup(line);
2300 void debrief_free_text()
2304 for (i=0; i<Num_debrief_lines; i++)
2308 Num_debrief_lines = 0;
2311 // setup the debriefing text lines for rendering
2312 void debrief_text_init()
2317 // release old text lines first
2318 debrief_free_text();
2319 Num_text_lines = Text_offset = 0;
2321 if (Current_mode == DEBRIEF_TAB) {
2322 for (i=0; i<Num_debrief_stages; i++) {
2324 Text[Num_text_lines++] = NULL; // add a blank line between stages
2326 src = Debrief_stages[i]->new_text;
2328 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2330 if (Recommend_active) {
2331 src = Debrief_stages[i]->new_recommendation_text;
2332 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2333 src = XSTR( "We have no recommendations for you.", 1054);
2336 Text[Num_text_lines++] = NULL;
2337 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2343 Num_debrief_lines = Num_text_lines;
2347 // not in debriefing mode, must be in stats mode
2349 debrief_setup_ship_kill_stats(Current_stage);
2353 // --------------------------------------------------------------------------------------
2357 Assert(!Debrief_inited);
2358 // Campaign.loop_enabled = 0;
2359 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2361 // set up the right briefing for this guy
2362 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2363 Debriefing = &Debriefings[Net_player->p_info.team];
2365 Debriefing = &Debriefings[0];
2368 // no longer is mission
2369 Game_mode &= ~(GM_IN_MISSION);
2373 New_mode = DEBRIEF_TAB;
2374 Recommend_active = Award_active = 0;
2379 Debrief_cue_voice = 0;
2380 Num_text_lines = Num_debrief_lines = 0;
2381 Debrief_first_voice_flag = 1;
2383 Debrief_multi_voice_loaded = 0;
2386 Medal_text_bitmap = bm_load(NOX("DebriefText01"));
2387 Rank_text_bitmap = bm_load(NOX("DebriefText02"));
2388 Badge_text_bitmap = bm_load(NOX("DebriefText03"));
2391 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2392 // MUST store goals and events first - may be used to evaluate next mission
2393 // store goals and events
2394 mission_campaign_store_goals_and_events();
2396 // evaluate next mission
2397 mission_campaign_eval_next_mission();
2400 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2402 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2403 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2406 // call scoring level close for my stats. Needed for award_init. The stats will
2407 // be backed out if used chooses to replace them.
2408 scoring_level_close();
2410 debrief_ui_init(); // init UI items
2411 debrief_award_init();
2413 debrief_voice_init();
2414 debrief_multi_list_init();
2415 // rank_bitmaps_clear();
2416 // rank_bitmaps_load();
2418 strcpy(Debrief_current_callsign, Player->callsign);
2419 Debrief_player = Player;
2420 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2422 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2423 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2424 // info directly from the server.
2425 if ( !MULTIPLAYER_CLIENT ) {
2426 debrief_set_stages_and_multi_stuff();
2428 if ( Num_debrief_stages <= 0 ) {
2429 Num_debrief_stages = 0;
2431 debrief_voice_load_all();
2434 // multiplayer client may have already received their debriefing info. If they have not,
2435 // then set the num debrief stages to 0
2436 if ( !Debrief_multi_stages_loaded ) {
2437 Num_debrief_stages = 0;
2442 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2443 common_music_init(SCORE_DEBRIEF_SUCCESS);
2445 common_music_init(SCORE_DEBRIEF_FAIL);
2449 // start up the appropriate music
2450 if (Campaign.next_mission == Campaign.current_mission) {
2451 // you failed the mission because you suck, so you get the suck music
2452 common_music_init(SCORE_DEBRIEF_FAIL);
2453 } else if (mission_goals_met()) {
2454 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2455 common_music_init(SCORE_DEBRIEF_SUCCESS);
2457 // you somehow passed the mission, so you get a little something for your efforts.
2458 common_music_init(SCORE_DEBRIEF_AVERAGE);
2461 if (Campaign.next_mission == Campaign.current_mission) {
2462 // better luck next time, increase his retries
2463 Player->failures_this_session++;
2465 // clear his retries info regardless of whether or not he accepts
2466 Player->failures_this_session = 0;
2469 if (Game_mode & GM_MULTIPLAYER) {
2470 multi_debrief_init();
2472 // if i'm not the host of the game, disable the multi kick button
2473 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2474 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2477 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2478 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2479 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2480 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2481 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2482 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2483 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2484 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2487 if (!Award_active) {
2488 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2489 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2492 Debrief_skip_popup_already_shown = 0;
2497 // --------------------------------------------------------------------------------------
2499 void debrief_close()
2503 Assert(Debrief_inited);
2505 // if the mission wasn't accepted, clear out my stats
2506 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2507 // are a little bit different
2508 if (Game_mode & GM_MULTIPLAYER) {
2509 // if stats weren't accepted, backout my own stats
2510 if (multi_debrief_stats_accept_code() != 1) {
2511 if(MULTIPLAYER_MASTER){
2512 for(idx=0; idx<MAX_PLAYERS; idx++){
2513 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2514 scoring_backout_accept(&Net_players[idx].player->stats);
2518 scoring_backout_accept( &Player->stats );
2523 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2524 scoring_backout_accept( &Player->stats );
2528 // if dude passed the misson and accepted, reset his show skip popup flag
2529 if (Debrief_accepted) {
2530 Player->show_skip_popup = 1;
2533 if (Num_debrief_lines) {
2534 for (i=0; i<Num_debrief_lines; i++){
2541 // clear out debrief info parsed from mission file
2542 mission_debrief_common_reset();
2544 // unload the overlay bitmap
2546 help_overlay_unload(DEBRIEFING_OVERLAY);
2549 // clear out award text
2550 Debrief_award_text_num_lines = 0;
2552 debrief_voice_unload_all();
2553 common_music_close();
2556 // rank_bitmaps_release();
2559 if (Background_bitmap >= 0){
2560 bm_unload(Background_bitmap);
2563 if (Award_bg_bitmap >= 0){
2564 bm_unload(Award_bg_bitmap);
2567 if (Rank_bitmap >= 0){
2568 bm_unload(Rank_bitmap);
2571 if (Medal_bitmap >= 0){
2572 bm_unload(Medal_bitmap);
2575 if (Badge_bitmap >= 0){
2576 bm_unload(Badge_bitmap);
2579 if (Wings_bitmap >= 0) {
2580 bm_unload(Wings_bitmap);
2583 if (Crest_bitmap >= 0) {
2584 bm_unload(Crest_bitmap);
2588 if (Medal_text_bitmap >= 0) {
2589 bm_unload(Medal_text_bitmap);
2592 if (Badge_text_bitmap >= 0) {
2593 bm_unload(Badge_text_bitmap);
2596 if (Rank_text_bitmap >= 0) {
2597 bm_unload(Rank_text_bitmap);
2601 Debrief_ui_window.destroy();
2602 common_free_interface_palette(); // restore game palette
2605 if (Game_mode & GM_MULTIPLAYER){
2606 multi_debrief_close();
2614 // handle keypresses in debriefing
2615 void debrief_do_keys(int new_k)
2622 case KEY_SHIFTED | KEY_TAB:
2630 // multiplayer accept popup is a little bit different
2631 if (Game_mode & GM_MULTIPLAYER) {
2632 multi_debrief_esc_hit();
2634 // display the normal debrief popup
2636 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2637 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2638 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2639 if (choice == 1) { // accept and continue on
2641 gameseq_post_event(GS_EVENT_MAIN_MENU);
2647 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2648 // need to popup saying that mission was a failure and must be replayed
2649 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));
2654 // Return to Main Hall
2655 gameseq_post_event(GS_EVENT_END_GAME);
2666 void debrief_draw_award_text()
2668 int start_y, curr_y, i, x, sw;
2669 int fh = gr_get_font_height();
2670 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];
2672 // vertically centered within field
2673 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);
2677 for (i=0; i<Debrief_award_text_num_lines; i++) {
2678 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2679 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2680 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2681 gr_set_color_fast(&Color_white);
2682 gr_string(x, curr_y, Debrief_award_text[i]);
2684 // adjust y pos, including a little extra between the "pairs"
2686 if ((i == 1) || (i == 3)) {
2687 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2692 // clears out text array so we dont have old award text showing up on new awards.
2693 void debrief_award_text_clear() {
2696 Debrief_award_text_num_lines = 0;
2697 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2698 //Debrief_award_text[i][0] = 0;
2699 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2703 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2704 void debrief_add_award_text(char *str)
2706 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2707 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2712 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];
2715 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2717 // maybe translate for displaying
2719 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2720 } else if (Lcl_pl) {
2721 medals_translate_name_pl(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2724 Debrief_award_text_num_lines++;
2726 // if its too long, split once ONLY
2727 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2728 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2729 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2730 if (line2 != NULL) {
2731 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2733 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2736 #endif // !MAKE_FS1: No text for FS1, it's all bitmaps
2738 // called once per frame to drive all the input reading and rendering
2739 void debrief_do_frame(float frametime)
2742 char *please_wait_str = XSTR("Please Wait", 1242);
2746 Assert(Debrief_inited);
2748 // first thing is to load the files
2749 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2750 // draw the background, etc
2751 GR_MAYBE_CLEAR_RES(Background_bitmap);
2752 if (Background_bitmap >= 0) {
2753 gr_set_bitmap(Background_bitmap);
2757 Debrief_ui_window.draw();
2759 if ( Debrief_multi_loading_bitmap > -1 ){
2760 gr_set_bitmap(Debrief_multi_loading_bitmap);
2761 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2764 // draw "Please Wait"
2765 gr_set_color_fast(&Color_normal);
2767 gr_get_string_size(&str_w, &str_h, please_wait_str);
2768 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2773 // make sure we run the debrief do frame
2774 if (Game_mode & GM_MULTIPLAYER) {
2775 multi_debrief_do_frame();
2780 int keypress = game_check_key();
2781 if(keypress == KEY_ESC){
2783 multi_quit_game(PROMPT_CLIENT);
2789 // if multiplayer client, and not loaded voice, then load it
2790 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2791 debrief_multi_fixup_stages();
2792 debrief_voice_load_all();
2793 Debrief_multi_voice_loaded = 1;
2796 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2797 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2798 Debrief_ui_window.set_ignore_gadgets(1);
2801 k = chatbox_process();
2802 if ( Game_mode & GM_NORMAL ) {
2803 new_k = Debrief_ui_window.process(k);
2805 new_k = Debrief_ui_window.process(k, 0);
2808 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2809 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2810 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2811 Debrief_ui_window.set_ignore_gadgets(0);
2817 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2818 Debrief_ui_window.set_ignore_gadgets(0);
2821 // don't show pilot info popup by default
2822 Debrief_should_show_popup = 0;
2824 // see if the mode has changed and handle it if so.
2825 if ( Current_mode != New_mode ) {
2826 debrief_voice_stop();
2827 Current_mode = New_mode;
2830 if (New_mode == DEBRIEF_TAB) {
2832 Debrief_cue_voice = 0;
2834 if (Debrief_first_voice_flag) {
2835 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2836 Debrief_first_voice_flag = 0;
2839 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2843 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2844 Current_stage = New_stage;
2845 debrief_text_init();
2848 debrief_voice_play();
2851 if (Game_mode & GM_MULTIPLAYER) {
2852 multi_debrief_do_frame();
2855 // Now do all the rendering for the frame
2856 GR_MAYBE_CLEAR_RES(Background_bitmap);
2857 if (Background_bitmap >= 0) {
2858 gr_set_bitmap(Background_bitmap);
2862 // draw the damn awarded stuff, G
2863 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2864 gr_set_bitmap(Award_bg_bitmap);
2865 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2866 if (Rank_bitmap >= 0) {
2867 gr_set_bitmap(Rank_bitmap);
2869 gr_bitmap(Debrief_rank_coords[0], Debrief_rank_coords[1]);
2871 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2875 if (Medal_bitmap >= 0) {
2876 gr_set_bitmap(Medal_bitmap);
2877 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2880 if (Badge_bitmap >= 0) {
2881 gr_set_bitmap(Badge_bitmap);
2883 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2885 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2889 if (Wings_bitmap >= 0) {
2890 gr_set_bitmap(Wings_bitmap);
2892 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2894 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2898 // this isn't used in FS1 but doesn't hurt to leave it
2899 if (Crest_bitmap >= 0) {
2900 gr_set_bitmap(Crest_bitmap);
2901 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2904 // draw medal/badge/rank labels
2906 debrief_draw_award_text();
2908 if (Rank_text_bitmap >= 0) {
2909 gr_set_bitmap(Rank_text_bitmap);
2910 gr_bitmap(Debrief_rank_text_coords[gr_screen.res][0], Debrief_rank_text_coords[gr_screen.res][1]);
2913 if (Medal_text_bitmap >= 0) {
2914 gr_set_bitmap(Medal_text_bitmap);
2915 gr_bitmap(Debrief_medal_text_coords[gr_screen.res][0], Debrief_medal_text_coords[gr_screen.res][1]);
2918 if (Badge_text_bitmap >= 0) {
2919 gr_set_bitmap(Badge_text_bitmap);
2920 gr_bitmap(Debrief_badge_text_coords[gr_screen.res][0], Debrief_badge_text_coords[gr_screen.res][1]);
2925 Debrief_ui_window.draw();
2926 debrief_redraw_pressed_buttons();
2927 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2928 if (Recommend_active && (Current_mode != STATS_TAB)) {
2929 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2932 // draw the title of the mission
2933 gr_set_color_fast(&Color_bright_white);
2934 strcpy(buf, The_mission.name);
2935 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2936 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2938 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2939 gr_set_color_fast(&Color_normal);
2940 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);
2943 // draw the screen-specific text
2944 switch (Current_mode) {
2946 if ( Num_debrief_stages <= 0 ) {
2947 gr_set_color_fast(&Color_white);
2948 Assert( Game_current_mission_filename != NULL );
2949 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);
2958 debrief_stats_render();
2962 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2965 gr_set_color_fast(&Color_red);
2966 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2967 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));
2970 debrief_render_stagenum();
2971 debrief_multi_list_draw();
2973 // render some extra stuff in multiplayer
2974 if (Game_mode & GM_MULTIPLAYER) {
2975 // render the chatbox last
2979 Debrief_ui_window.draw_tooltip();
2981 // render the status indicator for the voice system
2982 multi_common_voice_display_status();
2985 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2986 // want to include the mouse pointer which is drawn in the flip
2988 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2989 debrief_check_buttons();
2990 debrief_do_keys(new_k);
2993 // blit help overlay if active
2994 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2998 // dont let dude skip 3-09. hack.
2999 if(Game_mode & GM_CAMPAIGN_MODE){
3000 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
3001 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
3002 Debrief_skip_popup_already_shown = 1;
3007 // maybe show skip mission popup
3008 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)) {
3009 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
3010 XSTR("Advance To The Next Mission", 1474),
3011 XSTR("Don't Show Me This Again", 1475),
3012 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
3013 switch (popup_choice) {
3015 // stay on this mission, so proceed to normal debrief
3016 // in other words, do nothing.
3019 // skip this mission
3020 mission_campaign_skip_to_next();
3021 gameseq_post_event(GS_EVENT_START_GAME);
3024 // dont show this again
3025 Player->show_skip_popup = 0;
3029 Debrief_skip_popup_already_shown = 1;
3032 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
3033 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
3034 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
3035 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
3037 Debrief_should_show_popup = 0;
3041 void debrief_rebuild_player_list()
3045 debrief_multi_list_info *list;
3047 Multi_list_size = 0; // number of net players to choose from
3049 for ( i=0; i<MAX_PLAYERS; i++ ) {
3050 np = &Net_players[i];
3051 // remember not to include the standalone.
3052 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
3053 list = &Multi_list[Multi_list_size++];
3054 list->net_player_index = i;
3055 strcpy(list->callsign, np->player->callsign);
3057 // make sure to leave some room to blit the team indicator
3058 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
3063 void debrief_handle_player_drop()
3065 debrief_rebuild_player_list();
3068 void debrief_disable_accept()