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.9 2003/08/03 16:10:29 taylor
19 * cleanup; compile warning fixes
21 * Revision 1.8 2003/06/03 04:00:40 taylor
22 * Polish language support (Janusz Dziemidowicz)
24 * Revision 1.7 2003/05/25 02:30:43 taylor
27 * Revision 1.6 2002/07/13 06:46:48 theoddone33
30 * Revision 1.5 2002/06/09 04:41:23 relnev
31 * added copyright header
33 * Revision 1.4 2002/06/02 04:26:34 relnev
36 * Revision 1.3 2002/05/26 22:06:17 relnev
37 * makefile: disable stand_gui for now.
39 * rest: staticize some globals
41 * Revision 1.2 2002/05/07 03:16:46 theoddone33
42 * The Great Newline Fix
44 * Revision 1.1.1.1 2002/05/03 03:28:10 root
48 * 57 10/29/99 10:40p Jefff
49 * hack to make german medal names display without actually changing them
51 * 56 10/13/99 3:26p Jefff
52 * fixed unnumbered XSTRs
54 * 55 10/06/99 10:28a Jefff
57 * 54 9/30/99 5:57p Jefff
58 * show upsell at end of campaign in OEM builds
60 * 53 9/15/99 3:42a Jefff
63 * 52 9/14/99 4:35a Dave
64 * Argh. Added all kinds of code to handle potential crashes in debriefing
67 * 51 9/14/99 3:26a Dave
68 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
69 * respawn-too-early problem. Made a few crash points safe.
71 * 50 9/14/99 12:51a Jefff
73 * 49 9/13/99 6:01p Jefff
74 * fixed wrong promotion voice mapping for sm1-08
76 * 48 9/13/99 11:15a Jefff
77 * clear out award text bug fixed
79 * 47 9/13/99 12:17p Andsager
80 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
83 * 46 9/07/99 9:35p Jefff
84 * fixed bug where award text was not getting cleared properly between
87 * 45 9/07/99 6:56p Jefff
88 * a few adjustments to loop detection
90 * 44 9/07/99 1:54p Jefff
91 * skip mission cleanup
93 * 43 9/06/99 9:45p Jefff
94 * skip mission support
96 * 42 9/06/99 6:38p Dave
97 * Improved CD detection code.
99 * 41 9/03/99 1:32a Dave
100 * CD checking by act. Added support to play 2 cutscenes in a row
101 * seamlessly. Fixed super low level cfile bug related to files in the
102 * root directory of a CD. Added cheat code to set campaign mission # in
105 * 40 9/02/99 3:45p Jefff
106 * forgot to remove some debug code. doh.
108 * 39 9/02/99 3:41p Jefff
109 * changed badge voice handling to be similar to promotion voice handling
111 * 38 9/01/99 4:41p Jefff
112 * fixed stoopid text color bug
114 * 37 8/31/99 11:54a Jefff
115 * minor debrief music tweak
117 * 36 8/27/99 9:57a Dave
118 * Enabled standard cheat codes. Allow player to continue in a campaing
119 * after using cheat codes.
121 * 35 8/27/99 12:04a Dave
122 * Campaign loop screen.
124 * 34 8/26/99 8:49p Jefff
125 * Updated medals screen and about everything that ever touches medals in
126 * one way or another. Sheesh.
128 * 33 8/20/99 4:20p Jefff
129 * hack for choosing the correct promotion voice
131 * 32 8/16/99 4:05p Dave
132 * Big honking checkin.
134 * 31 8/16/99 9:49a Jefff
135 * mission title length fix in multi
137 * 30 8/11/99 5:33p Jefff
138 * added 3rd debrief music track
140 * 29 8/10/99 7:28p Jefff
141 * shuffled some text around
143 * 28 8/04/99 5:36p Andsager
144 * Show upsell screens at end of demo campaign before returning to main
147 * 27 8/04/99 2:07p Jefff
148 * mission title no longer overwrites popup
150 * 26 8/02/99 5:37p Jefff
152 * 25 8/02/99 4:52p Jefff
153 * negative feedback sound when recommendations button pressed and
156 * 24 7/21/99 6:21p Jefff
157 * added hotkeys to the "you cannot accept" popup
159 * 23 6/15/99 12:04p Anoop
160 * Added a warning for running out of debrief text lines.
162 * 22 6/09/99 2:17p Dave
163 * Fixed up pleasewait bitmap rendering.
165 * 21 6/01/99 6:07p Dave
166 * New loading/pause/please wait bar.
168 * 20 5/22/99 6:05p Dave
169 * Fixed a few localization # problems.
171 * 19 5/22/99 5:35p Dave
172 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
174 * 18 3/20/99 3:47p Andsager
175 * Fix crash with no mission loop description.
177 * 17 2/23/99 2:29p Dave
178 * First run of oldschool dogfight mode.
180 * 16 2/21/99 6:01p Dave
181 * Fixed standalone WSS packets.
183 * 15 2/11/99 3:08p Dave
184 * PXO refresh button. Very preliminary squad war support.
186 * 14 1/30/99 5:08p Dave
187 * More new hi-res stuff.Support for nice D3D textures.
189 * 13 1/29/99 2:08a Dave
190 * Fixed beam weapon collisions with players. Reduced size of scoring
191 * struct for multiplayer. Disabled PXO.
193 * 12 1/14/99 5:15p Neilk
194 * changed credits, command debrief interfaces to high resolution support
196 * 11 1/13/99 2:11p Andsager
197 * change default debriefing string text
199 * 10 12/17/98 4:50p Andsager
200 * Added debrief_assemble_optional_mission_popup_text() for single and
203 * 9 12/12/98 3:17p Andsager
204 * Clean up mission eval, goal, event and mission scoring.
206 * 8 12/10/98 10:19a Andsager
207 * Fix mission loop assert
209 * 7 12/10/98 9:59a Andsager
210 * Fix some bugs with mission loops
212 * 6 12/09/98 1:56p Andsager
213 * Initial checkin of mission loop
215 * 5 11/05/98 4:18p Dave
216 * First run nebula support. Beefed up localization a bit. Removed all
217 * conditional compiles for foreign versions. Modified mission file
220 * 4 10/23/98 3:51p Dave
221 * Full support for tstrings.tbl and foreign languages. All that remains
222 * is to make it active in Fred.
224 * 3 10/13/98 9:28a Dave
225 * Started neatening up freespace.h. Many variables renamed and
226 * reorganized. Added AlphaColors.[h,cpp]
228 * 2 10/07/98 10:53a Dave
231 * 1 10/07/98 10:49a Dave
233 * 178 9/17/98 3:08p Dave
234 * PXO to non-pxo game warning popup. Player icon stuff in create and join
235 * game screens. Upped server count refresh time in PXO to 35 secs (from
238 * 177 7/07/98 1:46p Dave
239 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
242 * 175 6/09/98 10:31a Hoffoss
243 * Created index numbers for all xstr() references. Any new xstr() stuff
244 * added from here on out should be added to the end if the list. The
245 * current list count can be found in FreeSpace.cpp (search for
248 * 174 6/07/98 3:26p Lawrance
249 * Fix bug with cut-off popup text
251 * 173 6/05/98 9:54a Lawrance
254 * 172 6/01/98 11:43a John
255 * JAS & MK: Classified all strings for localization.
257 * 171 5/27/98 1:24p Allender
258 * make targeting dots work (as well as other targeting features) properly
259 * in multiplayer. Don't query for CD when entering debrief in
262 * 170 5/26/98 11:10a Lawrance
263 * Fix bug where window controls get disabled when F1 pressed twice
265 * 169 5/24/98 12:55a Mike
266 * Prevent Assert() when no debriefing text for a stage.
268 * 168 5/23/98 10:38p Lawrance
269 * Avoid doing a cfile refresh when running debug
271 * 167 5/23/98 6:49p Lawrance
272 * Fix problems with refreshing the file list when a CD is inserted
274 * 166 5/21/98 6:57p Lawrance
275 * Don't prompt for the CD if voice not found
277 * 165 5/20/98 2:24a Dave
278 * Fixed server side voice muting. Tweaked multi debrief/endgame
279 * sequencing a bit. Much friendlier for stats tossing/accepting now.
281 * 164 5/19/98 8:35p Dave
282 * Revamp PXO channel listing system. Send campaign goals/events to
283 * clients for evaluation. Made lock button pressable on all screens.
285 * 163 5/19/98 11:13a Hoffoss
286 * Fixed bug where wrong wings award was being displayed in debriefing.
288 * 162 5/19/98 12:28a Mike
291 * 161 5/18/98 8:08p Hoffoss
292 * Moved placement of 'More' text.
294 * 160 5/18/98 3:50p Dan
295 * AL: Pick correct traitor debriefing voice file
297 * 159 5/17/98 6:32p Dave
298 * Make sure clients/servers aren't kicked out of the debriefing when team
299 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
300 * xfer/pilot info popup stuff.
302 * 158 5/16/98 9:14p Allender
303 * fix scoring ckise fir training missions to actually count medals, but
304 * nothing else. Code used to Assert when wings were granted then taken
305 * away because they were actually never granted in scoring structure
307 * 157 5/15/98 5:15p Dave
308 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
309 * status for team vs. team. Put in asserts to check for invalid team vs.
312 * 156 5/15/98 4:36p Allender
313 * fixed minor bug with wings
315 * 155 5/15/98 4:12p Allender
316 * removed redbook code. Put back in ingame join timer. Major fixups for
317 * stats in multiplayer. Pass correct score, medals, etc when leaving
318 * game. Be sure clients display medals, badges, etc.
320 * 154 5/15/98 2:25p Jasen
321 * temporarily disable granting of promotion and badges for clients
323 * 153 5/15/98 10:57a Allender
324 * fixed client side debriefings
326 * 152 5/15/98 10:36a Dave
327 * Removed 2 bogus bitmap drawing Int3()'s
329 * 151 5/14/98 2:44p Hoffoss
330 * Added wings awarding to debrief screen.
332 * 150 5/13/98 9:11p Lawrance
333 * Make 'replay mission' popup warn users about the loss of mission stats.
338 #include "missiondebrief.h"
339 #include "missionbriefcommon.h"
340 #include "missionscreencommon.h"
341 #include "missiongoals.h"
342 #include "missionpause.h"
343 #include "freespace.h"
344 #include "gamesequence.h"
352 #include "audiostr.h"
355 #include "contexthelp.h"
361 #include "multimsgs.h"
362 #include "multiutil.h"
363 #include "multiteamselect.h"
365 #include "eventmusic.h"
369 #include "multi_pinfo.h"
370 #include "contexthelp.h"
371 #include "multi_kick.h"
372 #include "multi_campaign.h"
373 #include "alphacolors.h"
374 #include "localize.h"
375 #include "multi_endgame.h"
378 #define MAX_TOTAL_DEBRIEF_LINES 200
380 #define TEXT_TYPE_NORMAL 1
381 #define TEXT_TYPE_RECOMMENDATION 2
383 #define DEBRIEF_NUM_STATS_PAGES 4
384 #define DEBRIEF_MISSION_STATS 0
385 #define DEBRIEF_MISSION_KILLS 1
386 #define DEBRIEF_ALLTIME_STATS 2
387 #define DEBRIEF_ALLTIME_KILLS 3
389 // 3rd coord is max width in pixels
390 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
403 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
416 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
421 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
434 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
447 #define MULTI_LIST_TEAM_OFFSET 16
449 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
454 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
463 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
476 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
490 int Debrief_rank_coords[2] = {
494 int Debrief_badge_coords[2] = {
500 // 0=x, 1=y, 2=width of the field
501 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
510 // 0=x, 1=y, 2=height of the field
511 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
520 // the medal text in FS1 is a bitmap
521 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][2] = {
530 int Debrief_rank_text_coords[GR_NUM_RESOLUTIONS][2] = {
539 int Debrief_badge_text_coords[GR_NUM_RESOLUTIONS][2] = {
550 // 1 = without medal (text will use medal space)
551 #define DB_WITH_MEDAL 0
552 #define DB_WITHOUT_MEDAL 1
553 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
562 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
563 "DebriefSingle", // GR_640
564 "2_DebriefSingle" // GR_1024
566 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
567 "DebriefMulti", // GR_640
568 "2_DebriefMulti" // GR_1024
570 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
571 "Debrief-m", // GR_640
572 "2_Debrief-m" // GR_1024
575 #define NUM_BUTTONS 18
578 #define DEBRIEF_TAB 0
580 #define TEXT_SCROLL_UP 2
581 #define TEXT_SCROLL_DOWN 3
582 #define REPLAY_MISSION 4
583 #define RECOMMENDATIONS 5
584 #define FIRST_STAGE 6
588 #define MULTI_PINFO_POPUP 10
589 #define MULTI_KICK 11
590 #define MEDALS_BUTTON 12
591 #define PLAYER_SCROLL_UP 13
592 #define PLAYER_SCROLL_DOWN 14
593 #define HELP_BUTTON 15
594 #define OPTIONS_BUTTON 16
595 #define ACCEPT_BUTTON 17
600 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
601 "PleaseWait", // GR_640
602 "2_PleaseWait" // GR_1024
608 char text[NAME_LENGTH+1]; // name of ship type with a colon
609 int num; // how many ships of this type player has killed
610 } debrief_stats_kill_info;
613 int net_player_index; // index into Net_players[] array
614 int rank_bitmap; // bitmap id for rank
615 char callsign[CALLSIGN_LEN];
616 } debrief_multi_list_info;
618 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
621 ui_button_info("DB_00", 0, 2, -1, -1, 0), // debriefing
622 ui_button_info("DB_01", 0, 20, -1, -1, 1), // statistics
623 ui_button_info("DB_02", 0, 195, -1, -1, 2), // scroll stats up
624 ui_button_info("DB_03", 0, 232, -1, -1, 3), // scroll stats down
625 ui_button_info("DB_04", 24, 424, -1, -1, 4), // replay mission
626 ui_button_info("DB_05", 30, 451, -1, -1, 5), // recommendations
627 ui_button_info("DB_06", 211, 445, -1, -1, 6), // first page
628 ui_button_info("DB_07", 234, 445, -1, -1, 7), // prev page
629 ui_button_info("DB_08", 259, 445, -1, -1, 8), // next page
630 ui_button_info("DB_09", 283, 445, -1, -1, 9), // last page
631 ui_button_info("DB_21", 441, 384, -1, -1, 21), // pilot info
632 ui_button_info("DB_25", 511, 384, -1, -1, 25), // kick
633 ui_button_info("DB_15", 604, 224, -1, -1, 15), // medals
634 ui_button_info("DB_16", 615, 329, -1, -1, 16), // scroll pilots up
635 ui_button_info("DB_17", 615, 371, -1, -1, 17), // scroll pilots down
636 ui_button_info("DB_10", 469, 428, -1, -1, 10), // help
637 ui_button_info("DB_11", 447, 452, -1, -1, 11), // options
638 ui_button_info("DB_12", 562, 410, -1, -1, 12), // accept
640 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
641 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
642 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
643 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
644 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
645 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
646 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
647 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
648 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
649 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
650 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
651 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
652 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
653 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
654 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
655 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
656 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
657 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
661 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
662 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
663 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
664 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
665 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
666 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
667 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
668 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
669 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
670 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
671 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
672 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
673 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
674 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
675 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
676 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
677 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
678 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
684 #define NUM_DEBRIEF_TEXT 0
686 #define NUM_DEBRIEF_TEXT 10
688 #define MP_TEXT_INDEX_1 4
689 #define MP_TEXT_INDEX_2 5
690 #define MP_TEXT_INDEX_3 6
691 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
693 // not needed for FS1
695 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
696 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
697 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
698 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
699 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
700 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
701 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
702 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
703 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
704 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
708 // not needed for FS1
710 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
711 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
712 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
713 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
714 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
715 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
716 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
717 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
718 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
719 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
725 char Debrief_current_callsign[CALLSIGN_LEN+10];
726 player *Debrief_player;
728 static UI_WINDOW Debrief_ui_window;
729 static UI_BUTTON List_region;
730 static int Background_bitmap; // bitmap for the background of the debriefing
731 static int Award_bg_bitmap;
732 static int Debrief_multi_loading_bitmap;
733 static int Rank_bitmap;
734 static int Medal_bitmap;
735 static int Badge_bitmap;
736 static int Wings_bitmap;
737 static int Crest_bitmap;
739 static int Rank_text_bitmap;
740 static int Medal_text_bitmap;
741 static int Badge_text_bitmap;
744 static int Debrief_accepted;
745 static int Turned_traitor;
746 static int Must_replay_mission;
748 static int Current_mode;
750 static int Recommend_active;
751 static int Award_active;
752 static int Text_offset;
753 static int Num_text_lines = 0;
754 static int Num_debrief_lines = 0;
755 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
756 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
758 static int Debrief_inited = 0;
759 static int New_stage;
760 static int Current_stage;
761 static int Num_stages;
762 static int Num_debrief_stages;
763 static int Stage_voice;
765 static int Multi_list_size;
766 static int Multi_list_offset;
768 int Debrief_multi_stages_loaded = 0;
769 int Debrief_multi_voice_loaded = 0;
771 // static int Debrief_voice_ask_for_cd;
773 // voice id's for debriefing text
774 static int Debrief_voices[MAX_DEBRIEF_STAGES];
776 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
777 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
778 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
780 // pointer used for getting to debriefing information
781 debriefing Traitor_debriefing; // used when player is a traitor
783 // pointers to the active stages for this debriefing
784 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
785 static debrief_stage Promotion_stage, Badge_stage;
786 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
787 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
788 int Multi_list_select;
790 // flag indicating if we should display info for the given player (in multiplayer)
791 int Debrief_should_show_popup = 1;
793 // already shown skip mission popup?
794 static int Debrief_skip_popup_already_shown = 0;
796 void debrief_text_init();
797 void debrief_accept(int ok_to_post_start_game_event = 1);
798 void debrief_kick_selected_player();
801 // promotion voice selection stuff
802 #define NUM_VOLITION_CAMPAIGNS 1
804 char campaign_name[32];
806 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
808 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
809 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
813 // data for which voice goes w/ which mission
814 typedef struct voice_map {
815 char mission_file[32];
819 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
820 { // FreeSpace2 campaign
852 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
854 { "loop1-1.fs2", 4 },
855 { "loop1-2.fs2", 4 },
856 { "loop1-3.fs2", 5 },
857 { "loop2-1.fs2", 4 },
862 #define DB_AWARD_WINGS 0
863 #define DB_AWARD_MEDAL 1
865 #define DB_AWARD_RANK 2
866 #define DB_AWARD_BADGE 3
867 #define DB_AWARD_BG 4
868 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][5] = {
885 #define DB_AWARD_SOC 2
886 #define DB_AWARD_RANK 3
887 #define DB_AWARD_BADGE 4
888 #define DB_AWARD_BG 5
889 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
909 #define AWARD_TEXT_MAX_LINES 5
910 #define AWARD_TEXT_MAX_LINE_LENGTH 128
911 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
912 int Debrief_award_text_num_lines = 0;
916 // prototypes, you know you love 'em
917 void debrief_add_award_text(char *str);
918 void debrief_award_text_clear();
923 char *debrief_tooltip_handler(char *str)
925 if (!stricmp(str, NOX("@.Medal"))) {
927 return XSTR( "Medal", 435);
930 } else if (!stricmp(str, NOX("@.Rank"))) {
932 return XSTR( "Rank", 436);
935 } else if (!stricmp(str, NOX("@.Badge"))) {
937 return XSTR( "Badge", 437);
940 } else if (!stricmp(str, NOX("@Medal"))) {
941 if (Medal_bitmap >= 0){
942 return Medals[Player->stats.m_medal_earned].name;
945 } else if (!stricmp(str, NOX("@Rank"))) {
946 if (Rank_bitmap >= 0){
947 return Ranks[Promoted].name;
950 } else if (!stricmp(str, NOX("@Badge"))) {
951 if (Badge_bitmap >= 0){
952 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
959 // initialize the array of handles to the different voice streams
960 void debrief_voice_init()
964 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
965 Debrief_voices[i] = -1;
969 void debrief_load_voice_file(int voice_num, char *name)
971 int load_attempts = 0;
974 if ( load_attempts++ > 5 ) {
978 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
979 if ( Debrief_voices[voice_num] >= 0 ) {
983 // Don't bother to ask for the CD in multiplayer
984 if ( Game_mode & GM_MULTIPLAYER ) {
988 // couldn't load voice, ask user to insert CD (if necessary)
990 // if ( Debrief_voice_ask_for_cd ) {
991 // if ( game_do_cd_check() == 0 ) {
992 // Debrief_voice_ask_for_cd = 0;
999 // open and pre-load the stream buffers for the different voice streams
1000 void debrief_voice_load_all()
1004 // Debrief_voice_ask_for_cd = 1;
1006 for ( i=0; i<Num_debrief_stages; i++ ) {
1007 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
1010 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
1011 debrief_load_voice_file(i, Debrief_stages[i]->voice);
1012 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
1017 // close all the briefing voice streams
1018 void debrief_voice_unload_all()
1022 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
1023 if ( Debrief_voices[i] != -1 ) {
1024 audiostream_close_file(Debrief_voices[i], 0);
1025 Debrief_voices[i] = -1;
1030 // start playback of the voice for a particular briefing stage
1031 void debrief_voice_play()
1033 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
1037 // no more stages? We are done then.
1038 if (Stage_voice >= Num_debrief_stages){
1042 // if in delayed start, see if delay has elapsed and start voice if so
1043 if (Debrief_cue_voice) {
1044 if (!timestamp_elapsed(Debrief_cue_voice)){
1048 Stage_voice++; // move up to next voice
1049 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
1050 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
1051 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
1057 // see if voice is still playing. If so, do nothing yet.
1058 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
1062 // set voice to play in a little while from now.
1063 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
1066 // stop playback of the voice for a particular briefing stage
1067 void debrief_voice_stop()
1069 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
1072 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
1076 // function to deal with inserting possible promition and badge stages into the debriefing
1078 void debrief_multi_fixup_stages()
1082 // possibly insert the badge stage first, them the promotion stage since they are
1083 // inserted at the front of the debrief stages.
1084 if ( Badge_bitmap >= 0 ) {
1085 // move all stages forward one. Don't
1086 for ( i = Num_debrief_stages; i > 0; i-- ) {
1087 Debrief_stages[i] = Debrief_stages[i-1];
1089 Debrief_stages[0] = &Badge_stage;
1090 Num_debrief_stages++;
1093 if ( Promoted >= 0) {
1094 // move all stages forward one
1095 for ( i = Num_debrief_stages; i > 0; i-- ) {
1096 Debrief_stages[i] = Debrief_stages[i-1];
1098 Debrief_stages[0] = &Promotion_stage;
1099 Num_debrief_stages++;
1104 // function called from multiplayer clients to set up the debriefing information for them
1105 // (sent from the server).
1106 void debrief_set_multi_clients( int stage_count, int active_stages[] )
1110 // set up the right briefing for this guy
1111 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
1112 Debriefing = &Debriefings[Net_player->p_info.team];
1114 Debriefing = &Debriefings[0];
1117 // see if this client was promoted -- if so, then add the first stage.
1118 Num_debrief_stages = 0;
1120 // set the pointers to the debriefings for this client
1121 for (i = 0; i < stage_count; i++) {
1122 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
1125 Debrief_multi_stages_loaded = 1;
1128 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
1129 // information to all clients after leaving this screen.
1130 void debrief_multi_server_stuff()
1132 debriefing *debriefp;
1134 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1135 int i, j, num_stages, stage_count[MAX_TEAMS];
1137 memset( stage_active, 0, sizeof(stage_active) );
1139 for (i=0; i<Num_teams; i++) {
1140 debriefp = &Debriefings[i];
1142 stages[i] = stage_active[i];
1143 for (j=0; j<debriefp->num_stages; j++) {
1144 if ( eval_sexp(debriefp->stages[j].formula) ) {
1145 stage_active[i][num_stages] = j;
1150 stage_count[i] = num_stages;
1153 // if we're in campaign mode, evaluate campaign stuff
1154 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1155 multi_campaign_eval_debrief();
1158 // send the information to all clients.
1159 send_debrief_info( stage_count, stages );
1163 // --------------------------------------------------------------------------------------
1164 // debrief_set_stages_and_multi_stuff()
1166 // Set up the active stages for this debriefing
1168 // returns: number of active debriefing stages
1170 int debrief_set_stages_and_multi_stuff()
1173 debriefing *debriefp;
1175 if ( MULTIPLAYER_CLIENT ) {
1179 Num_debrief_stages = 0;
1181 if ( Game_mode & GM_MULTIPLAYER ) {
1182 debrief_multi_server_stuff();
1185 // check to see if player is a traitor (looking at his team). If so, use the special
1186 // traitor debriefing. Only done in single player
1187 debriefp = Debriefing;
1188 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1189 if (Player_ship->team == TEAM_TRAITOR)
1190 debriefp = &Traitor_debriefing;
1193 Num_debrief_stages = 0;
1194 if (Promoted >= 0) {
1195 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1198 if (Badge_bitmap >= 0) {
1199 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1202 for (i=0; i<debriefp->num_stages; i++) {
1203 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1204 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1208 return Num_debrief_stages;
1211 // init the buttons that are specific to the debriefing screen
1212 void debrief_buttons_init()
1217 for ( i=0; i<NUM_BUTTONS; i++ ) {
1218 b = &Buttons[gr_screen.res][i];
1219 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1220 // set up callback for when a mouse first goes over a button
1221 b->button.set_highlight_action( common_play_highlight_sound );
1222 b->button.set_bmaps(b->filename);
1223 b->button.link_hotspot(b->hotspot);
1227 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1228 // multiplayer specific text
1229 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1230 // only add if in multiplayer mode
1231 if(Game_mode & GM_MULTIPLAYER){
1232 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1237 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1241 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1242 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1243 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1244 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1245 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1246 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1247 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1248 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1250 // if in multiplayer, disable the button for all players except the host
1251 // also disable for squad war matches
1252 if(Game_mode & GM_MULTIPLAYER){
1253 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1254 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1259 // --------------------------------------------------------------------------------------
1260 // debrief_ui_init()
1262 void debrief_ui_init()
1264 // init ship selection masks and buttons
1265 common_set_interface_palette("DebriefPalette"); // set the interface palette
1266 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1267 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1268 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1269 debrief_buttons_init();
1271 // load in help overlay bitmap
1272 help_overlay_load(DEBRIEFING_OVERLAY);
1273 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1275 if ( Game_mode & GM_MULTIPLAYER ) {
1276 // close down any old instances of the chatbox
1279 // create the new one
1281 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1282 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);
1285 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1288 if ( Background_bitmap < 0 ) {
1289 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1292 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1293 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1296 // sets Promotion_stage.voice
1297 // defaults to number 9 (Petrarch) for non-volition missions
1298 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1299 void debrief_choose_promotion_voice()
1303 if(Campaign.current_mission < 0){
1304 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1308 // search thru all official campaigns for our current campaign
1309 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1310 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1311 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1312 // now search thru the mission filenames,
1313 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1314 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1315 // found it! set the persona and bail
1316 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1324 // default to petrarch
1325 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1328 // sets Promotion_stage.voice
1329 // defaults to number 9 (Petrarch) for non-volition missions
1330 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1331 void debrief_choose_badge_voice()
1337 if(Campaign.current_mission < 0){
1339 // default to petrarch
1340 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1342 // default to FS1 guy
1343 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1347 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1349 if ( Player->on_bastion ) {
1350 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base2);
1353 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1357 // search thru all official campaigns for our current campaign
1358 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1359 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1360 // now search thru the mission filenames,
1361 for (j=0; j<Campaign.num_missions; j++) {
1362 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1363 // found it! set the persona and bail
1364 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1374 // default to petrarch
1375 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1377 // default to FS1 guy
1378 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1383 void debrief_award_init()
1395 // be sure there are no old award texts floating around
1397 debrief_award_text_clear();
1400 // handle medal earned
1401 if (Player->stats.m_medal_earned != -1) {
1402 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1404 if ( Player->stats.medals[13] > 1 ) {
1409 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1410 Wings_bitmap = bm_load(buf);
1412 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1413 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1416 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1417 Medal_bitmap = bm_load(buf);
1421 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1425 // handle promotions
1426 if ( Player->stats.m_promotion_earned != -1 ) {
1427 Promoted = Player->stats.m_promotion_earned;
1428 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1429 Rank_bitmap = bm_load(buf);
1431 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1432 Promotion_stage.new_recommendation_text = NULL;
1434 // choose appropriate promotion voice for this mission
1435 debrief_choose_promotion_voice();
1438 debrief_add_award_text(Ranks[Promoted].name);
1442 // handle badge earned
1443 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1444 if ( Player->stats.m_badge_earned != -1 ) {
1445 i = Player->stats.m_badge_earned;
1446 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1447 Badge_bitmap = bm_load(buf);
1449 Badge_stage.new_text = Badge_info[i].promotion_text;
1450 Badge_stage.new_recommendation_text = NULL;
1452 // choose appropriate voice
1453 debrief_choose_badge_voice();
1456 debrief_add_award_text(Medals[Badge_index[i]].name);
1460 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1467 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1468 // mission a traitor. The same debriefing always gets played
1469 void debrief_traitor_init()
1471 static int inited = 0;
1474 debriefing *debrief;
1475 debrief_stage *stagep;
1479 if ((rval = setjmp(parse_abort)) != 0) {
1480 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1483 read_file_text("traitor.tbl");
1487 // open localization
1490 // simplied form of the debriefing stuff.
1491 debrief = &Traitor_debriefing;
1492 required_string("#Debriefing_info");
1494 required_string("$Num stages:");
1495 stuff_int(&debrief->num_stages);
1496 Assert(debrief->num_stages == 1);
1499 stagep = &debrief->stages[stage_num++];
1500 required_string("$Formula:");
1501 stagep->formula = get_sexp_main();
1502 required_string("$multi text");
1503 if ( Fred_running ) {
1504 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1506 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1508 required_string("$Voice:");
1509 char traitor_voice_file[NAME_LENGTH];
1510 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1512 // DKA 9/13/99 Only 1 traitor msg for FS2
1514 if ( Player->on_bastion ) {
1515 strcpy(stagep->voice, NOX("3_"));
1517 strcpy(stagep->voice, NOX("1_"));
1521 strcat(stagep->voice, traitor_voice_file);
1523 required_string("$Recommendation text:");
1524 if ( Fred_running ) {
1525 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1527 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1531 // close localization
1535 // disable the accept button if in single player and I am a traitor
1536 Debrief_accepted = 0;
1537 Turned_traitor = Must_replay_mission = 0;
1538 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1539 if (Player_ship->team == TEAM_TRAITOR){
1543 if (Campaign.next_mission == Campaign.current_mission){
1544 Must_replay_mission = 1;
1548 if (Turned_traitor || Must_replay_mission) {
1549 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1551 // kill off any stats
1552 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1553 scoring_level_init( &Player->stats );
1557 // initialization for listing of players in game
1558 void debrief_multi_list_init()
1560 Multi_list_size = 0; // number of net players to choose from
1561 Multi_list_offset = 0;
1563 Multi_list_select = -1;
1565 if ( !(Game_mode & GM_MULTIPLAYER) )
1568 debrief_rebuild_player_list();
1570 // switch stats display to this newly selected player
1571 set_player_stats(Multi_list[0].net_player_index);
1572 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1573 Debrief_player = Player;
1576 void debrief_multi_list_scroll_up()
1578 // if we're at the beginning of the list, don't do anything
1579 if(Multi_list_offset == 0){
1580 gamesnd_play_iface(SND_GENERAL_FAIL);
1584 // otherwise scroll up
1585 Multi_list_offset--;
1586 gamesnd_play_iface(SND_USER_SELECT);
1589 void debrief_multi_list_scroll_down()
1591 // if we can scroll down no further
1592 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1593 gamesnd_play_iface(SND_GENERAL_FAIL);
1596 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1597 gamesnd_play_iface(SND_GENERAL_FAIL);
1601 // otherwise scroll down
1602 Multi_list_offset++;
1603 gamesnd_play_iface(SND_USER_SELECT);
1606 // draw the connected net players
1607 void debrief_multi_list_draw()
1609 int y, z, font_height,idx;
1610 char str[CALLSIGN_LEN+5];
1613 font_height = gr_get_font_height();
1615 // if we currently have no item picked, pick a reasonable one
1616 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1617 // select the entry which corresponds to the local player
1618 Multi_list_select = 0;
1619 for(idx=0;idx<Multi_list_size;idx++){
1620 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1621 Multi_list_select = idx;
1623 // switch stats display to this newly selected player
1624 set_player_stats(Multi_list[idx].net_player_index);
1625 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1626 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1632 // draw the list itself
1634 z = Multi_list_offset;
1635 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1636 np = &Net_players[Multi_list[z].net_player_index];
1638 if (z >= Multi_list_size){
1641 // set the proper text color for the highlight
1642 if(np->flags & NETINFO_FLAG_GAME_HOST){
1643 if(Multi_list_select == z){
1644 gr_set_color_fast(&Color_text_active_hi);
1646 gr_set_color_fast(&Color_bright);
1649 if(Multi_list_select == z){
1650 gr_set_color_fast(&Color_text_active);
1652 gr_set_color_fast(&Color_text_normal);
1656 // blit the proper indicator - skipping observers
1657 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1658 if(Netgame.type_flags & NG_TYPE_TEAM){
1660 if(np->p_info.team == 0){
1661 // draw his "selected" icon
1662 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1663 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1664 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1666 // draw his "normal" icon
1667 else if(Multi_common_icons[MICON_TEAM0] != -1){
1668 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1669 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1671 } else if(np->p_info.team == 1){
1672 // draw his "selected" icon
1673 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1674 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1675 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1677 // draw his "normal" icon
1678 else if(Multi_common_icons[MICON_TEAM1] != -1){
1679 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1680 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1684 // draw the team 0 selected icon
1685 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1686 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1687 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1692 strcpy(str,Multi_list[z].callsign);
1693 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)){
1694 strcat(str,XSTR( "(O)", 438));
1698 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1705 void debrief_kick_selected_player()
1707 if(Multi_list_select >= 0){
1708 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1709 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1713 // get optional mission popup text
1714 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1716 Assert(buffer != NULL);
1719 if (mission_loop_desc == NULL) {
1720 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1721 mprintf(("No mission loop description avail"));
1723 strcpy(buffer, mission_loop_desc);
1726 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1729 // what to do when the accept button is hit
1730 void debrief_accept(int ok_to_post_start_game_event)
1734 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1738 if (Game_mode & GM_MULTIPLAYER) {
1742 if (Player_ship->team == TEAM_TRAITOR){
1743 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1744 }/* else if (Cheats_enabled) {
1745 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1747 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1750 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1752 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1753 } else if ( z == 1 ) {
1754 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1760 Debrief_accepted = 1;
1761 // save mission stats
1762 if (Game_mode & GM_MULTIPLAYER) {
1763 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1764 // as well as doing stats transfers, etc.
1765 multi_debrief_accept_hit();
1769 int play_commit_sound = 1;
1770 // only write the player's stats if he's accepted
1772 // if we are just playing a single mission, then don't do many of the things
1773 // that need to be done. Nothing much should happen when just playing a single
1774 // mission that isn't in a campaign.
1775 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1777 // check for possible mission loop
1778 // check for (1) mission loop available, (2) dont have to repeat last mission
1779 if(!(Game_mode & GM_MULTIPLAYER)){
1780 int cur = Campaign.current_mission;
1781 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1782 if (Campaign.missions[cur].has_mission_loop) {
1783 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1786 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1789 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1791 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1793 Campaign.loop_enabled = 1;
1794 Campaign.next_mission = Campaign.loop_mission;
1803 if(ok_to_post_start_game_event){
1804 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1806 play_commit_sound = 0;
1809 // continue as normal
1812 mission_campaign_mission_over();
1814 // check to see if we are out of the loop now
1815 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1816 Campaign.loop_enabled = 0;
1819 // check if campaign is over
1820 if ( Campaign.next_mission == -1 ) {
1821 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
1822 gameseq_post_event(GS_EVENT_END_DEMO);
1824 gameseq_post_event(GS_EVENT_MAIN_MENU);
1827 if ( ok_to_post_start_game_event ) {
1829 if(game_do_cd_mission_check(Game_current_mission_filename)){
1830 gameseq_post_event(GS_EVENT_START_GAME);
1832 gameseq_post_event(GS_EVENT_MAIN_MENU);
1835 play_commit_sound = 0;
1840 gameseq_post_event(GS_EVENT_MAIN_MENU);
1843 if ( play_commit_sound ) {
1844 gamesnd_play_iface(SND_COMMIT_PRESSED);
1851 void debrief_next_tab()
1853 New_mode = Current_mode + 1;
1854 if (New_mode >= NUM_TABS)
1858 void debrief_prev_tab()
1860 New_mode = Current_mode - 1;
1862 New_mode = NUM_TABS - 1;
1865 // --------------------------------------------------------------------------------------
1866 // debrief_next_stage()
1868 void debrief_next_stage()
1870 if (Current_stage < Num_stages - 1) {
1871 New_stage = Current_stage + 1;
1872 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1875 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1878 // --------------------------------------------------------------------------------------
1879 // debrief_prev_stage()
1881 void debrief_prev_stage()
1883 if (Current_stage) {
1884 New_stage = Current_stage - 1;
1885 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1888 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1891 // --------------------------------------------------------------------------------------
1892 // debrief_first_stage()
1893 void debrief_first_stage()
1895 if (Current_stage) {
1897 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1900 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1903 // --------------------------------------------------------------------------------------
1904 // debrief_last_stage()
1905 void debrief_last_stage()
1907 if (Current_stage != Num_stages - 1) {
1908 New_stage = Num_stages - 1;
1909 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1912 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1915 // draw what stage number the debriefing is on
1916 void debrief_render_stagenum()
1924 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1925 gr_get_string_size(&w, NULL, buf);
1926 gr_set_color_fast(&Color_bright_blue);
1927 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1928 gr_set_color_fast(&Color_white);
1931 // render the mission time at the specified y location
1932 void debrief_render_mission_time(int y_loc)
1936 game_format_time(Missiontime, time_str);
1937 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1938 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1941 // render out the debriefing text to the scroll window
1942 void debrief_render()
1944 int y, z, font_height;
1946 if ( Num_stages <= 0 )
1949 font_height = gr_get_font_height();
1951 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]);
1954 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1955 if (z >= Num_text_lines)
1958 if (Text_type[z] == TEXT_TYPE_NORMAL)
1959 gr_set_color_fast(&Color_white);
1961 gr_set_color_fast(&Color_bright_red);
1964 gr_string(0, y, Text[z]);
1973 // render out the stats info to the scroll window
1975 void debrief_stats_render()
1977 int i, y, font_height;
1979 gr_set_color_fast(&Color_blue);
1980 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]);
1981 gr_string(0, 0, Debrief_current_callsign);
1982 font_height = gr_get_font_height();
1985 switch ( Current_stage ) {
1986 case DEBRIEF_MISSION_STATS:
1987 i = Current_stage - 1;
1991 gr_set_color_fast(&Color_white);
1993 // display mission completion time
1994 debrief_render_mission_time(y);
1997 show_stats_label(i, 0, y, font_height);
1998 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2000 case DEBRIEF_ALLTIME_STATS:
2001 i = Current_stage - 1;
2005 gr_set_color_fast(&Color_white);
2006 show_stats_label(i, 0, y, font_height);
2007 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2010 case DEBRIEF_ALLTIME_KILLS:
2011 case DEBRIEF_MISSION_KILLS:
2012 gr_set_color_fast(&Color_white);
2014 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
2015 if (i >= Num_text_lines)
2019 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2020 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
2022 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
2025 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
2026 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
2033 if (Num_text_lines == 2) {
2034 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2035 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
2037 gr_printf(0, y, XSTR( "(No ship kills)", 450));
2050 // do action for when the replay button is pressed
2051 void debrief_replay_pressed()
2053 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2055 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));
2062 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
2063 gamesnd_play_iface(SND_COMMIT_PRESSED);
2066 // -------------------------------------------------------------------
2067 // debrief_redraw_pressed_buttons()
2069 // Redraw any debriefing buttons that are pressed down. This function is needed
2070 // since we sometimes need to draw pressed buttons last to ensure the entire
2071 // button gets drawn (and not overlapped by other buttons)
2073 void debrief_redraw_pressed_buttons()
2078 for ( i=0; i<NUM_BUTTONS; i++ ) {
2079 b = &Buttons[gr_screen.res][i].button;
2080 // don't draw the recommendations button if we're in stats mode
2081 if ( b->button_down() ) {
2087 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
2089 void debrief_button_pressed(int num)
2093 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
2094 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
2095 if (num != Current_mode){
2096 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2101 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
2102 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
2103 if (num != Current_mode){
2104 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2109 case TEXT_SCROLL_UP:
2112 gamesnd_play_iface(SND_SCROLL);
2114 gamesnd_play_iface(SND_GENERAL_FAIL);
2118 case TEXT_SCROLL_DOWN:
2119 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2121 gamesnd_play_iface(SND_SCROLL);
2123 gamesnd_play_iface(SND_GENERAL_FAIL);
2127 case REPLAY_MISSION:
2128 if(Game_mode & GM_MULTIPLAYER){
2129 multi_debrief_replay_hit();
2131 debrief_replay_pressed();
2135 case RECOMMENDATIONS:
2136 gamesnd_play_iface(SND_USER_SELECT);
2137 Recommend_active = !Recommend_active;
2138 debrief_text_init();
2142 debrief_first_stage();
2146 debrief_prev_stage();
2150 debrief_next_stage();
2154 debrief_last_stage();
2158 gamesnd_play_iface(SND_HELP_PRESSED);
2159 launch_context_help();
2162 case OPTIONS_BUTTON:
2163 gamesnd_play_iface(SND_SWITCH_SCREENS);
2164 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2172 gamesnd_play_iface(SND_SWITCH_SCREENS);
2173 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2176 case PLAYER_SCROLL_UP:
2177 debrief_multi_list_scroll_up();
2180 case PLAYER_SCROLL_DOWN:
2181 debrief_multi_list_scroll_down();
2184 case MULTI_PINFO_POPUP:
2185 Debrief_should_show_popup = 1;
2189 debrief_kick_selected_player();
2194 void debrief_setup_ship_kill_stats(int stage_num)
2198 debrief_stats_kill_info *kill_info;
2200 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2201 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2204 Assert(Debrief_player != NULL);
2206 // kill_ar points to an array of MAX_SHIP_TYPE ints
2207 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2208 kill_arr = Debrief_player->stats.m_okKills;
2210 kill_arr = Debrief_player->stats.kills;
2214 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2216 // code used to add in mission kills, but the new system assumes that the player will accept, so
2217 // all time stats already have mission stats added in.
2218 if ( kill_arr[i] <= 0 ){
2223 kill_info = &Debrief_stats_kills[Num_text_lines++];
2225 kill_info->num = kill_arr[i];
2227 strcpy(kill_info->text, Ship_info[i].name);
2228 strcat(kill_info->text, NOX(":"));
2231 Num_text_lines += 2;
2234 // Iterate through the debriefing buttons, checking if they are pressed
2235 void debrief_check_buttons()
2239 for ( i=0; i<NUM_BUTTONS; i++ ) {
2240 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2241 debrief_button_pressed(i);
2245 if ( !(Game_mode & GM_MULTIPLAYER) )
2248 if (List_region.pressed()) {
2249 List_region.get_mouse_pos(NULL, &y);
2250 z = Multi_list_offset + y / gr_get_font_height();
2251 if ((z >= 0) && (z < Multi_list_size)) {
2252 // switch stats display to this newly selected player
2253 set_player_stats(Multi_list[z].net_player_index);
2254 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2255 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2256 Multi_list_select = z;
2257 debrief_setup_ship_kill_stats(Current_stage);
2258 gamesnd_play_iface(SND_USER_SELECT);
2262 // if the player was double clicked on - we should popup a player info popup
2264 if (List_region.double_clicked()) {
2265 Debrief_should_show_popup = 1;
2270 void debrief_text_stage_init(char *src, int type)
2272 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2273 char line[MAX_DEBRIEF_LINE_LEN];
2274 char *p_str[MAX_DEBRIEF_LINES];
2276 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2277 Assert(n_lines >= 0);
2279 // if you hit this, you proba
2280 if(n_lines >= MAX_DEBRIEF_LINES){
2281 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2284 for ( i=0; i<n_lines; i++ ) {
2285 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2286 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2287 strncpy(line, p_str[i], n_chars[i]);
2288 line[n_chars[i]] = 0;
2289 drop_white_space(line);
2290 Text_type[Num_text_lines] = type;
2291 Text[Num_text_lines++] = strdup(line);
2297 void debrief_free_text()
2301 for (i=0; i<Num_debrief_lines; i++)
2305 Num_debrief_lines = 0;
2308 // setup the debriefing text lines for rendering
2309 void debrief_text_init()
2314 // release old text lines first
2315 debrief_free_text();
2316 Num_text_lines = Text_offset = 0;
2318 if (Current_mode == DEBRIEF_TAB) {
2319 for (i=0; i<Num_debrief_stages; i++) {
2321 Text[Num_text_lines++] = NULL; // add a blank line between stages
2323 src = Debrief_stages[i]->new_text;
2325 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2327 if (Recommend_active) {
2328 src = Debrief_stages[i]->new_recommendation_text;
2329 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2330 src = XSTR( "We have no recommendations for you.", 1054);
2333 Text[Num_text_lines++] = NULL;
2334 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2340 Num_debrief_lines = Num_text_lines;
2344 // not in debriefing mode, must be in stats mode
2346 debrief_setup_ship_kill_stats(Current_stage);
2350 // --------------------------------------------------------------------------------------
2354 Assert(!Debrief_inited);
2355 // Campaign.loop_enabled = 0;
2356 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2358 // set up the right briefing for this guy
2359 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2360 Debriefing = &Debriefings[Net_player->p_info.team];
2362 Debriefing = &Debriefings[0];
2365 // no longer is mission
2366 Game_mode &= ~(GM_IN_MISSION);
2370 New_mode = DEBRIEF_TAB;
2371 Recommend_active = Award_active = 0;
2376 Debrief_cue_voice = 0;
2377 Num_text_lines = Num_debrief_lines = 0;
2378 Debrief_first_voice_flag = 1;
2380 Debrief_multi_voice_loaded = 0;
2383 Medal_text_bitmap = bm_load(NOX("DebriefText01"));
2384 Rank_text_bitmap = bm_load(NOX("DebriefText02"));
2385 Badge_text_bitmap = bm_load(NOX("DebriefText03"));
2388 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2389 // MUST store goals and events first - may be used to evaluate next mission
2390 // store goals and events
2391 mission_campaign_store_goals_and_events();
2393 // evaluate next mission
2394 mission_campaign_eval_next_mission();
2397 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2399 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2400 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2403 // call scoring level close for my stats. Needed for award_init. The stats will
2404 // be backed out if used chooses to replace them.
2405 scoring_level_close();
2407 debrief_ui_init(); // init UI items
2408 debrief_award_init();
2410 debrief_voice_init();
2411 debrief_multi_list_init();
2412 // rank_bitmaps_clear();
2413 // rank_bitmaps_load();
2415 strcpy(Debrief_current_callsign, Player->callsign);
2416 Debrief_player = Player;
2417 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2419 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2420 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2421 // info directly from the server.
2422 if ( !MULTIPLAYER_CLIENT ) {
2423 debrief_set_stages_and_multi_stuff();
2425 if ( Num_debrief_stages <= 0 ) {
2426 Num_debrief_stages = 0;
2428 debrief_voice_load_all();
2431 // multiplayer client may have already received their debriefing info. If they have not,
2432 // then set the num debrief stages to 0
2433 if ( !Debrief_multi_stages_loaded ) {
2434 Num_debrief_stages = 0;
2439 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2440 common_music_init(SCORE_DEBRIEF_SUCCESS);
2442 common_music_init(SCORE_DEBRIEF_FAIL);
2446 // start up the appropriate music
2447 if (Campaign.next_mission == Campaign.current_mission) {
2448 // you failed the mission because you suck, so you get the suck music
2449 common_music_init(SCORE_DEBRIEF_FAIL);
2450 } else if (mission_goals_met()) {
2451 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2452 common_music_init(SCORE_DEBRIEF_SUCCESS);
2454 // you somehow passed the mission, so you get a little something for your efforts.
2455 common_music_init(SCORE_DEBRIEF_AVERAGE);
2458 if (Campaign.next_mission == Campaign.current_mission) {
2459 // better luck next time, increase his retries
2460 Player->failures_this_session++;
2462 // clear his retries info regardless of whether or not he accepts
2463 Player->failures_this_session = 0;
2466 if (Game_mode & GM_MULTIPLAYER) {
2467 multi_debrief_init();
2469 // if i'm not the host of the game, disable the multi kick button
2470 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2471 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2474 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2475 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2476 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2477 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2478 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2479 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2480 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2481 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2484 if (!Award_active) {
2485 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2486 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2489 Debrief_skip_popup_already_shown = 0;
2494 // --------------------------------------------------------------------------------------
2496 void debrief_close()
2500 Assert(Debrief_inited);
2502 // if the mission wasn't accepted, clear out my stats
2503 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2504 // are a little bit different
2505 if (Game_mode & GM_MULTIPLAYER) {
2506 // if stats weren't accepted, backout my own stats
2507 if (multi_debrief_stats_accept_code() != 1) {
2508 if(MULTIPLAYER_MASTER){
2509 for(idx=0; idx<MAX_PLAYERS; idx++){
2510 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2511 scoring_backout_accept(&Net_players[idx].player->stats);
2515 scoring_backout_accept( &Player->stats );
2520 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2521 scoring_backout_accept( &Player->stats );
2525 // if dude passed the misson and accepted, reset his show skip popup flag
2526 if (Debrief_accepted) {
2527 Player->show_skip_popup = 1;
2530 if (Num_debrief_lines) {
2531 for (i=0; i<Num_debrief_lines; i++){
2538 // unload the overlay bitmap
2540 help_overlay_unload(DEBRIEFING_OVERLAY);
2543 // clear out award text
2544 Debrief_award_text_num_lines = 0;
2546 debrief_voice_unload_all();
2547 common_music_close();
2550 // rank_bitmaps_release();
2553 if (Background_bitmap >= 0){
2554 bm_unload(Background_bitmap);
2557 if (Award_bg_bitmap >= 0){
2558 bm_unload(Award_bg_bitmap);
2561 if (Rank_bitmap >= 0){
2562 bm_unload(Rank_bitmap);
2565 if (Medal_bitmap >= 0){
2566 bm_unload(Medal_bitmap);
2569 if (Badge_bitmap >= 0){
2570 bm_unload(Badge_bitmap);
2573 if (Wings_bitmap >= 0) {
2574 bm_unload(Wings_bitmap);
2577 if (Crest_bitmap >= 0) {
2578 bm_unload(Crest_bitmap);
2582 if (Medal_text_bitmap >= 0) {
2583 bm_unload(Medal_text_bitmap);
2586 if (Badge_text_bitmap >= 0) {
2587 bm_unload(Badge_text_bitmap);
2590 if (Rank_text_bitmap >= 0) {
2591 bm_unload(Rank_text_bitmap);
2595 Debrief_ui_window.destroy();
2596 common_free_interface_palette(); // restore game palette
2599 if (Game_mode & GM_MULTIPLAYER){
2600 multi_debrief_close();
2608 // handle keypresses in debriefing
2609 void debrief_do_keys(int new_k)
2616 case KEY_SHIFTED | KEY_TAB:
2624 // multiplayer accept popup is a little bit different
2625 if (Game_mode & GM_MULTIPLAYER) {
2626 multi_debrief_esc_hit();
2628 // display the normal debrief popup
2630 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2631 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2632 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2633 if (choice == 1) { // accept and continue on
2635 gameseq_post_event(GS_EVENT_MAIN_MENU);
2641 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2642 // need to popup saying that mission was a failure and must be replayed
2643 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));
2648 // Return to Main Hall
2649 gameseq_post_event(GS_EVENT_END_GAME);
2660 void debrief_draw_award_text()
2662 int start_y, curr_y, i, x, sw;
2663 int fh = gr_get_font_height();
2664 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];
2666 // vertically centered within field
2667 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);
2671 for (i=0; i<Debrief_award_text_num_lines; i++) {
2672 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2673 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2674 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2675 gr_set_color_fast(&Color_white);
2676 gr_string(x, curr_y, Debrief_award_text[i]);
2678 // adjust y pos, including a little extra between the "pairs"
2680 if ((i == 1) || (i == 3)) {
2681 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2686 // clears out text array so we dont have old award text showing up on new awards.
2687 void debrief_award_text_clear() {
2690 Debrief_award_text_num_lines = 0;
2691 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2692 //Debrief_award_text[i][0] = 0;
2693 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2697 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2698 void debrief_add_award_text(char *str)
2700 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2701 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2706 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];
2709 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2711 // maybe translate for displaying
2713 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2714 } else if (Lcl_pl) {
2715 medals_translate_name_pl(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2718 Debrief_award_text_num_lines++;
2720 // if its too long, split once ONLY
2721 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2722 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2723 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2724 if (line2 != NULL) {
2725 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2727 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2730 #endif // !MAKE_FS1: No text for FS1, it's all bitmaps
2732 // called once per frame to drive all the input reading and rendering
2733 void debrief_do_frame(float frametime)
2736 char *please_wait_str = XSTR("Please Wait", 1242);
2740 Assert(Debrief_inited);
2742 // first thing is to load the files
2743 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2744 // draw the background, etc
2745 GR_MAYBE_CLEAR_RES(Background_bitmap);
2746 if (Background_bitmap >= 0) {
2747 gr_set_bitmap(Background_bitmap);
2751 Debrief_ui_window.draw();
2753 if ( Debrief_multi_loading_bitmap > -1 ){
2754 gr_set_bitmap(Debrief_multi_loading_bitmap);
2755 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2758 // draw "Please Wait"
2759 gr_set_color_fast(&Color_normal);
2761 gr_get_string_size(&str_w, &str_h, please_wait_str);
2762 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2767 // make sure we run the debrief do frame
2768 if (Game_mode & GM_MULTIPLAYER) {
2769 multi_debrief_do_frame();
2774 int keypress = game_check_key();
2775 if(keypress == KEY_ESC){
2777 multi_quit_game(PROMPT_CLIENT);
2783 // if multiplayer client, and not loaded voice, then load it
2784 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2785 debrief_multi_fixup_stages();
2786 debrief_voice_load_all();
2787 Debrief_multi_voice_loaded = 1;
2790 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2791 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2792 Debrief_ui_window.set_ignore_gadgets(1);
2795 k = chatbox_process();
2796 if ( Game_mode & GM_NORMAL ) {
2797 new_k = Debrief_ui_window.process(k);
2799 new_k = Debrief_ui_window.process(k, 0);
2802 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2803 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2804 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2805 Debrief_ui_window.set_ignore_gadgets(0);
2811 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2812 Debrief_ui_window.set_ignore_gadgets(0);
2815 // don't show pilot info popup by default
2816 Debrief_should_show_popup = 0;
2818 // see if the mode has changed and handle it if so.
2819 if ( Current_mode != New_mode ) {
2820 debrief_voice_stop();
2821 Current_mode = New_mode;
2824 if (New_mode == DEBRIEF_TAB) {
2826 Debrief_cue_voice = 0;
2828 if (Debrief_first_voice_flag) {
2829 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2830 Debrief_first_voice_flag = 0;
2833 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2837 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2838 Current_stage = New_stage;
2839 debrief_text_init();
2842 debrief_voice_play();
2845 if (Game_mode & GM_MULTIPLAYER) {
2846 multi_debrief_do_frame();
2849 // Now do all the rendering for the frame
2850 GR_MAYBE_CLEAR_RES(Background_bitmap);
2851 if (Background_bitmap >= 0) {
2852 gr_set_bitmap(Background_bitmap);
2856 // draw the damn awarded stuff, G
2857 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2858 gr_set_bitmap(Award_bg_bitmap);
2859 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2860 if (Rank_bitmap >= 0) {
2861 gr_set_bitmap(Rank_bitmap);
2863 gr_bitmap(Debrief_rank_coords[0], Debrief_rank_coords[1]);
2865 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2869 if (Medal_bitmap >= 0) {
2870 gr_set_bitmap(Medal_bitmap);
2871 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2874 if (Badge_bitmap >= 0) {
2875 gr_set_bitmap(Badge_bitmap);
2877 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2879 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2883 if (Wings_bitmap >= 0) {
2884 gr_set_bitmap(Wings_bitmap);
2886 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2888 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2892 // this isn't used in FS1 but doesn't hurt to leave it
2893 if (Crest_bitmap >= 0) {
2894 gr_set_bitmap(Crest_bitmap);
2895 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2898 // draw medal/badge/rank labels
2900 debrief_draw_award_text();
2902 if (Rank_text_bitmap >= 0) {
2903 gr_set_bitmap(Rank_text_bitmap);
2904 gr_bitmap(Debrief_rank_text_coords[gr_screen.res][0], Debrief_rank_text_coords[gr_screen.res][1]);
2907 if (Medal_text_bitmap >= 0) {
2908 gr_set_bitmap(Medal_text_bitmap);
2909 gr_bitmap(Debrief_medal_text_coords[gr_screen.res][0], Debrief_medal_text_coords[gr_screen.res][1]);
2912 if (Badge_text_bitmap >= 0) {
2913 gr_set_bitmap(Badge_text_bitmap);
2914 gr_bitmap(Debrief_badge_text_coords[gr_screen.res][0], Debrief_badge_text_coords[gr_screen.res][1]);
2919 Debrief_ui_window.draw();
2920 debrief_redraw_pressed_buttons();
2921 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2922 if (Recommend_active && (Current_mode != STATS_TAB)) {
2923 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2926 // draw the title of the mission
2927 gr_set_color_fast(&Color_bright_white);
2928 strcpy(buf, The_mission.name);
2929 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2930 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2932 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2933 gr_set_color_fast(&Color_normal);
2934 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);
2937 // draw the screen-specific text
2938 switch (Current_mode) {
2940 if ( Num_debrief_stages <= 0 ) {
2941 gr_set_color_fast(&Color_white);
2942 Assert( Game_current_mission_filename != NULL );
2943 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);
2952 debrief_stats_render();
2956 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2959 gr_set_color_fast(&Color_red);
2960 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2961 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));
2964 debrief_render_stagenum();
2965 debrief_multi_list_draw();
2967 // render some extra stuff in multiplayer
2968 if (Game_mode & GM_MULTIPLAYER) {
2969 // render the chatbox last
2973 Debrief_ui_window.draw_tooltip();
2975 // render the status indicator for the voice system
2976 multi_common_voice_display_status();
2979 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2980 // want to include the mouse pointer which is drawn in the flip
2982 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2983 debrief_check_buttons();
2984 debrief_do_keys(new_k);
2987 // blit help overlay if active
2988 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2992 // dont let dude skip 3-09. hack.
2993 if(Game_mode & GM_CAMPAIGN_MODE){
2994 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2995 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2996 Debrief_skip_popup_already_shown = 1;
3001 // maybe show skip mission popup
3002 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)) {
3003 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
3004 XSTR("Advance To The Next Mission", 1474),
3005 XSTR("Don't Show Me This Again", 1475),
3006 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
3007 switch (popup_choice) {
3009 // stay on this mission, so proceed to normal debrief
3010 // in other words, do nothing.
3013 // skip this mission
3014 mission_campaign_skip_to_next();
3015 gameseq_post_event(GS_EVENT_START_GAME);
3018 // dont show this again
3019 Player->show_skip_popup = 0;
3023 Debrief_skip_popup_already_shown = 1;
3026 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
3027 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
3028 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
3029 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
3031 Debrief_should_show_popup = 0;
3035 void debrief_rebuild_player_list()
3039 debrief_multi_list_info *list;
3041 Multi_list_size = 0; // number of net players to choose from
3043 for ( i=0; i<MAX_PLAYERS; i++ ) {
3044 np = &Net_players[i];
3045 // remember not to include the standalone.
3046 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
3047 list = &Multi_list[Multi_list_size++];
3048 list->net_player_index = i;
3049 strcpy(list->callsign, np->player->callsign);
3051 // make sure to leave some room to blit the team indicator
3052 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
3057 void debrief_handle_player_drop()
3059 debrief_rebuild_player_list();
3062 void debrief_disable_accept()