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.7 2003/05/25 02:30:43 taylor
21 * Revision 1.6 2002/07/13 06:46:48 theoddone33
24 * Revision 1.5 2002/06/09 04:41:23 relnev
25 * added copyright header
27 * Revision 1.4 2002/06/02 04:26:34 relnev
30 * Revision 1.3 2002/05/26 22:06:17 relnev
31 * makefile: disable stand_gui for now.
33 * rest: staticize some globals
35 * Revision 1.2 2002/05/07 03:16:46 theoddone33
36 * The Great Newline Fix
38 * Revision 1.1.1.1 2002/05/03 03:28:10 root
42 * 57 10/29/99 10:40p Jefff
43 * hack to make german medal names display without actually changing them
45 * 56 10/13/99 3:26p Jefff
46 * fixed unnumbered XSTRs
48 * 55 10/06/99 10:28a Jefff
51 * 54 9/30/99 5:57p Jefff
52 * show upsell at end of campaign in OEM builds
54 * 53 9/15/99 3:42a Jefff
57 * 52 9/14/99 4:35a Dave
58 * Argh. Added all kinds of code to handle potential crashes in debriefing
61 * 51 9/14/99 3:26a Dave
62 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
63 * respawn-too-early problem. Made a few crash points safe.
65 * 50 9/14/99 12:51a Jefff
67 * 49 9/13/99 6:01p Jefff
68 * fixed wrong promotion voice mapping for sm1-08
70 * 48 9/13/99 11:15a Jefff
71 * clear out award text bug fixed
73 * 47 9/13/99 12:17p Andsager
74 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
77 * 46 9/07/99 9:35p Jefff
78 * fixed bug where award text was not getting cleared properly between
81 * 45 9/07/99 6:56p Jefff
82 * a few adjustments to loop detection
84 * 44 9/07/99 1:54p Jefff
85 * skip mission cleanup
87 * 43 9/06/99 9:45p Jefff
88 * skip mission support
90 * 42 9/06/99 6:38p Dave
91 * Improved CD detection code.
93 * 41 9/03/99 1:32a Dave
94 * CD checking by act. Added support to play 2 cutscenes in a row
95 * seamlessly. Fixed super low level cfile bug related to files in the
96 * root directory of a CD. Added cheat code to set campaign mission # in
99 * 40 9/02/99 3:45p Jefff
100 * forgot to remove some debug code. doh.
102 * 39 9/02/99 3:41p Jefff
103 * changed badge voice handling to be similar to promotion voice handling
105 * 38 9/01/99 4:41p Jefff
106 * fixed stoopid text color bug
108 * 37 8/31/99 11:54a Jefff
109 * minor debrief music tweak
111 * 36 8/27/99 9:57a Dave
112 * Enabled standard cheat codes. Allow player to continue in a campaing
113 * after using cheat codes.
115 * 35 8/27/99 12:04a Dave
116 * Campaign loop screen.
118 * 34 8/26/99 8:49p Jefff
119 * Updated medals screen and about everything that ever touches medals in
120 * one way or another. Sheesh.
122 * 33 8/20/99 4:20p Jefff
123 * hack for choosing the correct promotion voice
125 * 32 8/16/99 4:05p Dave
126 * Big honking checkin.
128 * 31 8/16/99 9:49a Jefff
129 * mission title length fix in multi
131 * 30 8/11/99 5:33p Jefff
132 * added 3rd debrief music track
134 * 29 8/10/99 7:28p Jefff
135 * shuffled some text around
137 * 28 8/04/99 5:36p Andsager
138 * Show upsell screens at end of demo campaign before returning to main
141 * 27 8/04/99 2:07p Jefff
142 * mission title no longer overwrites popup
144 * 26 8/02/99 5:37p Jefff
146 * 25 8/02/99 4:52p Jefff
147 * negative feedback sound when recommendations button pressed and
150 * 24 7/21/99 6:21p Jefff
151 * added hotkeys to the "you cannot accept" popup
153 * 23 6/15/99 12:04p Anoop
154 * Added a warning for running out of debrief text lines.
156 * 22 6/09/99 2:17p Dave
157 * Fixed up pleasewait bitmap rendering.
159 * 21 6/01/99 6:07p Dave
160 * New loading/pause/please wait bar.
162 * 20 5/22/99 6:05p Dave
163 * Fixed a few localization # problems.
165 * 19 5/22/99 5:35p Dave
166 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
168 * 18 3/20/99 3:47p Andsager
169 * Fix crash with no mission loop description.
171 * 17 2/23/99 2:29p Dave
172 * First run of oldschool dogfight mode.
174 * 16 2/21/99 6:01p Dave
175 * Fixed standalone WSS packets.
177 * 15 2/11/99 3:08p Dave
178 * PXO refresh button. Very preliminary squad war support.
180 * 14 1/30/99 5:08p Dave
181 * More new hi-res stuff.Support for nice D3D textures.
183 * 13 1/29/99 2:08a Dave
184 * Fixed beam weapon collisions with players. Reduced size of scoring
185 * struct for multiplayer. Disabled PXO.
187 * 12 1/14/99 5:15p Neilk
188 * changed credits, command debrief interfaces to high resolution support
190 * 11 1/13/99 2:11p Andsager
191 * change default debriefing string text
193 * 10 12/17/98 4:50p Andsager
194 * Added debrief_assemble_optional_mission_popup_text() for single and
197 * 9 12/12/98 3:17p Andsager
198 * Clean up mission eval, goal, event and mission scoring.
200 * 8 12/10/98 10:19a Andsager
201 * Fix mission loop assert
203 * 7 12/10/98 9:59a Andsager
204 * Fix some bugs with mission loops
206 * 6 12/09/98 1:56p Andsager
207 * Initial checkin of mission loop
209 * 5 11/05/98 4:18p Dave
210 * First run nebula support. Beefed up localization a bit. Removed all
211 * conditional compiles for foreign versions. Modified mission file
214 * 4 10/23/98 3:51p Dave
215 * Full support for tstrings.tbl and foreign languages. All that remains
216 * is to make it active in Fred.
218 * 3 10/13/98 9:28a Dave
219 * Started neatening up freespace.h. Many variables renamed and
220 * reorganized. Added AlphaColors.[h,cpp]
222 * 2 10/07/98 10:53a Dave
225 * 1 10/07/98 10:49a Dave
227 * 178 9/17/98 3:08p Dave
228 * PXO to non-pxo game warning popup. Player icon stuff in create and join
229 * game screens. Upped server count refresh time in PXO to 35 secs (from
232 * 177 7/07/98 1:46p Dave
233 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
236 * 175 6/09/98 10:31a Hoffoss
237 * Created index numbers for all xstr() references. Any new xstr() stuff
238 * added from here on out should be added to the end if the list. The
239 * current list count can be found in FreeSpace.cpp (search for
242 * 174 6/07/98 3:26p Lawrance
243 * Fix bug with cut-off popup text
245 * 173 6/05/98 9:54a Lawrance
248 * 172 6/01/98 11:43a John
249 * JAS & MK: Classified all strings for localization.
251 * 171 5/27/98 1:24p Allender
252 * make targeting dots work (as well as other targeting features) properly
253 * in multiplayer. Don't query for CD when entering debrief in
256 * 170 5/26/98 11:10a Lawrance
257 * Fix bug where window controls get disabled when F1 pressed twice
259 * 169 5/24/98 12:55a Mike
260 * Prevent Assert() when no debriefing text for a stage.
262 * 168 5/23/98 10:38p Lawrance
263 * Avoid doing a cfile refresh when running debug
265 * 167 5/23/98 6:49p Lawrance
266 * Fix problems with refreshing the file list when a CD is inserted
268 * 166 5/21/98 6:57p Lawrance
269 * Don't prompt for the CD if voice not found
271 * 165 5/20/98 2:24a Dave
272 * Fixed server side voice muting. Tweaked multi debrief/endgame
273 * sequencing a bit. Much friendlier for stats tossing/accepting now.
275 * 164 5/19/98 8:35p Dave
276 * Revamp PXO channel listing system. Send campaign goals/events to
277 * clients for evaluation. Made lock button pressable on all screens.
279 * 163 5/19/98 11:13a Hoffoss
280 * Fixed bug where wrong wings award was being displayed in debriefing.
282 * 162 5/19/98 12:28a Mike
285 * 161 5/18/98 8:08p Hoffoss
286 * Moved placement of 'More' text.
288 * 160 5/18/98 3:50p Dan
289 * AL: Pick correct traitor debriefing voice file
291 * 159 5/17/98 6:32p Dave
292 * Make sure clients/servers aren't kicked out of the debriefing when team
293 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
294 * xfer/pilot info popup stuff.
296 * 158 5/16/98 9:14p Allender
297 * fix scoring ckise fir training missions to actually count medals, but
298 * nothing else. Code used to Assert when wings were granted then taken
299 * away because they were actually never granted in scoring structure
301 * 157 5/15/98 5:15p Dave
302 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
303 * status for team vs. team. Put in asserts to check for invalid team vs.
306 * 156 5/15/98 4:36p Allender
307 * fixed minor bug with wings
309 * 155 5/15/98 4:12p Allender
310 * removed redbook code. Put back in ingame join timer. Major fixups for
311 * stats in multiplayer. Pass correct score, medals, etc when leaving
312 * game. Be sure clients display medals, badges, etc.
314 * 154 5/15/98 2:25p Jasen
315 * temporarily disable granting of promotion and badges for clients
317 * 153 5/15/98 10:57a Allender
318 * fixed client side debriefings
320 * 152 5/15/98 10:36a Dave
321 * Removed 2 bogus bitmap drawing Int3()'s
323 * 151 5/14/98 2:44p Hoffoss
324 * Added wings awarding to debrief screen.
326 * 150 5/13/98 9:11p Lawrance
327 * Make 'replay mission' popup warn users about the loss of mission stats.
332 #include "missiondebrief.h"
333 #include "missionbriefcommon.h"
334 #include "missionscreencommon.h"
335 #include "missiongoals.h"
336 #include "missionpause.h"
337 #include "freespace.h"
338 #include "gamesequence.h"
346 #include "audiostr.h"
349 #include "contexthelp.h"
355 #include "multimsgs.h"
356 #include "multiutil.h"
357 #include "multiteamselect.h"
359 #include "eventmusic.h"
363 #include "multi_pinfo.h"
364 #include "contexthelp.h"
365 #include "multi_kick.h"
366 #include "multi_campaign.h"
367 #include "alphacolors.h"
368 #include "localize.h"
369 #include "multi_endgame.h"
372 #define MAX_TOTAL_DEBRIEF_LINES 200
374 #define TEXT_TYPE_NORMAL 1
375 #define TEXT_TYPE_RECOMMENDATION 2
377 #define DEBRIEF_NUM_STATS_PAGES 4
378 #define DEBRIEF_MISSION_STATS 0
379 #define DEBRIEF_MISSION_KILLS 1
380 #define DEBRIEF_ALLTIME_STATS 2
381 #define DEBRIEF_ALLTIME_KILLS 3
383 // 3rd coord is max width in pixels
384 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
397 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
410 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
415 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
428 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
441 #define MULTI_LIST_TEAM_OFFSET 16
443 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
448 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
457 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
470 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
484 int Debrief_rank_coords[2] = {
488 int Debrief_badge_coords[2] = {
494 // 0=x, 1=y, 2=width of the field
495 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
504 // 0=x, 1=y, 2=height of the field
505 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
514 // the medal text in FS1 is a bitmap
515 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][2] = {
524 int Debrief_rank_text_coords[GR_NUM_RESOLUTIONS][2] = {
533 int Debrief_badge_text_coords[GR_NUM_RESOLUTIONS][2] = {
544 // 1 = without medal (text will use medal space)
545 #define DB_WITH_MEDAL 0
546 #define DB_WITHOUT_MEDAL 1
547 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
556 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
557 "DebriefSingle", // GR_640
558 "2_DebriefSingle" // GR_1024
560 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
561 "DebriefMulti", // GR_640
562 "2_DebriefMulti" // GR_1024
564 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
565 "Debrief-m", // GR_640
566 "2_Debrief-m" // GR_1024
569 #define NUM_BUTTONS 18
572 #define DEBRIEF_TAB 0
574 #define TEXT_SCROLL_UP 2
575 #define TEXT_SCROLL_DOWN 3
576 #define REPLAY_MISSION 4
577 #define RECOMMENDATIONS 5
578 #define FIRST_STAGE 6
582 #define MULTI_PINFO_POPUP 10
583 #define MULTI_KICK 11
584 #define MEDALS_BUTTON 12
585 #define PLAYER_SCROLL_UP 13
586 #define PLAYER_SCROLL_DOWN 14
587 #define HELP_BUTTON 15
588 #define OPTIONS_BUTTON 16
589 #define ACCEPT_BUTTON 17
594 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
595 "PleaseWait", // GR_640
596 "2_PleaseWait" // GR_1024
602 char text[NAME_LENGTH+1]; // name of ship type with a colon
603 int num; // how many ships of this type player has killed
604 } debrief_stats_kill_info;
607 int net_player_index; // index into Net_players[] array
608 int rank_bitmap; // bitmap id for rank
609 char callsign[CALLSIGN_LEN];
610 } debrief_multi_list_info;
612 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
615 ui_button_info("DB_00", 0, 2, -1, -1, 0), // debriefing
616 ui_button_info("DB_01", 0, 20, -1, -1, 1), // statistics
617 ui_button_info("DB_02", 0, 195, -1, -1, 2), // scroll stats up
618 ui_button_info("DB_03", 0, 232, -1, -1, 3), // scroll stats down
619 ui_button_info("DB_04", 24, 424, -1, -1, 4), // replay mission
620 ui_button_info("DB_05", 30, 451, -1, -1, 5), // recommendations
621 ui_button_info("DB_06", 211, 445, -1, -1, 6), // first page
622 ui_button_info("DB_07", 234, 445, -1, -1, 7), // prev page
623 ui_button_info("DB_08", 259, 445, -1, -1, 8), // next page
624 ui_button_info("DB_09", 283, 445, -1, -1, 9), // last page
625 ui_button_info("DB_21", 441, 384, -1, -1, 21), // pilot info
626 ui_button_info("DB_25", 511, 384, -1, -1, 25), // kick
627 ui_button_info("DB_15", 604, 224, -1, -1, 15), // medals
628 ui_button_info("DB_16", 615, 329, -1, -1, 16), // scroll pilots up
629 ui_button_info("DB_17", 615, 371, -1, -1, 17), // scroll pilots down
630 ui_button_info("DB_10", 469, 428, -1, -1, 10), // help
631 ui_button_info("DB_11", 447, 452, -1, -1, 11), // options
632 ui_button_info("DB_12", 562, 410, -1, -1, 12), // accept
634 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
635 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
636 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
637 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
638 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
639 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
640 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
641 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
642 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
643 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
644 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
645 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
646 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
647 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
648 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
649 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
650 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
651 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
655 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
656 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
657 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
658 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
659 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
660 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
661 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
662 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
663 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
664 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
665 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
666 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
667 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
668 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
669 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
670 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
671 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
672 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
678 #define NUM_DEBRIEF_TEXT 0
680 #define NUM_DEBRIEF_TEXT 10
682 #define MP_TEXT_INDEX_1 4
683 #define MP_TEXT_INDEX_2 5
684 #define MP_TEXT_INDEX_3 6
685 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
687 // not needed for FS1
689 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
690 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
691 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
692 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
693 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
694 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
695 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
696 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
697 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
698 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
702 // not needed for FS1
704 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
705 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
706 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
707 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
708 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
709 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
710 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
711 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
712 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
713 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
719 char Debrief_current_callsign[CALLSIGN_LEN+10];
720 player *Debrief_player;
722 static UI_WINDOW Debrief_ui_window;
723 static UI_BUTTON List_region;
724 static int Background_bitmap; // bitmap for the background of the debriefing
725 static int Award_bg_bitmap;
726 static int Debrief_multi_loading_bitmap;
727 static int Rank_bitmap;
728 static int Medal_bitmap;
729 static int Badge_bitmap;
730 static int Wings_bitmap;
731 static int Crest_bitmap;
733 static int Rank_text_bitmap;
734 static int Medal_text_bitmap;
735 static int Badge_text_bitmap;
738 static int Debrief_accepted;
739 static int Turned_traitor;
740 static int Must_replay_mission;
742 static int Current_mode;
744 static int Recommend_active;
745 static int Award_active;
746 static int Text_offset;
747 static int Num_text_lines = 0;
748 static int Num_debrief_lines = 0;
749 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
750 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
752 static int Debrief_inited = 0;
753 static int New_stage;
754 static int Current_stage;
755 static int Num_stages;
756 static int Num_debrief_stages;
757 static int Stage_voice;
759 static int Multi_list_size;
760 static int Multi_list_offset;
762 int Debrief_multi_stages_loaded = 0;
763 int Debrief_multi_voice_loaded = 0;
765 // static int Debrief_voice_ask_for_cd;
767 // voice id's for debriefing text
768 static int Debrief_voices[MAX_DEBRIEF_STAGES];
770 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
771 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
772 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
774 // pointer used for getting to debriefing information
775 debriefing Traitor_debriefing; // used when player is a traitor
777 // pointers to the active stages for this debriefing
778 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
779 static debrief_stage Promotion_stage, Badge_stage;
780 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
781 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
782 int Multi_list_select;
784 // flag indicating if we should display info for the given player (in multiplayer)
785 int Debrief_should_show_popup = 1;
787 // already shown skip mission popup?
788 static int Debrief_skip_popup_already_shown = 0;
790 void debrief_text_init();
791 void debrief_accept(int ok_to_post_start_game_event = 1);
792 void debrief_kick_selected_player();
795 // promotion voice selection stuff
796 #define NUM_VOLITION_CAMPAIGNS 1
798 char campaign_name[32];
800 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
802 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
803 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
807 // data for which voice goes w/ which mission
808 typedef struct voice_map {
809 char mission_file[32];
813 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
814 { // FreeSpace2 campaign
846 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
848 { "loop1-1.fs2", 4 },
849 { "loop1-2.fs2", 4 },
850 { "loop1-3.fs2", 5 },
851 { "loop2-1.fs2", 4 },
856 #define DB_AWARD_WINGS 0
857 #define DB_AWARD_MEDAL 1
859 #define DB_AWARD_RANK 2
860 #define DB_AWARD_BADGE 3
861 #define DB_AWARD_BG 4
862 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][5] = {
879 #define DB_AWARD_SOC 2
880 #define DB_AWARD_RANK 3
881 #define DB_AWARD_BADGE 4
882 #define DB_AWARD_BG 5
883 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
903 #define AWARD_TEXT_MAX_LINES 5
904 #define AWARD_TEXT_MAX_LINE_LENGTH 128
905 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
906 int Debrief_award_text_num_lines = 0;
910 // prototypes, you know you love 'em
911 void debrief_add_award_text(char *str);
912 void debrief_award_text_clear();
917 char *debrief_tooltip_handler(char *str)
919 if (!stricmp(str, NOX("@.Medal"))) {
921 return XSTR( "Medal", 435);
924 } else if (!stricmp(str, NOX("@.Rank"))) {
926 return XSTR( "Rank", 436);
929 } else if (!stricmp(str, NOX("@.Badge"))) {
931 return XSTR( "Badge", 437);
934 } else if (!stricmp(str, NOX("@Medal"))) {
935 if (Medal_bitmap >= 0){
936 return Medals[Player->stats.m_medal_earned].name;
939 } else if (!stricmp(str, NOX("@Rank"))) {
940 if (Rank_bitmap >= 0){
941 return Ranks[Promoted].name;
944 } else if (!stricmp(str, NOX("@Badge"))) {
945 if (Badge_bitmap >= 0){
946 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
953 // initialize the array of handles to the different voice streams
954 void debrief_voice_init()
958 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
959 Debrief_voices[i] = -1;
963 void debrief_load_voice_file(int voice_num, char *name)
965 int load_attempts = 0;
968 if ( load_attempts++ > 5 ) {
972 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
973 if ( Debrief_voices[voice_num] >= 0 ) {
977 // Don't bother to ask for the CD in multiplayer
978 if ( Game_mode & GM_MULTIPLAYER ) {
982 // couldn't load voice, ask user to insert CD (if necessary)
984 // if ( Debrief_voice_ask_for_cd ) {
985 // if ( game_do_cd_check() == 0 ) {
986 // Debrief_voice_ask_for_cd = 0;
993 // open and pre-load the stream buffers for the different voice streams
994 void debrief_voice_load_all()
998 // Debrief_voice_ask_for_cd = 1;
1000 for ( i=0; i<Num_debrief_stages; i++ ) {
1001 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
1004 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
1005 debrief_load_voice_file(i, Debrief_stages[i]->voice);
1006 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
1011 // close all the briefing voice streams
1012 void debrief_voice_unload_all()
1016 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
1017 if ( Debrief_voices[i] != -1 ) {
1018 audiostream_close_file(Debrief_voices[i], 0);
1019 Debrief_voices[i] = -1;
1024 // start playback of the voice for a particular briefing stage
1025 void debrief_voice_play()
1027 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
1031 // no more stages? We are done then.
1032 if (Stage_voice >= Num_debrief_stages){
1036 // if in delayed start, see if delay has elapsed and start voice if so
1037 if (Debrief_cue_voice) {
1038 if (!timestamp_elapsed(Debrief_cue_voice)){
1042 Stage_voice++; // move up to next voice
1043 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
1044 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
1045 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
1051 // see if voice is still playing. If so, do nothing yet.
1052 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
1056 // set voice to play in a little while from now.
1057 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
1060 // stop playback of the voice for a particular briefing stage
1061 void debrief_voice_stop()
1063 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
1066 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
1070 // function to deal with inserting possible promition and badge stages into the debriefing
1072 void debrief_multi_fixup_stages()
1076 // possibly insert the badge stage first, them the promotion stage since they are
1077 // inserted at the front of the debrief stages.
1078 if ( Badge_bitmap >= 0 ) {
1079 // move all stages forward one. Don't
1080 for ( i = Num_debrief_stages; i > 0; i-- ) {
1081 Debrief_stages[i] = Debrief_stages[i-1];
1083 Debrief_stages[0] = &Badge_stage;
1084 Num_debrief_stages++;
1087 if ( Promoted >= 0) {
1088 // move all stages forward one
1089 for ( i = Num_debrief_stages; i > 0; i-- ) {
1090 Debrief_stages[i] = Debrief_stages[i-1];
1092 Debrief_stages[0] = &Promotion_stage;
1093 Num_debrief_stages++;
1098 // function called from multiplayer clients to set up the debriefing information for them
1099 // (sent from the server).
1100 void debrief_set_multi_clients( int stage_count, int active_stages[] )
1104 // set up the right briefing for this guy
1105 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
1106 Debriefing = &Debriefings[Net_player->p_info.team];
1108 Debriefing = &Debriefings[0];
1111 // see if this client was promoted -- if so, then add the first stage.
1112 Num_debrief_stages = 0;
1114 // set the pointers to the debriefings for this client
1115 for (i = 0; i < stage_count; i++) {
1116 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
1119 Debrief_multi_stages_loaded = 1;
1122 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
1123 // information to all clients after leaving this screen.
1124 void debrief_multi_server_stuff()
1126 debriefing *debriefp;
1128 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1129 int i, j, num_stages, stage_count[MAX_TEAMS];
1131 memset( stage_active, 0, sizeof(stage_active) );
1133 for (i=0; i<Num_teams; i++) {
1134 debriefp = &Debriefings[i];
1136 stages[i] = stage_active[i];
1137 for (j=0; j<debriefp->num_stages; j++) {
1138 if ( eval_sexp(debriefp->stages[j].formula) ) {
1139 stage_active[i][num_stages] = j;
1144 stage_count[i] = num_stages;
1147 // if we're in campaign mode, evaluate campaign stuff
1148 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1149 multi_campaign_eval_debrief();
1152 // send the information to all clients.
1153 send_debrief_info( stage_count, stages );
1157 // --------------------------------------------------------------------------------------
1158 // debrief_set_stages_and_multi_stuff()
1160 // Set up the active stages for this debriefing
1162 // returns: number of active debriefing stages
1164 int debrief_set_stages_and_multi_stuff()
1167 debriefing *debriefp;
1169 if ( MULTIPLAYER_CLIENT ) {
1173 Num_debrief_stages = 0;
1175 if ( Game_mode & GM_MULTIPLAYER ) {
1176 debrief_multi_server_stuff();
1179 // check to see if player is a traitor (looking at his team). If so, use the special
1180 // traitor debriefing. Only done in single player
1181 debriefp = Debriefing;
1182 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1183 if (Player_ship->team == TEAM_TRAITOR)
1184 debriefp = &Traitor_debriefing;
1187 Num_debrief_stages = 0;
1188 if (Promoted >= 0) {
1189 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1192 if (Badge_bitmap >= 0) {
1193 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1196 for (i=0; i<debriefp->num_stages; i++) {
1197 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1198 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1202 return Num_debrief_stages;
1205 // init the buttons that are specific to the debriefing screen
1206 void debrief_buttons_init()
1211 for ( i=0; i<NUM_BUTTONS; i++ ) {
1212 b = &Buttons[gr_screen.res][i];
1213 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1214 // set up callback for when a mouse first goes over a button
1215 b->button.set_highlight_action( common_play_highlight_sound );
1216 b->button.set_bmaps(b->filename);
1217 b->button.link_hotspot(b->hotspot);
1221 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1222 // multiplayer specific text
1223 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1224 // only add if in multiplayer mode
1225 if(Game_mode & GM_MULTIPLAYER){
1226 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1231 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1235 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1236 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1237 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1238 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1239 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1240 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1241 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1242 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1244 // if in multiplayer, disable the button for all players except the host
1245 // also disable for squad war matches
1246 if(Game_mode & GM_MULTIPLAYER){
1247 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1248 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1253 // --------------------------------------------------------------------------------------
1254 // debrief_ui_init()
1256 void debrief_ui_init()
1258 // init ship selection masks and buttons
1259 common_set_interface_palette("DebriefPalette"); // set the interface palette
1260 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1261 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1262 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1263 debrief_buttons_init();
1265 // load in help overlay bitmap
1266 help_overlay_load(DEBRIEFING_OVERLAY);
1267 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1269 if ( Game_mode & GM_MULTIPLAYER ) {
1270 // close down any old instances of the chatbox
1273 // create the new one
1275 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1276 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);
1279 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1282 if ( Background_bitmap < 0 ) {
1283 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1286 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1287 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1290 // sets Promotion_stage.voice
1291 // defaults to number 9 (Petrarch) for non-volition missions
1292 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1293 void debrief_choose_promotion_voice()
1297 if(Campaign.current_mission < 0){
1298 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1302 // search thru all official campaigns for our current campaign
1303 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1304 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1305 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1306 // now search thru the mission filenames,
1307 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1308 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1309 // found it! set the persona and bail
1310 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1318 // default to petrarch
1319 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1322 // sets Promotion_stage.voice
1323 // defaults to number 9 (Petrarch) for non-volition missions
1324 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1325 void debrief_choose_badge_voice()
1331 if(Campaign.current_mission < 0){
1333 // default to petrarch
1334 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1336 // default to FS1 guy
1337 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1341 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1343 if ( Player->on_bastion ) {
1344 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base2);
1347 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1351 // search thru all official campaigns for our current campaign
1352 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1353 if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1354 // now search thru the mission filenames,
1355 for (j=0; j<Campaign.num_missions; j++) {
1356 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1357 // found it! set the persona and bail
1358 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1368 // default to petrarch
1369 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1371 // default to FS1 guy
1372 sprintf(Badge_stage.voice, NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1377 void debrief_award_init()
1389 // be sure there are no old award texts floating around
1391 debrief_award_text_clear();
1394 // handle medal earned
1395 if (Player->stats.m_medal_earned != -1) {
1396 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1398 if ( Player->stats.medals[13] > 1 ) {
1403 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1404 Wings_bitmap = bm_load(buf);
1406 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1407 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1410 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1411 Medal_bitmap = bm_load(buf);
1415 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1419 // handle promotions
1420 if ( Player->stats.m_promotion_earned != -1 ) {
1421 Promoted = Player->stats.m_promotion_earned;
1422 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1423 Rank_bitmap = bm_load(buf);
1425 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1426 Promotion_stage.new_recommendation_text = NULL;
1428 // choose appropriate promotion voice for this mission
1429 debrief_choose_promotion_voice();
1432 debrief_add_award_text(Ranks[Promoted].name);
1436 // handle badge earned
1437 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1438 if ( Player->stats.m_badge_earned != -1 ) {
1439 i = Player->stats.m_badge_earned;
1440 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1441 Badge_bitmap = bm_load(buf);
1443 Badge_stage.new_text = Badge_info[i].promotion_text;
1444 Badge_stage.new_recommendation_text = NULL;
1446 // choose appropriate voice
1447 debrief_choose_badge_voice();
1450 debrief_add_award_text(Medals[Badge_index[i]].name);
1454 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1461 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1462 // mission a traitor. The same debriefing always gets played
1463 void debrief_traitor_init()
1465 static int inited = 0;
1468 debriefing *debrief;
1469 debrief_stage *stagep;
1473 if ((rval = setjmp(parse_abort)) != 0) {
1474 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1477 read_file_text("traitor.tbl");
1481 // open localization
1484 // simplied form of the debriefing stuff.
1485 debrief = &Traitor_debriefing;
1486 required_string("#Debriefing_info");
1488 required_string("$Num stages:");
1489 stuff_int(&debrief->num_stages);
1490 Assert(debrief->num_stages == 1);
1493 stagep = &debrief->stages[stage_num++];
1494 required_string("$Formula:");
1495 stagep->formula = get_sexp_main();
1496 required_string("$multi text");
1497 if ( Fred_running ) {
1498 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1500 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1502 required_string("$Voice:");
1503 char traitor_voice_file[NAME_LENGTH];
1504 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1506 // DKA 9/13/99 Only 1 traitor msg for FS2
1508 if ( Player->on_bastion ) {
1509 strcpy(stagep->voice, NOX("3_"));
1511 strcpy(stagep->voice, NOX("1_"));
1515 strcat(stagep->voice, traitor_voice_file);
1517 required_string("$Recommendation text:");
1518 if ( Fred_running ) {
1519 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1521 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1525 // close localization
1529 // disable the accept button if in single player and I am a traitor
1530 Debrief_accepted = 0;
1531 Turned_traitor = Must_replay_mission = 0;
1532 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1533 if (Player_ship->team == TEAM_TRAITOR){
1537 if (Campaign.next_mission == Campaign.current_mission){
1538 Must_replay_mission = 1;
1542 if (Turned_traitor || Must_replay_mission) {
1543 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1545 // kill off any stats
1546 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1547 scoring_level_init( &Player->stats );
1551 // initialization for listing of players in game
1552 void debrief_multi_list_init()
1554 Multi_list_size = 0; // number of net players to choose from
1555 Multi_list_offset = 0;
1557 Multi_list_select = -1;
1559 if ( !(Game_mode & GM_MULTIPLAYER) )
1562 debrief_rebuild_player_list();
1564 // switch stats display to this newly selected player
1565 set_player_stats(Multi_list[0].net_player_index);
1566 strcpy(Debrief_current_callsign, Multi_list[0].callsign);
1567 Debrief_player = Player;
1570 void debrief_multi_list_scroll_up()
1572 // if we're at the beginning of the list, don't do anything
1573 if(Multi_list_offset == 0){
1574 gamesnd_play_iface(SND_GENERAL_FAIL);
1578 // otherwise scroll up
1579 Multi_list_offset--;
1580 gamesnd_play_iface(SND_USER_SELECT);
1583 void debrief_multi_list_scroll_down()
1585 // if we can scroll down no further
1586 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1587 gamesnd_play_iface(SND_GENERAL_FAIL);
1590 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1591 gamesnd_play_iface(SND_GENERAL_FAIL);
1595 // otherwise scroll down
1596 Multi_list_offset++;
1597 gamesnd_play_iface(SND_USER_SELECT);
1600 // draw the connected net players
1601 void debrief_multi_list_draw()
1603 int y, z, font_height,idx;
1604 char str[CALLSIGN_LEN+5];
1607 font_height = gr_get_font_height();
1609 // if we currently have no item picked, pick a reasonable one
1610 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1611 // select the entry which corresponds to the local player
1612 Multi_list_select = 0;
1613 for(idx=0;idx<Multi_list_size;idx++){
1614 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1615 Multi_list_select = idx;
1617 // switch stats display to this newly selected player
1618 set_player_stats(Multi_list[idx].net_player_index);
1619 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);
1620 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1626 // draw the list itself
1628 z = Multi_list_offset;
1629 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1630 np = &Net_players[Multi_list[z].net_player_index];
1632 if (z >= Multi_list_size){
1635 // set the proper text color for the highlight
1636 if(np->flags & NETINFO_FLAG_GAME_HOST){
1637 if(Multi_list_select == z){
1638 gr_set_color_fast(&Color_text_active_hi);
1640 gr_set_color_fast(&Color_bright);
1643 if(Multi_list_select == z){
1644 gr_set_color_fast(&Color_text_active);
1646 gr_set_color_fast(&Color_text_normal);
1650 // blit the proper indicator - skipping observers
1651 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1652 if(Netgame.type_flags & NG_TYPE_TEAM){
1654 if(np->p_info.team == 0){
1655 // draw his "selected" icon
1656 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1657 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1658 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1660 // draw his "normal" icon
1661 else if(Multi_common_icons[MICON_TEAM0] != -1){
1662 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1663 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1665 } else if(np->p_info.team == 1){
1666 // draw his "selected" icon
1667 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1668 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1669 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1671 // draw his "normal" icon
1672 else if(Multi_common_icons[MICON_TEAM1] != -1){
1673 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1674 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1678 // draw the team 0 selected icon
1679 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1680 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1681 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1686 strcpy(str,Multi_list[z].callsign);
1687 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)){
1688 strcat(str,XSTR( "(O)", 438));
1692 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1699 void debrief_kick_selected_player()
1701 if(Multi_list_select >= 0){
1702 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1703 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1707 // get optional mission popup text
1708 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1710 Assert(buffer != NULL);
1713 if (mission_loop_desc == NULL) {
1714 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1715 mprintf(("No mission loop description avail"));
1717 strcpy(buffer, mission_loop_desc);
1720 strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1723 // what to do when the accept button is hit
1724 void debrief_accept(int ok_to_post_start_game_event)
1728 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1732 if (Game_mode & GM_MULTIPLAYER) {
1736 if (Player_ship->team == TEAM_TRAITOR){
1737 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1738 }/* else if (Cheats_enabled) {
1739 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1741 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1744 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1746 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1747 } else if ( z == 1 ) {
1748 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1754 Debrief_accepted = 1;
1755 // save mission stats
1756 if (Game_mode & GM_MULTIPLAYER) {
1757 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1758 // as well as doing stats transfers, etc.
1759 multi_debrief_accept_hit();
1763 int play_commit_sound = 1;
1764 // only write the player's stats if he's accepted
1766 // if we are just playing a single mission, then don't do many of the things
1767 // that need to be done. Nothing much should happen when just playing a single
1768 // mission that isn't in a campaign.
1769 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1771 // check for possible mission loop
1772 // check for (1) mission loop available, (2) dont have to repeat last mission
1773 if(!(Game_mode & GM_MULTIPLAYER)){
1774 int cur = Campaign.current_mission;
1775 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1776 if (Campaign.missions[cur].has_mission_loop) {
1777 Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1780 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1783 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1785 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1787 Campaign.loop_enabled = 1;
1788 Campaign.next_mission = Campaign.loop_mission;
1797 if(ok_to_post_start_game_event){
1798 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1800 play_commit_sound = 0;
1803 // continue as normal
1806 mission_campaign_mission_over();
1808 // check to see if we are out of the loop now
1809 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1810 Campaign.loop_enabled = 0;
1813 // check if campaign is over
1814 if ( Campaign.next_mission == -1 ) {
1815 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
1816 gameseq_post_event(GS_EVENT_END_DEMO);
1818 gameseq_post_event(GS_EVENT_MAIN_MENU);
1821 if ( ok_to_post_start_game_event ) {
1823 if(game_do_cd_mission_check(Game_current_mission_filename)){
1824 gameseq_post_event(GS_EVENT_START_GAME);
1826 gameseq_post_event(GS_EVENT_MAIN_MENU);
1829 play_commit_sound = 0;
1834 gameseq_post_event(GS_EVENT_MAIN_MENU);
1837 if ( play_commit_sound ) {
1838 gamesnd_play_iface(SND_COMMIT_PRESSED);
1845 void debrief_next_tab()
1847 New_mode = Current_mode + 1;
1848 if (New_mode >= NUM_TABS)
1852 void debrief_prev_tab()
1854 New_mode = Current_mode - 1;
1856 New_mode = NUM_TABS - 1;
1859 // --------------------------------------------------------------------------------------
1860 // debrief_next_stage()
1862 void debrief_next_stage()
1864 if (Current_stage < Num_stages - 1) {
1865 New_stage = Current_stage + 1;
1866 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1869 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1872 // --------------------------------------------------------------------------------------
1873 // debrief_prev_stage()
1875 void debrief_prev_stage()
1877 if (Current_stage) {
1878 New_stage = Current_stage - 1;
1879 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1882 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1885 // --------------------------------------------------------------------------------------
1886 // debrief_first_stage()
1887 void debrief_first_stage()
1889 if (Current_stage) {
1891 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1894 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1897 // --------------------------------------------------------------------------------------
1898 // debrief_last_stage()
1899 void debrief_last_stage()
1901 if (Current_stage != Num_stages - 1) {
1902 New_stage = Num_stages - 1;
1903 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1906 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1909 // draw what stage number the debriefing is on
1910 void debrief_render_stagenum()
1918 sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1919 gr_get_string_size(&w, NULL, buf);
1920 gr_set_color_fast(&Color_bright_blue);
1921 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1922 gr_set_color_fast(&Color_white);
1925 // render the mission time at the specified y location
1926 void debrief_render_mission_time(int y_loc)
1930 game_format_time(Missiontime, time_str);
1931 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1932 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1935 // render out the debriefing text to the scroll window
1936 void debrief_render()
1938 int y, z, font_height;
1940 if ( Num_stages <= 0 )
1943 font_height = gr_get_font_height();
1945 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]);
1948 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1949 if (z >= Num_text_lines)
1952 if (Text_type[z] == TEXT_TYPE_NORMAL)
1953 gr_set_color_fast(&Color_white);
1955 gr_set_color_fast(&Color_bright_red);
1958 gr_string(0, y, Text[z]);
1967 // render out the stats info to the scroll window
1969 void debrief_stats_render()
1971 int i, y, font_height;
1973 gr_set_color_fast(&Color_blue);
1974 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]);
1975 gr_string(0, 0, Debrief_current_callsign);
1976 font_height = gr_get_font_height();
1979 switch ( Current_stage ) {
1980 case DEBRIEF_MISSION_STATS:
1981 i = Current_stage - 1;
1985 gr_set_color_fast(&Color_white);
1987 // display mission completion time
1988 debrief_render_mission_time(y);
1991 show_stats_label(i, 0, y, font_height);
1992 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1994 case DEBRIEF_ALLTIME_STATS:
1995 i = Current_stage - 1;
1999 gr_set_color_fast(&Color_white);
2000 show_stats_label(i, 0, y, font_height);
2001 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2004 case DEBRIEF_ALLTIME_KILLS:
2005 case DEBRIEF_MISSION_KILLS:
2006 gr_set_color_fast(&Color_white);
2008 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
2009 if (i >= Num_text_lines)
2013 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2014 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
2016 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
2019 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
2020 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
2027 if (Num_text_lines == 2) {
2028 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2029 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
2031 gr_printf(0, y, XSTR( "(No ship kills)", 450));
2044 // do action for when the replay button is pressed
2045 void debrief_replay_pressed()
2047 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2049 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));
2056 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
2057 gamesnd_play_iface(SND_COMMIT_PRESSED);
2060 // -------------------------------------------------------------------
2061 // debrief_redraw_pressed_buttons()
2063 // Redraw any debriefing buttons that are pressed down. This function is needed
2064 // since we sometimes need to draw pressed buttons last to ensure the entire
2065 // button gets drawn (and not overlapped by other buttons)
2067 void debrief_redraw_pressed_buttons()
2072 for ( i=0; i<NUM_BUTTONS; i++ ) {
2073 b = &Buttons[gr_screen.res][i].button;
2074 // don't draw the recommendations button if we're in stats mode
2075 if ( b->button_down() ) {
2081 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
2083 void debrief_button_pressed(int num)
2087 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
2088 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
2089 if (num != Current_mode){
2090 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2095 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
2096 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
2097 if (num != Current_mode){
2098 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2103 case TEXT_SCROLL_UP:
2106 gamesnd_play_iface(SND_SCROLL);
2108 gamesnd_play_iface(SND_GENERAL_FAIL);
2112 case TEXT_SCROLL_DOWN:
2113 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2115 gamesnd_play_iface(SND_SCROLL);
2117 gamesnd_play_iface(SND_GENERAL_FAIL);
2121 case REPLAY_MISSION:
2122 if(Game_mode & GM_MULTIPLAYER){
2123 multi_debrief_replay_hit();
2125 debrief_replay_pressed();
2129 case RECOMMENDATIONS:
2130 gamesnd_play_iface(SND_USER_SELECT);
2131 Recommend_active = !Recommend_active;
2132 debrief_text_init();
2136 debrief_first_stage();
2140 debrief_prev_stage();
2144 debrief_next_stage();
2148 debrief_last_stage();
2152 gamesnd_play_iface(SND_HELP_PRESSED);
2153 launch_context_help();
2156 case OPTIONS_BUTTON:
2157 gamesnd_play_iface(SND_SWITCH_SCREENS);
2158 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2166 gamesnd_play_iface(SND_SWITCH_SCREENS);
2167 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2170 case PLAYER_SCROLL_UP:
2171 debrief_multi_list_scroll_up();
2174 case PLAYER_SCROLL_DOWN:
2175 debrief_multi_list_scroll_down();
2178 case MULTI_PINFO_POPUP:
2179 Debrief_should_show_popup = 1;
2183 debrief_kick_selected_player();
2188 void debrief_setup_ship_kill_stats(int stage_num)
2192 debrief_stats_kill_info *kill_info;
2194 Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2195 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2198 Assert(Debrief_player != NULL);
2200 // kill_ar points to an array of MAX_SHIP_TYPE ints
2201 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2202 kill_arr = Debrief_player->stats.m_okKills;
2204 kill_arr = Debrief_player->stats.kills;
2208 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2210 // code used to add in mission kills, but the new system assumes that the player will accept, so
2211 // all time stats already have mission stats added in.
2212 if ( kill_arr[i] <= 0 ){
2217 kill_info = &Debrief_stats_kills[Num_text_lines++];
2219 kill_info->num = kill_arr[i];
2221 strcpy(kill_info->text, Ship_info[i].name);
2222 strcat(kill_info->text, NOX(":"));
2225 Num_text_lines += 2;
2228 // Iterate through the debriefing buttons, checking if they are pressed
2229 void debrief_check_buttons()
2233 for ( i=0; i<NUM_BUTTONS; i++ ) {
2234 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2235 debrief_button_pressed(i);
2239 if ( !(Game_mode & GM_MULTIPLAYER) )
2242 if (List_region.pressed()) {
2243 List_region.get_mouse_pos(NULL, &y);
2244 z = Multi_list_offset + y / gr_get_font_height();
2245 if ((z >= 0) && (z < Multi_list_size)) {
2246 // switch stats display to this newly selected player
2247 set_player_stats(Multi_list[z].net_player_index);
2248 strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2249 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2250 Multi_list_select = z;
2251 debrief_setup_ship_kill_stats(Current_stage);
2252 gamesnd_play_iface(SND_USER_SELECT);
2256 // if the player was double clicked on - we should popup a player info popup
2258 if (List_region.double_clicked()) {
2259 Debrief_should_show_popup = 1;
2264 void debrief_text_stage_init(char *src, int type)
2266 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2267 char line[MAX_DEBRIEF_LINE_LEN];
2268 char *p_str[MAX_DEBRIEF_LINES];
2270 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2271 Assert(n_lines >= 0);
2273 // if you hit this, you proba
2274 if(n_lines >= MAX_DEBRIEF_LINES){
2275 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2278 for ( i=0; i<n_lines; i++ ) {
2279 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2280 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2281 strncpy(line, p_str[i], n_chars[i]);
2282 line[n_chars[i]] = 0;
2283 drop_white_space(line);
2284 Text_type[Num_text_lines] = type;
2285 Text[Num_text_lines++] = strdup(line);
2291 void debrief_free_text()
2295 for (i=0; i<Num_debrief_lines; i++)
2299 Num_debrief_lines = 0;
2302 // setup the debriefing text lines for rendering
2303 void debrief_text_init()
2308 // release old text lines first
2309 debrief_free_text();
2310 Num_text_lines = Text_offset = 0;
2312 if (Current_mode == DEBRIEF_TAB) {
2313 for (i=0; i<Num_debrief_stages; i++) {
2315 Text[Num_text_lines++] = NULL; // add a blank line between stages
2317 src = Debrief_stages[i]->new_text;
2319 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2321 if (Recommend_active) {
2322 src = Debrief_stages[i]->new_recommendation_text;
2323 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2324 src = XSTR( "We have no recommendations for you.", 1054);
2327 Text[Num_text_lines++] = NULL;
2328 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2334 Num_debrief_lines = Num_text_lines;
2338 // not in debriefing mode, must be in stats mode
2340 debrief_setup_ship_kill_stats(Current_stage);
2344 // --------------------------------------------------------------------------------------
2348 Assert(!Debrief_inited);
2349 // Campaign.loop_enabled = 0;
2350 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2352 // set up the right briefing for this guy
2353 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2354 Debriefing = &Debriefings[Net_player->p_info.team];
2356 Debriefing = &Debriefings[0];
2359 // no longer is mission
2360 Game_mode &= ~(GM_IN_MISSION);
2364 New_mode = DEBRIEF_TAB;
2365 Recommend_active = Award_active = 0;
2370 Debrief_cue_voice = 0;
2371 Num_text_lines = Num_debrief_lines = 0;
2372 Debrief_first_voice_flag = 1;
2374 Debrief_multi_voice_loaded = 0;
2377 Medal_text_bitmap = bm_load(NOX("DebriefText01"));
2378 Rank_text_bitmap = bm_load(NOX("DebriefText02"));
2379 Badge_text_bitmap = bm_load(NOX("DebriefText03"));
2382 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2383 // MUST store goals and events first - may be used to evaluate next mission
2384 // store goals and events
2385 mission_campaign_store_goals_and_events();
2387 // evaluate next mission
2388 mission_campaign_eval_next_mission();
2391 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2393 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2394 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2397 // call scoring level close for my stats. Needed for award_init. The stats will
2398 // be backed out if used chooses to replace them.
2399 scoring_level_close();
2401 debrief_ui_init(); // init UI items
2402 debrief_award_init();
2404 debrief_voice_init();
2405 debrief_multi_list_init();
2406 // rank_bitmaps_clear();
2407 // rank_bitmaps_load();
2409 strcpy(Debrief_current_callsign, Player->callsign);
2410 Debrief_player = Player;
2411 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2413 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2414 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2415 // info directly from the server.
2416 if ( !MULTIPLAYER_CLIENT ) {
2417 debrief_set_stages_and_multi_stuff();
2419 if ( Num_debrief_stages <= 0 ) {
2420 Num_debrief_stages = 0;
2422 debrief_voice_load_all();
2425 // multiplayer client may have already received their debriefing info. If they have not,
2426 // then set the num debrief stages to 0
2427 if ( !Debrief_multi_stages_loaded ) {
2428 Num_debrief_stages = 0;
2433 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2434 common_music_init(SCORE_DEBRIEF_SUCCESS);
2436 common_music_init(SCORE_DEBRIEF_FAIL);
2440 // start up the appropriate music
2441 if (Campaign.next_mission == Campaign.current_mission) {
2442 // you failed the mission because you suck, so you get the suck music
2443 common_music_init(SCORE_DEBRIEF_FAIL);
2444 } else if (mission_goals_met()) {
2445 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2446 common_music_init(SCORE_DEBRIEF_SUCCESS);
2448 // you somehow passed the mission, so you get a little something for your efforts.
2449 common_music_init(SCORE_DEBRIEF_AVERAGE);
2452 if (Campaign.next_mission == Campaign.current_mission) {
2453 // better luck next time, increase his retries
2454 Player->failures_this_session++;
2456 // clear his retries info regardless of whether or not he accepts
2457 Player->failures_this_session = 0;
2460 if (Game_mode & GM_MULTIPLAYER) {
2461 multi_debrief_init();
2463 // if i'm not the host of the game, disable the multi kick button
2464 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2465 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2468 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2469 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2470 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2471 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2472 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2473 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2474 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2475 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2478 if (!Award_active) {
2479 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2480 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2483 Debrief_skip_popup_already_shown = 0;
2488 // --------------------------------------------------------------------------------------
2490 void debrief_close()
2494 Assert(Debrief_inited);
2496 // if the mission wasn't accepted, clear out my stats
2497 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2498 // are a little bit different
2499 if (Game_mode & GM_MULTIPLAYER) {
2500 // if stats weren't accepted, backout my own stats
2501 if (multi_debrief_stats_accept_code() != 1) {
2502 if(MULTIPLAYER_MASTER){
2503 for(idx=0; idx<MAX_PLAYERS; idx++){
2504 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2505 scoring_backout_accept(&Net_players[idx].player->stats);
2509 scoring_backout_accept( &Player->stats );
2514 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2515 scoring_backout_accept( &Player->stats );
2519 // if dude passed the misson and accepted, reset his show skip popup flag
2520 if (Debrief_accepted) {
2521 Player->show_skip_popup = 1;
2524 if (Num_debrief_lines) {
2525 for (i=0; i<Num_debrief_lines; i++){
2532 // unload the overlay bitmap
2534 help_overlay_unload(DEBRIEFING_OVERLAY);
2537 // clear out award text
2538 Debrief_award_text_num_lines = 0;
2540 debrief_voice_unload_all();
2541 common_music_close();
2544 // rank_bitmaps_release();
2547 if (Background_bitmap >= 0){
2548 bm_unload(Background_bitmap);
2551 if (Award_bg_bitmap >= 0){
2552 bm_unload(Award_bg_bitmap);
2555 if (Rank_bitmap >= 0){
2556 bm_unload(Rank_bitmap);
2559 if (Medal_bitmap >= 0){
2560 bm_unload(Medal_bitmap);
2563 if (Badge_bitmap >= 0){
2564 bm_unload(Badge_bitmap);
2567 if (Wings_bitmap >= 0) {
2568 bm_unload(Wings_bitmap);
2571 if (Crest_bitmap >= 0) {
2572 bm_unload(Crest_bitmap);
2576 if (Medal_text_bitmap >= 0) {
2577 bm_unload(Medal_text_bitmap);
2580 if (Badge_text_bitmap >= 0) {
2581 bm_unload(Badge_text_bitmap);
2584 if (Rank_text_bitmap >= 0) {
2585 bm_unload(Rank_text_bitmap);
2589 Debrief_ui_window.destroy();
2590 common_free_interface_palette(); // restore game palette
2593 if (Game_mode & GM_MULTIPLAYER){
2594 multi_debrief_close();
2602 // handle keypresses in debriefing
2603 void debrief_do_keys(int new_k)
2610 case KEY_SHIFTED | KEY_TAB:
2618 // multiplayer accept popup is a little bit different
2619 if (Game_mode & GM_MULTIPLAYER) {
2620 multi_debrief_esc_hit();
2622 // display the normal debrief popup
2624 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2625 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2626 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2627 if (choice == 1) { // accept and continue on
2629 gameseq_post_event(GS_EVENT_MAIN_MENU);
2635 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2636 // need to popup saying that mission was a failure and must be replayed
2637 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));
2642 // Return to Main Hall
2643 gameseq_post_event(GS_EVENT_END_GAME);
2654 void debrief_draw_award_text()
2656 int start_y, curr_y, i, x, sw;
2657 int fh = gr_get_font_height();
2658 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];
2660 // vertically centered within field
2661 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);
2665 for (i=0; i<Debrief_award_text_num_lines; i++) {
2666 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2667 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2668 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2669 gr_set_color_fast(&Color_white);
2670 gr_string(x, curr_y, Debrief_award_text[i]);
2672 // adjust y pos, including a little extra between the "pairs"
2674 if ((i == 1) || (i == 3)) {
2675 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2680 // clears out text array so we dont have old award text showing up on new awards.
2681 void debrief_award_text_clear() {
2684 Debrief_award_text_num_lines = 0;
2685 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2686 //Debrief_award_text[i][0] = 0;
2687 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2691 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2692 void debrief_add_award_text(char *str)
2694 Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2695 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2700 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];
2703 strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);
2705 // maybe translate for displaying
2707 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2710 Debrief_award_text_num_lines++;
2712 // if its too long, split once ONLY
2713 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2714 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2715 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2716 if (line2 != NULL) {
2717 sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2); // indent a space
2719 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2722 #endif // !MAKE_FS1: No text for FS1, it's all bitmaps
2724 // called once per frame to drive all the input reading and rendering
2725 void debrief_do_frame(float frametime)
2728 char *please_wait_str = XSTR("Please Wait", 1242);
2732 Assert(Debrief_inited);
2734 // first thing is to load the files
2735 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2736 // draw the background, etc
2737 GR_MAYBE_CLEAR_RES(Background_bitmap);
2738 if (Background_bitmap >= 0) {
2739 gr_set_bitmap(Background_bitmap);
2743 Debrief_ui_window.draw();
2745 if ( Debrief_multi_loading_bitmap > -1 ){
2746 gr_set_bitmap(Debrief_multi_loading_bitmap);
2747 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2750 // draw "Please Wait"
2751 gr_set_color_fast(&Color_normal);
2753 gr_get_string_size(&str_w, &str_h, please_wait_str);
2754 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2759 // make sure we run the debrief do frame
2760 if (Game_mode & GM_MULTIPLAYER) {
2761 multi_debrief_do_frame();
2766 int keypress = game_check_key();
2767 if(keypress == KEY_ESC){
2769 multi_quit_game(PROMPT_CLIENT);
2775 // if multiplayer client, and not loaded voice, then load it
2776 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2777 debrief_multi_fixup_stages();
2778 debrief_voice_load_all();
2779 Debrief_multi_voice_loaded = 1;
2782 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2783 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2784 Debrief_ui_window.set_ignore_gadgets(1);
2787 k = chatbox_process();
2788 if ( Game_mode & GM_NORMAL ) {
2789 new_k = Debrief_ui_window.process(k);
2791 new_k = Debrief_ui_window.process(k, 0);
2794 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2795 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2796 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2797 Debrief_ui_window.set_ignore_gadgets(0);
2803 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2804 Debrief_ui_window.set_ignore_gadgets(0);
2807 // don't show pilot info popup by default
2808 Debrief_should_show_popup = 0;
2810 // see if the mode has changed and handle it if so.
2811 if ( Current_mode != New_mode ) {
2812 debrief_voice_stop();
2813 Current_mode = New_mode;
2816 if (New_mode == DEBRIEF_TAB) {
2818 Debrief_cue_voice = 0;
2820 if (Debrief_first_voice_flag) {
2821 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2822 Debrief_first_voice_flag = 0;
2825 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2829 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2830 Current_stage = New_stage;
2831 debrief_text_init();
2834 debrief_voice_play();
2837 if (Game_mode & GM_MULTIPLAYER) {
2838 multi_debrief_do_frame();
2841 // Now do all the rendering for the frame
2842 GR_MAYBE_CLEAR_RES(Background_bitmap);
2843 if (Background_bitmap >= 0) {
2844 gr_set_bitmap(Background_bitmap);
2848 // draw the damn awarded stuff, G
2849 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2850 gr_set_bitmap(Award_bg_bitmap);
2851 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2852 if (Rank_bitmap >= 0) {
2853 gr_set_bitmap(Rank_bitmap);
2855 gr_bitmap(Debrief_rank_coords[0], Debrief_rank_coords[1]);
2857 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2861 if (Medal_bitmap >= 0) {
2862 gr_set_bitmap(Medal_bitmap);
2863 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2866 if (Badge_bitmap >= 0) {
2867 gr_set_bitmap(Badge_bitmap);
2869 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2871 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2875 if (Wings_bitmap >= 0) {
2876 gr_set_bitmap(Wings_bitmap);
2878 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2880 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2884 // this isn't used in FS1 but doesn't hurt to leave it
2885 if (Crest_bitmap >= 0) {
2886 gr_set_bitmap(Crest_bitmap);
2887 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2890 // draw medal/badge/rank labels
2892 debrief_draw_award_text();
2894 if (Rank_text_bitmap >= 0) {
2895 gr_set_bitmap(Rank_text_bitmap);
2896 gr_bitmap(Debrief_rank_text_coords[gr_screen.res][0], Debrief_rank_text_coords[gr_screen.res][1]);
2899 if (Medal_text_bitmap >= 0) {
2900 gr_set_bitmap(Medal_text_bitmap);
2901 gr_bitmap(Debrief_medal_text_coords[gr_screen.res][0], Debrief_medal_text_coords[gr_screen.res][1]);
2904 if (Badge_text_bitmap >= 0) {
2905 gr_set_bitmap(Badge_text_bitmap);
2906 gr_bitmap(Debrief_badge_text_coords[gr_screen.res][0], Debrief_badge_text_coords[gr_screen.res][1]);
2911 Debrief_ui_window.draw();
2912 debrief_redraw_pressed_buttons();
2913 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2914 if (Recommend_active && (Current_mode != STATS_TAB)) {
2915 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2918 // draw the title of the mission
2919 gr_set_color_fast(&Color_bright_white);
2920 strcpy(buf, The_mission.name);
2921 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2922 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2924 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2925 gr_set_color_fast(&Color_normal);
2926 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);
2929 // draw the screen-specific text
2930 switch (Current_mode) {
2932 if ( Num_debrief_stages <= 0 ) {
2933 gr_set_color_fast(&Color_white);
2934 Assert( Game_current_mission_filename != NULL );
2935 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);
2944 debrief_stats_render();
2948 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2951 gr_set_color_fast(&Color_red);
2952 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2953 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));
2956 debrief_render_stagenum();
2957 debrief_multi_list_draw();
2959 // render some extra stuff in multiplayer
2960 if (Game_mode & GM_MULTIPLAYER) {
2961 // render the chatbox last
2965 Debrief_ui_window.draw_tooltip();
2967 // render the status indicator for the voice system
2968 multi_common_voice_display_status();
2971 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2972 // want to include the mouse pointer which is drawn in the flip
2974 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2975 debrief_check_buttons();
2976 debrief_do_keys(new_k);
2979 // blit help overlay if active
2980 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2984 // dont let dude skip 3-09. hack.
2985 if(Game_mode & GM_CAMPAIGN_MODE){
2986 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2987 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2988 Debrief_skip_popup_already_shown = 1;
2993 // maybe show skip mission popup
2994 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)) {
2995 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
2996 XSTR("Advance To The Next Mission", 1474),
2997 XSTR("Don't Show Me This Again", 1475),
2998 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
2999 switch (popup_choice) {
3001 // stay on this mission, so proceed to normal debrief
3002 // in other words, do nothing.
3005 // skip this mission
3006 mission_campaign_skip_to_next();
3007 gameseq_post_event(GS_EVENT_START_GAME);
3010 // dont show this again
3011 Player->show_skip_popup = 0;
3015 Debrief_skip_popup_already_shown = 1;
3018 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
3019 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
3020 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
3021 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
3023 Debrief_should_show_popup = 0;
3027 void debrief_rebuild_player_list()
3031 debrief_multi_list_info *list;
3033 Multi_list_size = 0; // number of net players to choose from
3035 for ( i=0; i<MAX_PLAYERS; i++ ) {
3036 np = &Net_players[i];
3037 // remember not to include the standalone.
3038 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
3039 list = &Multi_list[Multi_list_size++];
3040 list->net_player_index = i;
3041 strcpy(list->callsign, np->player->callsign);
3043 // make sure to leave some room to blit the team indicator
3044 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
3049 void debrief_handle_player_drop()
3051 debrief_rebuild_player_list();
3054 void debrief_disable_accept()