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.8 2003/06/03 04:00:40 taylor
19 * Polish language support (Janusz Dziemidowicz)
21 * Revision 1.7 2003/05/25 02:30:43 taylor
24 * Revision 1.6 2002/07/13 06:46:48 theoddone33
27 * Revision 1.5 2002/06/09 04:41:23 relnev
28 * added copyright header
30 * Revision 1.4 2002/06/02 04:26:34 relnev
33 * Revision 1.3 2002/05/26 22:06:17 relnev
34 * makefile: disable stand_gui for now.
36 * rest: staticize some globals
38 * Revision 1.2 2002/05/07 03:16:46 theoddone33
39 * The Great Newline Fix
41 * Revision 1.1.1.1 2002/05/03 03:28:10 root
45 * 57 10/29/99 10:40p Jefff
46 * hack to make german medal names display without actually changing them
48 * 56 10/13/99 3:26p Jefff
49 * fixed unnumbered XSTRs
51 * 55 10/06/99 10:28a Jefff
54 * 54 9/30/99 5:57p Jefff
55 * show upsell at end of campaign in OEM builds
57 * 53 9/15/99 3:42a Jefff
60 * 52 9/14/99 4:35a Dave
61 * Argh. Added all kinds of code to handle potential crashes in debriefing
64 * 51 9/14/99 3:26a Dave
65 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
66 * respawn-too-early problem. Made a few crash points safe.
68 * 50 9/14/99 12:51a Jefff
70 * 49 9/13/99 6:01p Jefff
71 * fixed wrong promotion voice mapping for sm1-08
73 * 48 9/13/99 11:15a Jefff
74 * clear out award text bug fixed
76 * 47 9/13/99 12:17p Andsager
77 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
80 * 46 9/07/99 9:35p Jefff
81 * fixed bug where award text was not getting cleared properly between
84 * 45 9/07/99 6:56p Jefff
85 * a few adjustments to loop detection
87 * 44 9/07/99 1:54p Jefff
88 * skip mission cleanup
90 * 43 9/06/99 9:45p Jefff
91 * skip mission support
93 * 42 9/06/99 6:38p Dave
94 * Improved CD detection code.
96 * 41 9/03/99 1:32a Dave
97 * CD checking by act. Added support to play 2 cutscenes in a row
98 * seamlessly. Fixed super low level cfile bug related to files in the
99 * root directory of a CD. Added cheat code to set campaign mission # in
102 * 40 9/02/99 3:45p Jefff
103 * forgot to remove some debug code. doh.
105 * 39 9/02/99 3:41p Jefff
106 * changed badge voice handling to be similar to promotion voice handling
108 * 38 9/01/99 4:41p Jefff
109 * fixed stoopid text color bug
111 * 37 8/31/99 11:54a Jefff
112 * minor debrief music tweak
114 * 36 8/27/99 9:57a Dave
115 * Enabled standard cheat codes. Allow player to continue in a campaing
116 * after using cheat codes.
118 * 35 8/27/99 12:04a Dave
119 * Campaign loop screen.
121 * 34 8/26/99 8:49p Jefff
122 * Updated medals screen and about everything that ever touches medals in
123 * one way or another. Sheesh.
125 * 33 8/20/99 4:20p Jefff
126 * hack for choosing the correct promotion voice
128 * 32 8/16/99 4:05p Dave
129 * Big honking checkin.
131 * 31 8/16/99 9:49a Jefff
132 * mission title length fix in multi
134 * 30 8/11/99 5:33p Jefff
135 * added 3rd debrief music track
137 * 29 8/10/99 7:28p Jefff
138 * shuffled some text around
140 * 28 8/04/99 5:36p Andsager
141 * Show upsell screens at end of demo campaign before returning to main
144 * 27 8/04/99 2:07p Jefff
145 * mission title no longer overwrites popup
147 * 26 8/02/99 5:37p Jefff
149 * 25 8/02/99 4:52p Jefff
150 * negative feedback sound when recommendations button pressed and
153 * 24 7/21/99 6:21p Jefff
154 * added hotkeys to the "you cannot accept" popup
156 * 23 6/15/99 12:04p Anoop
157 * Added a warning for running out of debrief text lines.
159 * 22 6/09/99 2:17p Dave
160 * Fixed up pleasewait bitmap rendering.
162 * 21 6/01/99 6:07p Dave
163 * New loading/pause/please wait bar.
165 * 20 5/22/99 6:05p Dave
166 * Fixed a few localization # problems.
168 * 19 5/22/99 5:35p Dave
169 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
171 * 18 3/20/99 3:47p Andsager
172 * Fix crash with no mission loop description.
174 * 17 2/23/99 2:29p Dave
175 * First run of oldschool dogfight mode.
177 * 16 2/21/99 6:01p Dave
178 * Fixed standalone WSS packets.
180 * 15 2/11/99 3:08p Dave
181 * PXO refresh button. Very preliminary squad war support.
183 * 14 1/30/99 5:08p Dave
184 * More new hi-res stuff.Support for nice D3D textures.
186 * 13 1/29/99 2:08a Dave
187 * Fixed beam weapon collisions with players. Reduced size of scoring
188 * struct for multiplayer. Disabled PXO.
190 * 12 1/14/99 5:15p Neilk
191 * changed credits, command debrief interfaces to high resolution support
193 * 11 1/13/99 2:11p Andsager
194 * change default debriefing string text
196 * 10 12/17/98 4:50p Andsager
197 * Added debrief_assemble_optional_mission_popup_text() for single and
200 * 9 12/12/98 3:17p Andsager
201 * Clean up mission eval, goal, event and mission scoring.
203 * 8 12/10/98 10:19a Andsager
204 * Fix mission loop assert
206 * 7 12/10/98 9:59a Andsager
207 * Fix some bugs with mission loops
209 * 6 12/09/98 1:56p Andsager
210 * Initial checkin of mission loop
212 * 5 11/05/98 4:18p Dave
213 * First run nebula support. Beefed up localization a bit. Removed all
214 * conditional compiles for foreign versions. Modified mission file
217 * 4 10/23/98 3:51p Dave
218 * Full support for tstrings.tbl and foreign languages. All that remains
219 * is to make it active in Fred.
221 * 3 10/13/98 9:28a Dave
222 * Started neatening up freespace.h. Many variables renamed and
223 * reorganized. Added AlphaColors.[h,cpp]
225 * 2 10/07/98 10:53a Dave
228 * 1 10/07/98 10:49a Dave
230 * 178 9/17/98 3:08p Dave
231 * PXO to non-pxo game warning popup. Player icon stuff in create and join
232 * game screens. Upped server count refresh time in PXO to 35 secs (from
235 * 177 7/07/98 1:46p Dave
236 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
239 * 175 6/09/98 10:31a Hoffoss
240 * Created index numbers for all xstr() references. Any new xstr() stuff
241 * added from here on out should be added to the end if the list. The
242 * current list count can be found in FreeSpace.cpp (search for
245 * 174 6/07/98 3:26p Lawrance
246 * Fix bug with cut-off popup text
248 * 173 6/05/98 9:54a Lawrance
251 * 172 6/01/98 11:43a John
252 * JAS & MK: Classified all strings for localization.
254 * 171 5/27/98 1:24p Allender
255 * make targeting dots work (as well as other targeting features) properly
256 * in multiplayer. Don't query for CD when entering debrief in
259 * 170 5/26/98 11:10a Lawrance
260 * Fix bug where window controls get disabled when F1 pressed twice
262 * 169 5/24/98 12:55a Mike
263 * Prevent Assert() when no debriefing text for a stage.
265 * 168 5/23/98 10:38p Lawrance
266 * Avoid doing a cfile refresh when running debug
268 * 167 5/23/98 6:49p Lawrance
269 * Fix problems with refreshing the file list when a CD is inserted
271 * 166 5/21/98 6:57p Lawrance
272 * Don't prompt for the CD if voice not found
274 * 165 5/20/98 2:24a Dave
275 * Fixed server side voice muting. Tweaked multi debrief/endgame
276 * sequencing a bit. Much friendlier for stats tossing/accepting now.
278 * 164 5/19/98 8:35p Dave
279 * Revamp PXO channel listing system. Send campaign goals/events to
280 * clients for evaluation. Made lock button pressable on all screens.
282 * 163 5/19/98 11:13a Hoffoss
283 * Fixed bug where wrong wings award was being displayed in debriefing.
285 * 162 5/19/98 12:28a Mike
288 * 161 5/18/98 8:08p Hoffoss
289 * Moved placement of 'More' text.
291 * 160 5/18/98 3:50p Dan
292 * AL: Pick correct traitor debriefing voice file
294 * 159 5/17/98 6:32p Dave
295 * Make sure clients/servers aren't kicked out of the debriefing when team
296 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
297 * xfer/pilot info popup stuff.
299 * 158 5/16/98 9:14p Allender
300 * fix scoring ckise fir training missions to actually count medals, but
301 * nothing else. Code used to Assert when wings were granted then taken
302 * away because they were actually never granted in scoring structure
304 * 157 5/15/98 5:15p Dave
305 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
306 * status for team vs. team. Put in asserts to check for invalid team vs.
309 * 156 5/15/98 4:36p Allender
310 * fixed minor bug with wings
312 * 155 5/15/98 4:12p Allender
313 * removed redbook code. Put back in ingame join timer. Major fixups for
314 * stats in multiplayer. Pass correct score, medals, etc when leaving
315 * game. Be sure clients display medals, badges, etc.
317 * 154 5/15/98 2:25p Jasen
318 * temporarily disable granting of promotion and badges for clients
320 * 153 5/15/98 10:57a Allender
321 * fixed client side debriefings
323 * 152 5/15/98 10:36a Dave
324 * Removed 2 bogus bitmap drawing Int3()'s
326 * 151 5/14/98 2:44p Hoffoss
327 * Added wings awarding to debrief screen.
329 * 150 5/13/98 9:11p Lawrance
330 * Make 'replay mission' popup warn users about the loss of mission stats.
335 #include "missiondebrief.h"
336 #include "missionbriefcommon.h"
337 #include "missionscreencommon.h"
338 #include "missiongoals.h"
339 #include "missionpause.h"
340 #include "freespace.h"
341 #include "gamesequence.h"
349 #include "audiostr.h"
352 #include "contexthelp.h"
358 #include "multimsgs.h"
359 #include "multiutil.h"
360 #include "multiteamselect.h"
362 #include "eventmusic.h"
366 #include "multi_pinfo.h"
367 #include "contexthelp.h"
368 #include "multi_kick.h"
369 #include "multi_campaign.h"
370 #include "alphacolors.h"
371 #include "localize.h"
372 #include "multi_endgame.h"
375 #define MAX_TOTAL_DEBRIEF_LINES 200
377 #define TEXT_TYPE_NORMAL 1
378 #define TEXT_TYPE_RECOMMENDATION 2
380 #define DEBRIEF_NUM_STATS_PAGES 4
381 #define DEBRIEF_MISSION_STATS 0
382 #define DEBRIEF_MISSION_KILLS 1
383 #define DEBRIEF_ALLTIME_STATS 2
384 #define DEBRIEF_ALLTIME_KILLS 3
386 // 3rd coord is max width in pixels
387 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
400 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
413 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
418 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
431 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
444 #define MULTI_LIST_TEAM_OFFSET 16
446 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
451 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
460 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
473 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
487 int Debrief_rank_coords[2] = {
491 int Debrief_badge_coords[2] = {
497 // 0=x, 1=y, 2=width of the field
498 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
507 // 0=x, 1=y, 2=height of the field
508 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
517 // the medal text in FS1 is a bitmap
518 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][2] = {
527 int Debrief_rank_text_coords[GR_NUM_RESOLUTIONS][2] = {
536 int Debrief_badge_text_coords[GR_NUM_RESOLUTIONS][2] = {
547 // 1 = without medal (text will use medal space)
548 #define DB_WITH_MEDAL 0
549 #define DB_WITHOUT_MEDAL 1
550 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
559 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
560 "DebriefSingle", // GR_640
561 "2_DebriefSingle" // GR_1024
563 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
564 "DebriefMulti", // GR_640
565 "2_DebriefMulti" // GR_1024
567 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
568 "Debrief-m", // GR_640
569 "2_Debrief-m" // GR_1024
572 #define NUM_BUTTONS 18
575 #define DEBRIEF_TAB 0
577 #define TEXT_SCROLL_UP 2
578 #define TEXT_SCROLL_DOWN 3
579 #define REPLAY_MISSION 4
580 #define RECOMMENDATIONS 5
581 #define FIRST_STAGE 6
585 #define MULTI_PINFO_POPUP 10
586 #define MULTI_KICK 11
587 #define MEDALS_BUTTON 12
588 #define PLAYER_SCROLL_UP 13
589 #define PLAYER_SCROLL_DOWN 14
590 #define HELP_BUTTON 15
591 #define OPTIONS_BUTTON 16
592 #define ACCEPT_BUTTON 17
597 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
598 "PleaseWait", // GR_640
599 "2_PleaseWait" // GR_1024
605 char text[NAME_LENGTH+1]; // name of ship type with a colon
606 int num; // how many ships of this type player has killed
607 } debrief_stats_kill_info;
610 int net_player_index; // index into Net_players[] array
611 int rank_bitmap; // bitmap id for rank
612 char callsign[CALLSIGN_LEN];
613 } debrief_multi_list_info;
615 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
618 ui_button_info("DB_00", 0, 2, -1, -1, 0), // debriefing
619 ui_button_info("DB_01", 0, 20, -1, -1, 1), // statistics
620 ui_button_info("DB_02", 0, 195, -1, -1, 2), // scroll stats up
621 ui_button_info("DB_03", 0, 232, -1, -1, 3), // scroll stats down
622 ui_button_info("DB_04", 24, 424, -1, -1, 4), // replay mission
623 ui_button_info("DB_05", 30, 451, -1, -1, 5), // recommendations
624 ui_button_info("DB_06", 211, 445, -1, -1, 6), // first page
625 ui_button_info("DB_07", 234, 445, -1, -1, 7), // prev page
626 ui_button_info("DB_08", 259, 445, -1, -1, 8), // next page
627 ui_button_info("DB_09", 283, 445, -1, -1, 9), // last page
628 ui_button_info("DB_21", 441, 384, -1, -1, 21), // pilot info
629 ui_button_info("DB_25", 511, 384, -1, -1, 25), // kick
630 ui_button_info("DB_15", 604, 224, -1, -1, 15), // medals
631 ui_button_info("DB_16", 615, 329, -1, -1, 16), // scroll pilots up
632 ui_button_info("DB_17", 615, 371, -1, -1, 17), // scroll pilots down
633 ui_button_info("DB_10", 469, 428, -1, -1, 10), // help
634 ui_button_info("DB_11", 447, 452, -1, -1, 11), // options
635 ui_button_info("DB_12", 562, 410, -1, -1, 12), // accept
637 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
638 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
639 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
640 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
641 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
642 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
643 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
644 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
645 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
646 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
647 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
648 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
649 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
650 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
651 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
652 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
653 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
654 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
658 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
659 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
660 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
661 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
662 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
663 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
664 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
665 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
666 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
667 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
668 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
669 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
670 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
671 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
672 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
673 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
674 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
675 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
681 #define NUM_DEBRIEF_TEXT 0
683 #define NUM_DEBRIEF_TEXT 10
685 #define MP_TEXT_INDEX_1 4
686 #define MP_TEXT_INDEX_2 5
687 #define MP_TEXT_INDEX_3 6
688 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
690 // not needed for FS1
692 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
693 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
694 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
695 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
696 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
697 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
698 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
699 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
700 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
701 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
705 // not needed for FS1
707 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
708 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
709 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
710 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
711 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
712 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
713 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
714 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
715 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
716 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
722 char Debrief_current_callsign[CALLSIGN_LEN+10];
723 player *Debrief_player;
725 static UI_WINDOW Debrief_ui_window;
726 static UI_BUTTON List_region;
727 static int Background_bitmap; // bitmap for the background of the debriefing
728 static int Award_bg_bitmap;
729 static int Debrief_multi_loading_bitmap;
730 static int Rank_bitmap;
731 static int Medal_bitmap;
732 static int Badge_bitmap;
733 static int Wings_bitmap;
734 static int Crest_bitmap;
736 static int Rank_text_bitmap;
737 static int Medal_text_bitmap;
738 static int Badge_text_bitmap;
741 static int Debrief_accepted;
742 static int Turned_traitor;
743 static int Must_replay_mission;
745 static int Current_mode;
747 static int Recommend_active;
748 static int Award_active;
749 static int Text_offset;
750 static int Num_text_lines = 0;
751 static int Num_debrief_lines = 0;
752 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
753 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
755 static int Debrief_inited = 0;
756 static int New_stage;
757 static int Current_stage;
758 static int Num_stages;
759 static int Num_debrief_stages;
760 static int Stage_voice;
762 static int Multi_list_size;
763 static int Multi_list_offset;
765 int Debrief_multi_stages_loaded = 0;
766 int Debrief_multi_voice_loaded = 0;
768 // static int Debrief_voice_ask_for_cd;
770 // voice id's for debriefing text
771 static int Debrief_voices[MAX_DEBRIEF_STAGES];
773 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
774 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
775 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
777 // pointer used for getting to debriefing information
778 debriefing Traitor_debriefing; // used when player is a traitor
780 // pointers to the active stages for this debriefing
781 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
782 static debrief_stage Promotion_stage, Badge_stage;
783 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
784 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
785 int Multi_list_select;
787 // flag indicating if we should display info for the given player (in multiplayer)
788 int Debrief_should_show_popup = 1;
790 // already shown skip mission popup?
791 static int Debrief_skip_popup_already_shown = 0;
793 void debrief_text_init();
794 void debrief_accept(int ok_to_post_start_game_event = 1);
795 void debrief_kick_selected_player();
798 // promotion voice selection stuff
799 #define NUM_VOLITION_CAMPAIGNS 1
801 char campaign_name[32];
803 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
805 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
806 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
810 // data for which voice goes w/ which mission
811 typedef struct voice_map {
812 char mission_file[32];
816 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
817 { // FreeSpace2 campaign
849 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
851 { "loop1-1.fs2", 4 },
852 { "loop1-2.fs2", 4 },
853 { "loop1-3.fs2", 5 },
854 { "loop2-1.fs2", 4 },
859 #define DB_AWARD_WINGS 0
860 #define DB_AWARD_MEDAL 1
862 #define DB_AWARD_RANK 2
863 #define DB_AWARD_BADGE 3
864 #define DB_AWARD_BG 4
865 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][5] = {
882 #define DB_AWARD_SOC 2
883 #define DB_AWARD_RANK 3
884 #define DB_AWARD_BADGE 4
885 #define DB_AWARD_BG 5
886 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
906 #define AWARD_TEXT_MAX_LINES 5
907 #define AWARD_TEXT_MAX_LINE_LENGTH 128
908 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
909 int Debrief_award_text_num_lines = 0;
913 // prototypes, you know you love 'em
914 void debrief_add_award_text(char *str);
915 void debrief_award_text_clear();
920 char *debrief_tooltip_handler(char *str)
922 if (!stricmp(str, NOX("@.Medal"))) {
924 return XSTR( "Medal", 435);
927 } else if (!stricmp(str, NOX("@.Rank"))) {
929 return XSTR( "Rank", 436);
932 } else if (!stricmp(str, NOX("@.Badge"))) {
934 return XSTR( "Badge", 437);
937 } else if (!stricmp(str, NOX("@Medal"))) {
938 if (Medal_bitmap >= 0){
939 return Medals[Player->stats.m_medal_earned].name;
942 } else if (!stricmp(str, NOX("@Rank"))) {
943 if (Rank_bitmap >= 0){
944 return Ranks[Promoted].name;
947 } else if (!stricmp(str, NOX("@Badge"))) {
948 if (Badge_bitmap >= 0){
949 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
956 // initialize the array of handles to the different voice streams
957 void debrief_voice_init()
961 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
962 Debrief_voices[i] = -1;
966 void debrief_load_voice_file(int voice_num, char *name)
968 int load_attempts = 0;
971 if ( load_attempts++ > 5 ) {
975 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
976 if ( Debrief_voices[voice_num] >= 0 ) {
980 // Don't bother to ask for the CD in multiplayer
981 if ( Game_mode & GM_MULTIPLAYER ) {
985 // couldn't load voice, ask user to insert CD (if necessary)
987 // if ( Debrief_voice_ask_for_cd ) {
988 // if ( game_do_cd_check() == 0 ) {
989 // Debrief_voice_ask_for_cd = 0;
996 // open and pre-load the stream buffers for the different voice streams
997 void debrief_voice_load_all()
1001 // Debrief_voice_ask_for_cd = 1;
1003 for ( i=0; i<Num_debrief_stages; i++ ) {
1004 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
1007 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
1008 debrief_load_voice_file(i, Debrief_stages[i]->voice);
1009 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
1014 // close all the briefing voice streams
1015 void debrief_voice_unload_all()
1019 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
1020 if ( Debrief_voices[i] != -1 ) {
1021 audiostream_close_file(Debrief_voices[i], 0);
1022 Debrief_voices[i] = -1;
1027 // start playback of the voice for a particular briefing stage
1028 void debrief_voice_play()
1030 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
1034 // no more stages? We are done then.
1035 if (Stage_voice >= Num_debrief_stages){
1039 // if in delayed start, see if delay has elapsed and start voice if so
1040 if (Debrief_cue_voice) {
1041 if (!timestamp_elapsed(Debrief_cue_voice)){
1045 Stage_voice++; // move up to next voice
1046 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
1047 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
1048 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
1054 // see if voice is still playing. If so, do nothing yet.
1055 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
1059 // set voice to play in a little while from now.
1060 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
1063 // stop playback of the voice for a particular briefing stage
1064 void debrief_voice_stop()
1066 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
1069 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
1073 // function to deal with inserting possible promition and badge stages into the debriefing
1075 void debrief_multi_fixup_stages()
1079 // possibly insert the badge stage first, them the promotion stage since they are
1080 // inserted at the front of the debrief stages.
1081 if ( Badge_bitmap >= 0 ) {
1082 // move all stages forward one. Don't
1083 for ( i = Num_debrief_stages; i > 0; i-- ) {
1084 Debrief_stages[i] = Debrief_stages[i-1];
1086 Debrief_stages[0] = &Badge_stage;
1087 Num_debrief_stages++;
1090 if ( Promoted >= 0) {
1091 // move all stages forward one
1092 for ( i = Num_debrief_stages; i > 0; i-- ) {
1093 Debrief_stages[i] = Debrief_stages[i-1];
1095 Debrief_stages[0] = &Promotion_stage;
1096 Num_debrief_stages++;
1101 // function called from multiplayer clients to set up the debriefing information for them
1102 // (sent from the server).
1103 void debrief_set_multi_clients( int stage_count, int active_stages[] )
1107 // set up the right briefing for this guy
1108 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
1109 Debriefing = &Debriefings[Net_player->p_info.team];
1111 Debriefing = &Debriefings[0];
1114 // see if this client was promoted -- if so, then add the first stage.
1115 Num_debrief_stages = 0;
1117 // set the pointers to the debriefings for this client
1118 for (i = 0; i < stage_count; i++) {
1119 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
1122 Debrief_multi_stages_loaded = 1;
1125 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
1126 // information to all clients after leaving this screen.
1127 void debrief_multi_server_stuff()
1129 debriefing *debriefp;
1131 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1132 int i, j, num_stages, stage_count[MAX_TEAMS];
1134 memset( stage_active, 0, sizeof(stage_active) );
1136 for (i=0; i<Num_teams; i++) {
1137 debriefp = &Debriefings[i];
1139 stages[i] = stage_active[i];
1140 for (j=0; j<debriefp->num_stages; j++) {
1141 if ( eval_sexp(debriefp->stages[j].formula) ) {
1142 stage_active[i][num_stages] = j;
1147 stage_count[i] = num_stages;
1150 // if we're in campaign mode, evaluate campaign stuff
1151 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1152 multi_campaign_eval_debrief();
1155 // send the information to all clients.
1156 send_debrief_info( stage_count, stages );
1160 // --------------------------------------------------------------------------------------
1161 // debrief_set_stages_and_multi_stuff()
1163 // Set up the active stages for this debriefing
1165 // returns: number of active debriefing stages
1167 int debrief_set_stages_and_multi_stuff()
1170 debriefing *debriefp;
1172 if ( MULTIPLAYER_CLIENT ) {
1176 Num_debrief_stages = 0;
1178 if ( Game_mode & GM_MULTIPLAYER ) {
1179 debrief_multi_server_stuff();
1182 // check to see if player is a traitor (looking at his team). If so, use the special
1183 // traitor debriefing. Only done in single player
1184 debriefp = Debriefing;
1185 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1186 if (Player_ship->team == TEAM_TRAITOR)
1187 debriefp = &Traitor_debriefing;
1190 Num_debrief_stages = 0;
1191 if (Promoted >= 0) {
1192 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1195 if (Badge_bitmap >= 0) {
1196 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1199 for (i=0; i<debriefp->num_stages; i++) {
1200 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1201 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1205 return Num_debrief_stages;
1208 // init the buttons that are specific to the debriefing screen
1209 void debrief_buttons_init()
1214 for ( i=0; i<NUM_BUTTONS; i++ ) {
1215 b = &Buttons[gr_screen.res][i];
1216 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1217 // set up callback for when a mouse first goes over a button
1218 b->button.set_highlight_action( common_play_highlight_sound );
1219 b->button.set_bmaps(b->filename);
1220 b->button.link_hotspot(b->hotspot);
1224 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1225 // multiplayer specific text
1226 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1227 // only add if in multiplayer mode
1228 if(Game_mode & GM_MULTIPLAYER){
1229 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1234 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1238 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1239 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1240 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1241 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1242 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1243 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1244 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1245 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1247 // if in multiplayer, disable the button for all players except the host
1248 // also disable for squad war matches
1249 if(Game_mode & GM_MULTIPLAYER){
1250 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1251 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1256 // --------------------------------------------------------------------------------------
1257 // debrief_ui_init()
1259 void debrief_ui_init()
1261 // init ship selection masks and buttons
1262 common_set_interface_palette("DebriefPalette"); // set the interface palette
1263 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1264 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1265 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1266 debrief_buttons_init();
1268 // load in help overlay bitmap
1269 help_overlay_load(DEBRIEFING_OVERLAY);
1270 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1272 if ( Game_mode & GM_MULTIPLAYER ) {
1273 // close down any old instances of the chatbox
1276 // create the new one
1278 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1279 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);
1282 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1285 if ( Background_bitmap < 0 ) {
1286 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1289 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1290 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1293 // sets Promotion_stage.voice
1294 // defaults to number 9 (Petrarch) for non-volition missions
1295 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1296 void debrief_choose_promotion_voice()
1300 if(Campaign.current_mission < 0){
1301 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1305 // search thru all official campaigns for our current campaign
1306 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1307 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1308 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1309 // now search thru the mission filenames,
1310 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1311 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1312 // found it! set the persona and bail
1313 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1321 // default to petrarch
1322 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1325 // sets Promotion_stage.voice
1326 // defaults to number 9 (Petrarch) for non-volition missions
1327 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1328 void debrief_choose_badge_voice()
1334 if(Campaign.current_mission < 0){
1336 // default to petrarch
1337 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1339 // default to FS1 guy
1340 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1344 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1346 if ( Player->on_bastion ) {
1347 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base2);
1350 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1354 // search thru all official campaigns for our current campaign
1355 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1356 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1357 // now search thru the mission filenames,
1358 for (j=0; j<Campaign.num_missions; j++) {
1359 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1360 // found it! set the persona and bail
1361 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1371 // default to petrarch
1372 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1374 // default to FS1 guy
1375 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1380 void debrief_award_init()
1392 // be sure there are no old award texts floating around
1394 debrief_award_text_clear();
1397 // handle medal earned
1398 if (Player->stats.m_medal_earned != -1) {
1399 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1401 if ( Player->stats.medals[13] > 1 ) {
1406 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1407 Wings_bitmap = bm_load(buf);
1409 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1410 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1413 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1414 Medal_bitmap = bm_load(buf);
1418 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1422 // handle promotions
1423 if ( Player->stats.m_promotion_earned != -1 ) {
1424 Promoted = Player->stats.m_promotion_earned;
1425 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1426 Rank_bitmap = bm_load(buf);
1428 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1429 Promotion_stage.new_recommendation_text = NULL;
1431 // choose appropriate promotion voice for this mission
1432 debrief_choose_promotion_voice();
1435 debrief_add_award_text(Ranks[Promoted].name);
1439 // handle badge earned
1440 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1441 if ( Player->stats.m_badge_earned != -1 ) {
1442 i = Player->stats.m_badge_earned;
1443 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1444 Badge_bitmap = bm_load(buf);
1446 Badge_stage.new_text = Badge_info[i].promotion_text;
1447 Badge_stage.new_recommendation_text = NULL;
1449 // choose appropriate voice
1450 debrief_choose_badge_voice();
1453 debrief_add_award_text(Medals[Badge_index[i]].name);
1457 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1464 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1465 // mission a traitor. The same debriefing always gets played
1466 void debrief_traitor_init()
1468 static int inited = 0;
1471 debriefing *debrief;
1472 debrief_stage *stagep;
1476 if ((rval = setjmp(parse_abort)) != 0) {
1477 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1480 read_file_text("traitor.tbl");
1484 // open localization
1487 // simplied form of the debriefing stuff.
1488 debrief = &Traitor_debriefing;
1489 required_string("#Debriefing_info");
1491 required_string("$Num stages:");
1492 stuff_int(&debrief->num_stages);
1493 Assert(debrief->num_stages == 1);
1496 stagep = &debrief->stages[stage_num++];
1497 required_string("$Formula:");
1498 stagep->formula = get_sexp_main();
1499 required_string("$multi text");
1500 if ( Fred_running ) {
1501 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1503 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1505 required_string("$Voice:");
1506 char traitor_voice_file[NAME_LENGTH];
1507 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1509 // DKA 9/13/99 Only 1 traitor msg for FS2
1511 if ( Player->on_bastion ) {
1512 strcpy(stagep->voice, NOX("3_"));
1514 strcpy(stagep->voice, NOX("1_"));
1518 strcat(stagep->voice, traitor_voice_file);
1520 required_string("$Recommendation text:");
1521 if ( Fred_running ) {
1522 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1524 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1528 // close localization
1532 // disable the accept button if in single player and I am a traitor
1533 Debrief_accepted = 0;
1534 Turned_traitor = Must_replay_mission = 0;
1535 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1536 if (Player_ship->team == TEAM_TRAITOR){
1540 if (Campaign.next_mission == Campaign.current_mission){
1541 Must_replay_mission = 1;
1545 if (Turned_traitor || Must_replay_mission) {
1546 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1548 // kill off any stats
1549 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1550 scoring_level_init( &Player->stats );
1554 // initialization for listing of players in game
1555 void debrief_multi_list_init()
1557 Multi_list_size = 0; // number of net players to choose from
1558 Multi_list_offset = 0;
1560 Multi_list_select = -1;
1562 if ( !(Game_mode & GM_MULTIPLAYER) )
1565 debrief_rebuild_player_list();
1567 // switch stats display to this newly selected player
1568 set_player_stats(Multi_list[0].net_player_index);
1569 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1570 Debrief_player = Player;
1573 void debrief_multi_list_scroll_up()
1575 // if we're at the beginning of the list, don't do anything
1576 if(Multi_list_offset == 0){
1577 gamesnd_play_iface(SND_GENERAL_FAIL);
1581 // otherwise scroll up
1582 Multi_list_offset--;
1583 gamesnd_play_iface(SND_USER_SELECT);
1586 void debrief_multi_list_scroll_down()
1588 // if we can scroll down no further
1589 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1590 gamesnd_play_iface(SND_GENERAL_FAIL);
1593 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1594 gamesnd_play_iface(SND_GENERAL_FAIL);
1598 // otherwise scroll down
1599 Multi_list_offset++;
1600 gamesnd_play_iface(SND_USER_SELECT);
1603 // draw the connected net players
1604 void debrief_multi_list_draw()
1606 int y, z, font_height,idx;
1607 char str[CALLSIGN_LEN+5];
1610 font_height = gr_get_font_height();
1612 // if we currently have no item picked, pick a reasonable one
1613 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1614 // select the entry which corresponds to the local player
1615 Multi_list_select = 0;
1616 for(idx=0;idx<Multi_list_size;idx++){
1617 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1618 Multi_list_select = idx;
1620 // switch stats display to this newly selected player
1621 set_player_stats(Multi_list[idx].net_player_index);
1622 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1623 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1629 // draw the list itself
1631 z = Multi_list_offset;
1632 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1633 np = &Net_players[Multi_list[z].net_player_index];
1635 if (z >= Multi_list_size){
1638 // set the proper text color for the highlight
1639 if(np->flags & NETINFO_FLAG_GAME_HOST){
1640 if(Multi_list_select == z){
1641 gr_set_color_fast(&Color_text_active_hi);
1643 gr_set_color_fast(&Color_bright);
1646 if(Multi_list_select == z){
1647 gr_set_color_fast(&Color_text_active);
1649 gr_set_color_fast(&Color_text_normal);
1653 // blit the proper indicator - skipping observers
1654 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1655 if(Netgame.type_flags & NG_TYPE_TEAM){
1657 if(np->p_info.team == 0){
1658 // draw his "selected" icon
1659 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1660 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1661 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1663 // draw his "normal" icon
1664 else if(Multi_common_icons[MICON_TEAM0] != -1){
1665 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1666 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1668 } else if(np->p_info.team == 1){
1669 // draw his "selected" icon
1670 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1671 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1672 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1674 // draw his "normal" icon
1675 else if(Multi_common_icons[MICON_TEAM1] != -1){
1676 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1677 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1681 // draw the team 0 selected icon
1682 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1683 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1684 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1689 strcpy(str,Multi_list[z].callsign);
1690 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)){
1691 strcat(str,XSTR( "(O)", 438));
1695 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1702 void debrief_kick_selected_player()
1704 if(Multi_list_select >= 0){
1705 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1706 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1710 // get optional mission popup text
1711 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1713 Assert(buffer != NULL);
1716 if (mission_loop_desc == NULL) {
1717 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1718 mprintf(("No mission loop description avail"));
1720 strcpy(buffer, mission_loop_desc);
1723 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1726 // what to do when the accept button is hit
1727 void debrief_accept(int ok_to_post_start_game_event)
1731 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1735 if (Game_mode & GM_MULTIPLAYER) {
1739 if (Player_ship->team == TEAM_TRAITOR){
1740 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1741 }/* else if (Cheats_enabled) {
1742 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1744 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1747 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1749 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1750 } else if ( z == 1 ) {
1751 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1757 Debrief_accepted = 1;
1758 // save mission stats
1759 if (Game_mode & GM_MULTIPLAYER) {
1760 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1761 // as well as doing stats transfers, etc.
1762 multi_debrief_accept_hit();
1766 int play_commit_sound = 1;
1767 // only write the player's stats if he's accepted
1769 // if we are just playing a single mission, then don't do many of the things
1770 // that need to be done. Nothing much should happen when just playing a single
1771 // mission that isn't in a campaign.
1772 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1774 // check for possible mission loop
1775 // check for (1) mission loop available, (2) dont have to repeat last mission
1776 if(!(Game_mode & GM_MULTIPLAYER)){
1777 int cur = Campaign.current_mission;
1778 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1779 if (Campaign.missions[cur].has_mission_loop) {
1780 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1783 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1786 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1788 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1790 Campaign.loop_enabled = 1;
1791 Campaign.next_mission = Campaign.loop_mission;
1800 if(ok_to_post_start_game_event){
1801 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1803 play_commit_sound = 0;
1806 // continue as normal
1809 mission_campaign_mission_over();
1811 // check to see if we are out of the loop now
1812 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1813 Campaign.loop_enabled = 0;
1816 // check if campaign is over
1817 if ( Campaign.next_mission == -1 ) {
1818 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
1819 gameseq_post_event(GS_EVENT_END_DEMO);
1821 gameseq_post_event(GS_EVENT_MAIN_MENU);
1824 if ( ok_to_post_start_game_event ) {
1826 if(game_do_cd_mission_check(Game_current_mission_filename)){
1827 gameseq_post_event(GS_EVENT_START_GAME);
1829 gameseq_post_event(GS_EVENT_MAIN_MENU);
1832 play_commit_sound = 0;
1837 gameseq_post_event(GS_EVENT_MAIN_MENU);
1840 if ( play_commit_sound ) {
1841 gamesnd_play_iface(SND_COMMIT_PRESSED);
1848 void debrief_next_tab()
1850 New_mode = Current_mode + 1;
1851 if (New_mode >= NUM_TABS)
1855 void debrief_prev_tab()
1857 New_mode = Current_mode - 1;
1859 New_mode = NUM_TABS - 1;
1862 // --------------------------------------------------------------------------------------
1863 // debrief_next_stage()
1865 void debrief_next_stage()
1867 if (Current_stage < Num_stages - 1) {
1868 New_stage = Current_stage + 1;
1869 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1872 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1875 // --------------------------------------------------------------------------------------
1876 // debrief_prev_stage()
1878 void debrief_prev_stage()
1880 if (Current_stage) {
1881 New_stage = Current_stage - 1;
1882 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1885 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1888 // --------------------------------------------------------------------------------------
1889 // debrief_first_stage()
1890 void debrief_first_stage()
1892 if (Current_stage) {
1894 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1897 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1900 // --------------------------------------------------------------------------------------
1901 // debrief_last_stage()
1902 void debrief_last_stage()
1904 if (Current_stage != Num_stages - 1) {
1905 New_stage = Num_stages - 1;
1906 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1909 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1912 // draw what stage number the debriefing is on
1913 void debrief_render_stagenum()
1921 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1922 gr_get_string_size(&w, NULL, buf);
1923 gr_set_color_fast(&Color_bright_blue);
1924 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1925 gr_set_color_fast(&Color_white);
1928 // render the mission time at the specified y location
1929 void debrief_render_mission_time(int y_loc)
1933 game_format_time(Missiontime, time_str);
1934 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1935 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1938 // render out the debriefing text to the scroll window
1939 void debrief_render()
1941 int y, z, font_height;
1943 if ( Num_stages <= 0 )
1946 font_height = gr_get_font_height();
1948 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]);
1951 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1952 if (z >= Num_text_lines)
1955 if (Text_type[z] == TEXT_TYPE_NORMAL)
1956 gr_set_color_fast(&Color_white);
1958 gr_set_color_fast(&Color_bright_red);
1961 gr_string(0, y, Text[z]);
1970 // render out the stats info to the scroll window
1972 void debrief_stats_render()
1974 int i, y, font_height;
1976 gr_set_color_fast(&Color_blue);
1977 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]);
1978 gr_string(0, 0, Debrief_current_callsign);
1979 font_height = gr_get_font_height();
1982 switch ( Current_stage ) {
1983 case DEBRIEF_MISSION_STATS:
1984 i = Current_stage - 1;
1988 gr_set_color_fast(&Color_white);
1990 // display mission completion time
1991 debrief_render_mission_time(y);
1994 show_stats_label(i, 0, y, font_height);
1995 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1997 case DEBRIEF_ALLTIME_STATS:
1998 i = Current_stage - 1;
2002 gr_set_color_fast(&Color_white);
2003 show_stats_label(i, 0, y, font_height);
2004 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2007 case DEBRIEF_ALLTIME_KILLS:
2008 case DEBRIEF_MISSION_KILLS:
2009 gr_set_color_fast(&Color_white);
2011 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
2012 if (i >= Num_text_lines)
2016 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2017 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
2019 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
2022 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
2023 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
2030 if (Num_text_lines == 2) {
2031 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2032 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
2034 gr_printf(0, y, XSTR( "(No ship kills)", 450));
2047 // do action for when the replay button is pressed
2048 void debrief_replay_pressed()
2050 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2052 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));
2059 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
2060 gamesnd_play_iface(SND_COMMIT_PRESSED);
2063 // -------------------------------------------------------------------
2064 // debrief_redraw_pressed_buttons()
2066 // Redraw any debriefing buttons that are pressed down. This function is needed
2067 // since we sometimes need to draw pressed buttons last to ensure the entire
2068 // button gets drawn (and not overlapped by other buttons)
2070 void debrief_redraw_pressed_buttons()
2075 for ( i=0; i<NUM_BUTTONS; i++ ) {
2076 b = &Buttons[gr_screen.res][i].button;
2077 // don't draw the recommendations button if we're in stats mode
2078 if ( b->button_down() ) {
2084 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
2086 void debrief_button_pressed(int num)
2090 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
2091 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
2092 if (num != Current_mode){
2093 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2098 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
2099 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
2100 if (num != Current_mode){
2101 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2106 case TEXT_SCROLL_UP:
2109 gamesnd_play_iface(SND_SCROLL);
2111 gamesnd_play_iface(SND_GENERAL_FAIL);
2115 case TEXT_SCROLL_DOWN:
2116 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2118 gamesnd_play_iface(SND_SCROLL);
2120 gamesnd_play_iface(SND_GENERAL_FAIL);
2124 case REPLAY_MISSION:
2125 if(Game_mode & GM_MULTIPLAYER){
2126 multi_debrief_replay_hit();
2128 debrief_replay_pressed();
2132 case RECOMMENDATIONS:
2133 gamesnd_play_iface(SND_USER_SELECT);
2134 Recommend_active = !Recommend_active;
2135 debrief_text_init();
2139 debrief_first_stage();
2143 debrief_prev_stage();
2147 debrief_next_stage();
2151 debrief_last_stage();
2155 gamesnd_play_iface(SND_HELP_PRESSED);
2156 launch_context_help();
2159 case OPTIONS_BUTTON:
2160 gamesnd_play_iface(SND_SWITCH_SCREENS);
2161 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2169 gamesnd_play_iface(SND_SWITCH_SCREENS);
2170 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2173 case PLAYER_SCROLL_UP:
2174 debrief_multi_list_scroll_up();
2177 case PLAYER_SCROLL_DOWN:
2178 debrief_multi_list_scroll_down();
2181 case MULTI_PINFO_POPUP:
2182 Debrief_should_show_popup = 1;
2186 debrief_kick_selected_player();
2191 void debrief_setup_ship_kill_stats(int stage_num)
2195 debrief_stats_kill_info *kill_info;
2197 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2198 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2201 Assert(Debrief_player != NULL);
2203 // kill_ar points to an array of MAX_SHIP_TYPE ints
2204 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2205 kill_arr = Debrief_player->stats.m_okKills;
2207 kill_arr = Debrief_player->stats.kills;
2211 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2213 // code used to add in mission kills, but the new system assumes that the player will accept, so
2214 // all time stats already have mission stats added in.
2215 if ( kill_arr[i] <= 0 ){
2220 kill_info = &Debrief_stats_kills[Num_text_lines++];
2222 kill_info->num = kill_arr[i];
2224 strcpy(kill_info->text, Ship_info[i].name);
2225 strcat(kill_info->text, NOX(":"));
2228 Num_text_lines += 2;
2231 // Iterate through the debriefing buttons, checking if they are pressed
2232 void debrief_check_buttons()
2236 for ( i=0; i<NUM_BUTTONS; i++ ) {
2237 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2238 debrief_button_pressed(i);
2242 if ( !(Game_mode & GM_MULTIPLAYER) )
2245 if (List_region.pressed()) {
2246 List_region.get_mouse_pos(NULL, &y);
2247 z = Multi_list_offset + y / gr_get_font_height();
2248 if ((z >= 0) && (z < Multi_list_size)) {
2249 // switch stats display to this newly selected player
2250 set_player_stats(Multi_list[z].net_player_index);
2251 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2252 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2253 Multi_list_select = z;
2254 debrief_setup_ship_kill_stats(Current_stage);
2255 gamesnd_play_iface(SND_USER_SELECT);
2259 // if the player was double clicked on - we should popup a player info popup
2261 if (List_region.double_clicked()) {
2262 Debrief_should_show_popup = 1;
2267 void debrief_text_stage_init(char *src, int type)
2269 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2270 char line[MAX_DEBRIEF_LINE_LEN];
2271 char *p_str[MAX_DEBRIEF_LINES];
2273 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2274 Assert(n_lines >= 0);
2276 // if you hit this, you proba
2277 if(n_lines >= MAX_DEBRIEF_LINES){
2278 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2281 for ( i=0; i<n_lines; i++ ) {
2282 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2283 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2284 strncpy(line, p_str[i], n_chars[i]);
2285 line[n_chars[i]] = 0;
2286 drop_white_space(line);
2287 Text_type[Num_text_lines] = type;
2288 Text[Num_text_lines++] = strdup(line);
2294 void debrief_free_text()
2298 for (i=0; i<Num_debrief_lines; i++)
2302 Num_debrief_lines = 0;
2305 // setup the debriefing text lines for rendering
2306 void debrief_text_init()
2311 // release old text lines first
2312 debrief_free_text();
2313 Num_text_lines = Text_offset = 0;
2315 if (Current_mode == DEBRIEF_TAB) {
2316 for (i=0; i<Num_debrief_stages; i++) {
2318 Text[Num_text_lines++] = NULL; // add a blank line between stages
2320 src = Debrief_stages[i]->new_text;
2322 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2324 if (Recommend_active) {
2325 src = Debrief_stages[i]->new_recommendation_text;
2326 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2327 src = XSTR( "We have no recommendations for you.", 1054);
2330 Text[Num_text_lines++] = NULL;
2331 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2337 Num_debrief_lines = Num_text_lines;
2341 // not in debriefing mode, must be in stats mode
2343 debrief_setup_ship_kill_stats(Current_stage);
2347 // --------------------------------------------------------------------------------------
2351 Assert(!Debrief_inited);
2352 // Campaign.loop_enabled = 0;
2353 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2355 // set up the right briefing for this guy
2356 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2357 Debriefing = &Debriefings[Net_player->p_info.team];
2359 Debriefing = &Debriefings[0];
2362 // no longer is mission
2363 Game_mode &= ~(GM_IN_MISSION);
2367 New_mode = DEBRIEF_TAB;
2368 Recommend_active = Award_active = 0;
2373 Debrief_cue_voice = 0;
2374 Num_text_lines = Num_debrief_lines = 0;
2375 Debrief_first_voice_flag = 1;
2377 Debrief_multi_voice_loaded = 0;
2380 Medal_text_bitmap = bm_load(NOX("DebriefText01"));
2381 Rank_text_bitmap = bm_load(NOX("DebriefText02"));
2382 Badge_text_bitmap = bm_load(NOX("DebriefText03"));
2385 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2386 // MUST store goals and events first - may be used to evaluate next mission
2387 // store goals and events
2388 mission_campaign_store_goals_and_events();
2390 // evaluate next mission
2391 mission_campaign_eval_next_mission();
2394 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2396 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2397 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2400 // call scoring level close for my stats. Needed for award_init. The stats will
2401 // be backed out if used chooses to replace them.
2402 scoring_level_close();
2404 debrief_ui_init(); // init UI items
2405 debrief_award_init();
2407 debrief_voice_init();
2408 debrief_multi_list_init();
2409 // rank_bitmaps_clear();
2410 // rank_bitmaps_load();
2412 strcpy(Debrief_current_callsign, Player->callsign);
2413 Debrief_player = Player;
2414 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2416 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2417 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2418 // info directly from the server.
2419 if ( !MULTIPLAYER_CLIENT ) {
2420 debrief_set_stages_and_multi_stuff();
2422 if ( Num_debrief_stages <= 0 ) {
2423 Num_debrief_stages = 0;
2425 debrief_voice_load_all();
2428 // multiplayer client may have already received their debriefing info. If they have not,
2429 // then set the num debrief stages to 0
2430 if ( !Debrief_multi_stages_loaded ) {
2431 Num_debrief_stages = 0;
2436 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2437 common_music_init(SCORE_DEBRIEF_SUCCESS);
2439 common_music_init(SCORE_DEBRIEF_FAIL);
2443 // start up the appropriate music
2444 if (Campaign.next_mission == Campaign.current_mission) {
2445 // you failed the mission because you suck, so you get the suck music
2446 common_music_init(SCORE_DEBRIEF_FAIL);
2447 } else if (mission_goals_met()) {
2448 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2449 common_music_init(SCORE_DEBRIEF_SUCCESS);
2451 // you somehow passed the mission, so you get a little something for your efforts.
2452 common_music_init(SCORE_DEBRIEF_AVERAGE);
2455 if (Campaign.next_mission == Campaign.current_mission) {
2456 // better luck next time, increase his retries
2457 Player->failures_this_session++;
2459 // clear his retries info regardless of whether or not he accepts
2460 Player->failures_this_session = 0;
2463 if (Game_mode & GM_MULTIPLAYER) {
2464 multi_debrief_init();
2466 // if i'm not the host of the game, disable the multi kick button
2467 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2468 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2471 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2472 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2473 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2474 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2475 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2476 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2477 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2478 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2481 if (!Award_active) {
2482 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2483 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2486 Debrief_skip_popup_already_shown = 0;
2491 // --------------------------------------------------------------------------------------
2493 void debrief_close()
2497 Assert(Debrief_inited);
2499 // if the mission wasn't accepted, clear out my stats
2500 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2501 // are a little bit different
2502 if (Game_mode & GM_MULTIPLAYER) {
2503 // if stats weren't accepted, backout my own stats
2504 if (multi_debrief_stats_accept_code() != 1) {
2505 if(MULTIPLAYER_MASTER){
2506 for(idx=0; idx<MAX_PLAYERS; idx++){
2507 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2508 scoring_backout_accept(&Net_players[idx].player->stats);
2512 scoring_backout_accept( &Player->stats );
2517 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2518 scoring_backout_accept( &Player->stats );
2522 // if dude passed the misson and accepted, reset his show skip popup flag
2523 if (Debrief_accepted) {
2524 Player->show_skip_popup = 1;
2527 if (Num_debrief_lines) {
2528 for (i=0; i<Num_debrief_lines; i++){
2535 // unload the overlay bitmap
2537 help_overlay_unload(DEBRIEFING_OVERLAY);
2540 // clear out award text
2541 Debrief_award_text_num_lines = 0;
2543 debrief_voice_unload_all();
2544 common_music_close();
2547 // rank_bitmaps_release();
2550 if (Background_bitmap >= 0){
2551 bm_unload(Background_bitmap);
2554 if (Award_bg_bitmap >= 0){
2555 bm_unload(Award_bg_bitmap);
2558 if (Rank_bitmap >= 0){
2559 bm_unload(Rank_bitmap);
2562 if (Medal_bitmap >= 0){
2563 bm_unload(Medal_bitmap);
2566 if (Badge_bitmap >= 0){
2567 bm_unload(Badge_bitmap);
2570 if (Wings_bitmap >= 0) {
2571 bm_unload(Wings_bitmap);
2574 if (Crest_bitmap >= 0) {
2575 bm_unload(Crest_bitmap);
2579 if (Medal_text_bitmap >= 0) {
2580 bm_unload(Medal_text_bitmap);
2583 if (Badge_text_bitmap >= 0) {
2584 bm_unload(Badge_text_bitmap);
2587 if (Rank_text_bitmap >= 0) {
2588 bm_unload(Rank_text_bitmap);
2592 Debrief_ui_window.destroy();
2593 common_free_interface_palette(); // restore game palette
2596 if (Game_mode & GM_MULTIPLAYER){
2597 multi_debrief_close();
2605 // handle keypresses in debriefing
2606 void debrief_do_keys(int new_k)
2613 case KEY_SHIFTED | KEY_TAB:
2621 // multiplayer accept popup is a little bit different
2622 if (Game_mode & GM_MULTIPLAYER) {
2623 multi_debrief_esc_hit();
2625 // display the normal debrief popup
2627 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2628 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2629 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2630 if (choice == 1) { // accept and continue on
2632 gameseq_post_event(GS_EVENT_MAIN_MENU);
2638 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2639 // need to popup saying that mission was a failure and must be replayed
2640 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));
2645 // Return to Main Hall
2646 gameseq_post_event(GS_EVENT_END_GAME);
2657 void debrief_draw_award_text()
2659 int start_y, curr_y, i, x, sw;
2660 int fh = gr_get_font_height();
2661 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];
2663 // vertically centered within field
2664 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);
2668 for (i=0; i<Debrief_award_text_num_lines; i++) {
2669 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2670 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2671 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2672 gr_set_color_fast(&Color_white);
2673 gr_string(x, curr_y, Debrief_award_text[i]);
2675 // adjust y pos, including a little extra between the "pairs"
2677 if ((i == 1) || (i == 3)) {
2678 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2683 // clears out text array so we dont have old award text showing up on new awards.
2684 void debrief_award_text_clear() {
2687 Debrief_award_text_num_lines = 0;
2688 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2689 //Debrief_award_text[i][0] = 0;
2690 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2694 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2695 void debrief_add_award_text(char *str)
2697 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2698 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2703 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];
2706 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2708 // maybe translate for displaying
2710 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2713 medals_translate_name_pl(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2716 Debrief_award_text_num_lines++;
2718 // if its too long, split once ONLY
2719 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2720 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2721 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2722 if (line2 != NULL) {
2723 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2725 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2728 #endif // !MAKE_FS1: No text for FS1, it's all bitmaps
2730 // called once per frame to drive all the input reading and rendering
2731 void debrief_do_frame(float frametime)
2734 char *please_wait_str = XSTR("Please Wait", 1242);
2738 Assert(Debrief_inited);
2740 // first thing is to load the files
2741 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2742 // draw the background, etc
2743 GR_MAYBE_CLEAR_RES(Background_bitmap);
2744 if (Background_bitmap >= 0) {
2745 gr_set_bitmap(Background_bitmap);
2749 Debrief_ui_window.draw();
2751 if ( Debrief_multi_loading_bitmap > -1 ){
2752 gr_set_bitmap(Debrief_multi_loading_bitmap);
2753 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2756 // draw "Please Wait"
2757 gr_set_color_fast(&Color_normal);
2759 gr_get_string_size(&str_w, &str_h, please_wait_str);
2760 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2765 // make sure we run the debrief do frame
2766 if (Game_mode & GM_MULTIPLAYER) {
2767 multi_debrief_do_frame();
2772 int keypress = game_check_key();
2773 if(keypress == KEY_ESC){
2775 multi_quit_game(PROMPT_CLIENT);
2781 // if multiplayer client, and not loaded voice, then load it
2782 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2783 debrief_multi_fixup_stages();
2784 debrief_voice_load_all();
2785 Debrief_multi_voice_loaded = 1;
2788 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2789 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2790 Debrief_ui_window.set_ignore_gadgets(1);
2793 k = chatbox_process();
2794 if ( Game_mode & GM_NORMAL ) {
2795 new_k = Debrief_ui_window.process(k);
2797 new_k = Debrief_ui_window.process(k, 0);
2800 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2801 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2802 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2803 Debrief_ui_window.set_ignore_gadgets(0);
2809 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2810 Debrief_ui_window.set_ignore_gadgets(0);
2813 // don't show pilot info popup by default
2814 Debrief_should_show_popup = 0;
2816 // see if the mode has changed and handle it if so.
2817 if ( Current_mode != New_mode ) {
2818 debrief_voice_stop();
2819 Current_mode = New_mode;
2822 if (New_mode == DEBRIEF_TAB) {
2824 Debrief_cue_voice = 0;
2826 if (Debrief_first_voice_flag) {
2827 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2828 Debrief_first_voice_flag = 0;
2831 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2835 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2836 Current_stage = New_stage;
2837 debrief_text_init();
2840 debrief_voice_play();
2843 if (Game_mode & GM_MULTIPLAYER) {
2844 multi_debrief_do_frame();
2847 // Now do all the rendering for the frame
2848 GR_MAYBE_CLEAR_RES(Background_bitmap);
2849 if (Background_bitmap >= 0) {
2850 gr_set_bitmap(Background_bitmap);
2854 // draw the damn awarded stuff, G
2855 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2856 gr_set_bitmap(Award_bg_bitmap);
2857 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2858 if (Rank_bitmap >= 0) {
2859 gr_set_bitmap(Rank_bitmap);
2861 gr_bitmap(Debrief_rank_coords[0], Debrief_rank_coords[1]);
2863 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2867 if (Medal_bitmap >= 0) {
2868 gr_set_bitmap(Medal_bitmap);
2869 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2872 if (Badge_bitmap >= 0) {
2873 gr_set_bitmap(Badge_bitmap);
2875 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2877 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2881 if (Wings_bitmap >= 0) {
2882 gr_set_bitmap(Wings_bitmap);
2884 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2886 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2890 // this isn't used in FS1 but doesn't hurt to leave it
2891 if (Crest_bitmap >= 0) {
2892 gr_set_bitmap(Crest_bitmap);
2893 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2896 // draw medal/badge/rank labels
2898 debrief_draw_award_text();
2900 if (Rank_text_bitmap >= 0) {
2901 gr_set_bitmap(Rank_text_bitmap);
2902 gr_bitmap(Debrief_rank_text_coords[gr_screen.res][0], Debrief_rank_text_coords[gr_screen.res][1]);
2905 if (Medal_text_bitmap >= 0) {
2906 gr_set_bitmap(Medal_text_bitmap);
2907 gr_bitmap(Debrief_medal_text_coords[gr_screen.res][0], Debrief_medal_text_coords[gr_screen.res][1]);
2910 if (Badge_text_bitmap >= 0) {
2911 gr_set_bitmap(Badge_text_bitmap);
2912 gr_bitmap(Debrief_badge_text_coords[gr_screen.res][0], Debrief_badge_text_coords[gr_screen.res][1]);
2917 Debrief_ui_window.draw();
2918 debrief_redraw_pressed_buttons();
2919 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2920 if (Recommend_active && (Current_mode != STATS_TAB)) {
2921 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2924 // draw the title of the mission
2925 gr_set_color_fast(&Color_bright_white);
2926 strcpy(buf, The_mission.name);
2927 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2928 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2930 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2931 gr_set_color_fast(&Color_normal);
2932 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);
2935 // draw the screen-specific text
2936 switch (Current_mode) {
2938 if ( Num_debrief_stages <= 0 ) {
2939 gr_set_color_fast(&Color_white);
2940 Assert( Game_current_mission_filename != NULL );
2941 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);
2950 debrief_stats_render();
2954 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2957 gr_set_color_fast(&Color_red);
2958 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2959 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));
2962 debrief_render_stagenum();
2963 debrief_multi_list_draw();
2965 // render some extra stuff in multiplayer
2966 if (Game_mode & GM_MULTIPLAYER) {
2967 // render the chatbox last
2971 Debrief_ui_window.draw_tooltip();
2973 // render the status indicator for the voice system
2974 multi_common_voice_display_status();
2977 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2978 // want to include the mouse pointer which is drawn in the flip
2980 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2981 debrief_check_buttons();
2982 debrief_do_keys(new_k);
2985 // blit help overlay if active
2986 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2990 // dont let dude skip 3-09. hack.
2991 if(Game_mode & GM_CAMPAIGN_MODE){
2992 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2993 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2994 Debrief_skip_popup_already_shown = 1;
2999 // maybe show skip mission popup
3000 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)) {
3001 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
3002 XSTR("Advance To The Next Mission", 1474),
3003 XSTR("Don't Show Me This Again", 1475),
3004 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
3005 switch (popup_choice) {
3007 // stay on this mission, so proceed to normal debrief
3008 // in other words, do nothing.
3011 // skip this mission
3012 mission_campaign_skip_to_next();
3013 gameseq_post_event(GS_EVENT_START_GAME);
3016 // dont show this again
3017 Player->show_skip_popup = 0;
3021 Debrief_skip_popup_already_shown = 1;
3024 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
3025 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
3026 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
3027 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
3029 Debrief_should_show_popup = 0;
3033 void debrief_rebuild_player_list()
3037 debrief_multi_list_info *list;
3039 Multi_list_size = 0; // number of net players to choose from
3041 for ( i=0; i<MAX_PLAYERS; i++ ) {
3042 np = &Net_players[i];
3043 // remember not to include the standalone.
3044 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
3045 list = &Multi_list[Multi_list_size++];
3046 list->net_player_index = i;
3047 strcpy(list->callsign, np->player->callsign);
3049 // make sure to leave some room to blit the team indicator
3050 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
3055 void debrief_handle_player_drop()
3057 debrief_rebuild_player_list();
3060 void debrief_disable_accept()