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.14 2006/04/26 19:43:25 taylor
19 * this should squash the first second double-play of debriefing voice
21 * Revision 1.13 2005/08/12 08:52:32 taylor
22 * various GCC4 warning fixes
24 * Revision 1.12 2005/03/29 02:18:47 taylor
25 * Various 64-bit platform fixes
26 * Fix compiler errors with MAKE_FS1 and fix gr_set_bitmap() too
27 * Make sure that turrets can fire at asteroids for FS1 (needed for a couple missions)
28 * Streaming audio support (big thanks to Pierre Willenbrock!!)
29 * Removed dependance on strings.tbl for FS1 since we don't actually need it now
31 * Revision 1.11 2004/09/20 01:31:44 theoddone33
34 * Revision 1.10 2004/07/04 11:39:06 taylor
35 * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
37 * Revision 1.9 2003/08/03 16:10:29 taylor
38 * cleanup; compile warning fixes
40 * Revision 1.8 2003/06/03 04:00:40 taylor
41 * Polish language support (Janusz Dziemidowicz)
43 * Revision 1.7 2003/05/25 02:30:43 taylor
46 * Revision 1.6 2002/07/13 06:46:48 theoddone33
49 * Revision 1.5 2002/06/09 04:41:23 relnev
50 * added copyright header
52 * Revision 1.4 2002/06/02 04:26:34 relnev
55 * Revision 1.3 2002/05/26 22:06:17 relnev
56 * makefile: disable stand_gui for now.
58 * rest: staticize some globals
60 * Revision 1.2 2002/05/07 03:16:46 theoddone33
61 * The Great Newline Fix
63 * Revision 1.1.1.1 2002/05/03 03:28:10 root
67 * 57 10/29/99 10:40p Jefff
68 * hack to make german medal names display without actually changing them
70 * 56 10/13/99 3:26p Jefff
71 * fixed unnumbered XSTRs
73 * 55 10/06/99 10:28a Jefff
76 * 54 9/30/99 5:57p Jefff
77 * show upsell at end of campaign in OEM builds
79 * 53 9/15/99 3:42a Jefff
82 * 52 9/14/99 4:35a Dave
83 * Argh. Added all kinds of code to handle potential crashes in debriefing
86 * 51 9/14/99 3:26a Dave
87 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
88 * respawn-too-early problem. Made a few crash points safe.
90 * 50 9/14/99 12:51a Jefff
92 * 49 9/13/99 6:01p Jefff
93 * fixed wrong promotion voice mapping for sm1-08
95 * 48 9/13/99 11:15a Jefff
96 * clear out award text bug fixed
98 * 47 9/13/99 12:17p Andsager
99 * Fix traitor debrief not playinf for FS2. Don't append _3 or _1 as in
102 * 46 9/07/99 9:35p Jefff
103 * fixed bug where award text was not getting cleared properly between
106 * 45 9/07/99 6:56p Jefff
107 * a few adjustments to loop detection
109 * 44 9/07/99 1:54p Jefff
110 * skip mission cleanup
112 * 43 9/06/99 9:45p Jefff
113 * skip mission support
115 * 42 9/06/99 6:38p Dave
116 * Improved CD detection code.
118 * 41 9/03/99 1:32a Dave
119 * CD checking by act. Added support to play 2 cutscenes in a row
120 * seamlessly. Fixed super low level cfile bug related to files in the
121 * root directory of a CD. Added cheat code to set campaign mission # in
124 * 40 9/02/99 3:45p Jefff
125 * forgot to remove some debug code. doh.
127 * 39 9/02/99 3:41p Jefff
128 * changed badge voice handling to be similar to promotion voice handling
130 * 38 9/01/99 4:41p Jefff
131 * fixed stoopid text color bug
133 * 37 8/31/99 11:54a Jefff
134 * minor debrief music tweak
136 * 36 8/27/99 9:57a Dave
137 * Enabled standard cheat codes. Allow player to continue in a campaing
138 * after using cheat codes.
140 * 35 8/27/99 12:04a Dave
141 * Campaign loop screen.
143 * 34 8/26/99 8:49p Jefff
144 * Updated medals screen and about everything that ever touches medals in
145 * one way or another. Sheesh.
147 * 33 8/20/99 4:20p Jefff
148 * hack for choosing the correct promotion voice
150 * 32 8/16/99 4:05p Dave
151 * Big honking checkin.
153 * 31 8/16/99 9:49a Jefff
154 * mission title length fix in multi
156 * 30 8/11/99 5:33p Jefff
157 * added 3rd debrief music track
159 * 29 8/10/99 7:28p Jefff
160 * shuffled some text around
162 * 28 8/04/99 5:36p Andsager
163 * Show upsell screens at end of demo campaign before returning to main
166 * 27 8/04/99 2:07p Jefff
167 * mission title no longer overwrites popup
169 * 26 8/02/99 5:37p Jefff
171 * 25 8/02/99 4:52p Jefff
172 * negative feedback sound when recommendations button pressed and
175 * 24 7/21/99 6:21p Jefff
176 * added hotkeys to the "you cannot accept" popup
178 * 23 6/15/99 12:04p Anoop
179 * Added a warning for running out of debrief text lines.
181 * 22 6/09/99 2:17p Dave
182 * Fixed up pleasewait bitmap rendering.
184 * 21 6/01/99 6:07p Dave
185 * New loading/pause/please wait bar.
187 * 20 5/22/99 6:05p Dave
188 * Fixed a few localization # problems.
190 * 19 5/22/99 5:35p Dave
191 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
193 * 18 3/20/99 3:47p Andsager
194 * Fix crash with no mission loop description.
196 * 17 2/23/99 2:29p Dave
197 * First run of oldschool dogfight mode.
199 * 16 2/21/99 6:01p Dave
200 * Fixed standalone WSS packets.
202 * 15 2/11/99 3:08p Dave
203 * PXO refresh button. Very preliminary squad war support.
205 * 14 1/30/99 5:08p Dave
206 * More new hi-res stuff.Support for nice D3D textures.
208 * 13 1/29/99 2:08a Dave
209 * Fixed beam weapon collisions with players. Reduced size of scoring
210 * struct for multiplayer. Disabled PXO.
212 * 12 1/14/99 5:15p Neilk
213 * changed credits, command debrief interfaces to high resolution support
215 * 11 1/13/99 2:11p Andsager
216 * change default debriefing string text
218 * 10 12/17/98 4:50p Andsager
219 * Added debrief_assemble_optional_mission_popup_text() for single and
222 * 9 12/12/98 3:17p Andsager
223 * Clean up mission eval, goal, event and mission scoring.
225 * 8 12/10/98 10:19a Andsager
226 * Fix mission loop assert
228 * 7 12/10/98 9:59a Andsager
229 * Fix some bugs with mission loops
231 * 6 12/09/98 1:56p Andsager
232 * Initial checkin of mission loop
234 * 5 11/05/98 4:18p Dave
235 * First run nebula support. Beefed up localization a bit. Removed all
236 * conditional compiles for foreign versions. Modified mission file
239 * 4 10/23/98 3:51p Dave
240 * Full support for tstrings.tbl and foreign languages. All that remains
241 * is to make it active in Fred.
243 * 3 10/13/98 9:28a Dave
244 * Started neatening up freespace.h. Many variables renamed and
245 * reorganized. Added AlphaColors.[h,cpp]
247 * 2 10/07/98 10:53a Dave
250 * 1 10/07/98 10:49a Dave
252 * 178 9/17/98 3:08p Dave
253 * PXO to non-pxo game warning popup. Player icon stuff in create and join
254 * game screens. Upped server count refresh time in PXO to 35 secs (from
257 * 177 7/07/98 1:46p Dave
258 * Fixed nasty debriefing badge/promotion bug. Added extra physics info
261 * 175 6/09/98 10:31a Hoffoss
262 * Created index numbers for all xstr() references. Any new xstr() stuff
263 * added from here on out should be added to the end if the list. The
264 * current list count can be found in FreeSpace.cpp (search for
267 * 174 6/07/98 3:26p Lawrance
268 * Fix bug with cut-off popup text
270 * 173 6/05/98 9:54a Lawrance
273 * 172 6/01/98 11:43a John
274 * JAS & MK: Classified all strings for localization.
276 * 171 5/27/98 1:24p Allender
277 * make targeting dots work (as well as other targeting features) properly
278 * in multiplayer. Don't query for CD when entering debrief in
281 * 170 5/26/98 11:10a Lawrance
282 * Fix bug where window controls get disabled when F1 pressed twice
284 * 169 5/24/98 12:55a Mike
285 * Prevent SDL_assert() when no debriefing text for a stage.
287 * 168 5/23/98 10:38p Lawrance
288 * Avoid doing a cfile refresh when running debug
290 * 167 5/23/98 6:49p Lawrance
291 * Fix problems with refreshing the file list when a CD is inserted
293 * 166 5/21/98 6:57p Lawrance
294 * Don't prompt for the CD if voice not found
296 * 165 5/20/98 2:24a Dave
297 * Fixed server side voice muting. Tweaked multi debrief/endgame
298 * sequencing a bit. Much friendlier for stats tossing/accepting now.
300 * 164 5/19/98 8:35p Dave
301 * Revamp PXO channel listing system. Send campaign goals/events to
302 * clients for evaluation. Made lock button pressable on all screens.
304 * 163 5/19/98 11:13a Hoffoss
305 * Fixed bug where wrong wings award was being displayed in debriefing.
307 * 162 5/19/98 12:28a Mike
310 * 161 5/18/98 8:08p Hoffoss
311 * Moved placement of 'More' text.
313 * 160 5/18/98 3:50p Dan
314 * AL: Pick correct traitor debriefing voice file
316 * 159 5/17/98 6:32p Dave
317 * Make sure clients/servers aren't kicked out of the debriefing when team
318 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
319 * xfer/pilot info popup stuff.
321 * 158 5/16/98 9:14p Allender
322 * fix scoring ckise fir training missions to actually count medals, but
323 * nothing else. Code used to SDL_assert when wings were granted then taken
324 * away because they were actually never granted in scoring structure
326 * 157 5/15/98 5:15p Dave
327 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
328 * status for team vs. team. Put in asserts to check for invalid team vs.
331 * 156 5/15/98 4:36p Allender
332 * fixed minor bug with wings
334 * 155 5/15/98 4:12p Allender
335 * removed redbook code. Put back in ingame join timer. Major fixups for
336 * stats in multiplayer. Pass correct score, medals, etc when leaving
337 * game. Be sure clients display medals, badges, etc.
339 * 154 5/15/98 2:25p Jasen
340 * temporarily disable granting of promotion and badges for clients
342 * 153 5/15/98 10:57a Allender
343 * fixed client side debriefings
345 * 152 5/15/98 10:36a Dave
346 * Removed 2 bogus bitmap drawing Int3()'s
348 * 151 5/14/98 2:44p Hoffoss
349 * Added wings awarding to debrief screen.
351 * 150 5/13/98 9:11p Lawrance
352 * Make 'replay mission' popup warn users about the loss of mission stats.
357 #include "missiondebrief.h"
358 #include "missionbriefcommon.h"
359 #include "missionscreencommon.h"
360 #include "missiongoals.h"
361 #include "missionpause.h"
362 #include "freespace.h"
363 #include "gamesequence.h"
371 #include "audiostr.h"
374 #include "contexthelp.h"
380 #include "multimsgs.h"
381 #include "multiutil.h"
382 #include "multiteamselect.h"
384 #include "eventmusic.h"
388 #include "multi_pinfo.h"
389 #include "contexthelp.h"
390 #include "multi_kick.h"
391 #include "multi_campaign.h"
392 #include "alphacolors.h"
393 #include "localize.h"
394 #include "multi_endgame.h"
397 #define MAX_TOTAL_DEBRIEF_LINES 200
399 #define TEXT_TYPE_NORMAL 1
400 #define TEXT_TYPE_RECOMMENDATION 2
402 #define DEBRIEF_NUM_STATS_PAGES 4
403 #define DEBRIEF_MISSION_STATS 0
404 #define DEBRIEF_MISSION_KILLS 1
405 #define DEBRIEF_ALLTIME_STATS 2
406 #define DEBRIEF_ALLTIME_KILLS 3
408 // 3rd coord is max width in pixels
409 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
422 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
435 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
440 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
453 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
466 #define MULTI_LIST_TEAM_OFFSET 16
468 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
473 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
482 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
495 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
509 int Debrief_rank_coords[2] = {
513 int Debrief_badge_coords[2] = {
519 // 0=x, 1=y, 2=width of the field
520 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
529 // 0=x, 1=y, 2=height of the field
530 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
539 // the medal text in FS1 is a bitmap
540 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][2] = {
549 int Debrief_rank_text_coords[GR_NUM_RESOLUTIONS][2] = {
558 int Debrief_badge_text_coords[GR_NUM_RESOLUTIONS][2] = {
569 // 1 = without medal (text will use medal space)
570 #define DB_WITH_MEDAL 0
571 #define DB_WITHOUT_MEDAL 1
572 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
581 const char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
582 "DebriefSingle", // GR_640
583 "2_DebriefSingle" // GR_1024
585 const char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
586 "DebriefMulti", // GR_640
587 "2_DebriefMulti" // GR_1024
589 const char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
590 "Debrief-m", // GR_640
591 "2_Debrief-m" // GR_1024
594 #define NUM_BUTTONS 18
597 #define DEBRIEF_TAB 0
599 #define TEXT_SCROLL_UP 2
600 #define TEXT_SCROLL_DOWN 3
601 #define REPLAY_MISSION 4
602 #define RECOMMENDATIONS 5
603 #define FIRST_STAGE 6
607 #define MULTI_PINFO_POPUP 10
608 #define MULTI_KICK 11
609 #define MEDALS_BUTTON 12
610 #define PLAYER_SCROLL_UP 13
611 #define PLAYER_SCROLL_DOWN 14
612 #define HELP_BUTTON 15
613 #define OPTIONS_BUTTON 16
614 #define ACCEPT_BUTTON 17
619 const char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
620 "PleaseWait", // GR_640
621 "2_PleaseWait" // GR_1024
627 char text[NAME_LENGTH+1]; // name of ship type with a colon
628 int num; // how many ships of this type player has killed
629 } debrief_stats_kill_info;
632 int net_player_index; // index into Net_players[] array
633 int rank_bitmap; // bitmap id for rank
634 char callsign[CALLSIGN_LEN];
635 } debrief_multi_list_info;
637 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
640 ui_button_info("DB_00", 0, 2, -1, -1, 0), // debriefing
641 ui_button_info("DB_01", 0, 20, -1, -1, 1), // statistics
642 ui_button_info("DB_02", 0, 195, -1, -1, 2), // scroll stats up
643 ui_button_info("DB_03", 0, 232, -1, -1, 3), // scroll stats down
644 ui_button_info("DB_04", 24, 424, -1, -1, 4), // replay mission
645 ui_button_info("DB_05", 30, 451, -1, -1, 5), // recommendations
646 ui_button_info("DB_06", 211, 445, -1, -1, 6), // first page
647 ui_button_info("DB_07", 234, 445, -1, -1, 7), // prev page
648 ui_button_info("DB_08", 259, 445, -1, -1, 8), // next page
649 ui_button_info("DB_09", 283, 445, -1, -1, 9), // last page
650 ui_button_info("DB_21", 441, 384, -1, -1, 21), // pilot info
651 ui_button_info("DB_25", 511, 384, -1, -1, 25), // kick
652 ui_button_info("DB_15", 604, 224, -1, -1, 15), // medals
653 ui_button_info("DB_16", 615, 329, -1, -1, 16), // scroll pilots up
654 ui_button_info("DB_17", 615, 371, -1, -1, 17), // scroll pilots down
655 ui_button_info("DB_10", 469, 428, -1, -1, 10), // help
656 ui_button_info("DB_11", 447, 452, -1, -1, 11), // options
657 ui_button_info("DB_12", 562, 410, -1, -1, 12), // accept
659 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
660 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
661 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
662 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
663 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
664 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
665 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
666 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
667 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
668 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
669 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
670 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
671 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
672 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
673 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
674 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
675 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
676 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
680 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
681 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
682 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
683 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
684 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
685 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
686 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
687 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
688 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
689 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
690 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
691 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
692 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
693 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
694 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
695 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
696 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
697 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
703 #define NUM_DEBRIEF_TEXT 10
704 #define MP_TEXT_INDEX_1 4
705 #define MP_TEXT_INDEX_2 5
706 #define MP_TEXT_INDEX_3 6
707 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
709 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
710 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
711 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
712 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
713 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
714 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
715 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
716 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
717 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
718 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
721 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
722 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
723 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
724 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
725 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
726 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
727 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
728 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
729 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
730 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
736 char Debrief_current_callsign[CALLSIGN_LEN+10];
737 player *Debrief_player;
739 static UI_WINDOW Debrief_ui_window;
740 static UI_BUTTON List_region;
741 static int Background_bitmap; // bitmap for the background of the debriefing
742 static int Award_bg_bitmap;
743 static int Debrief_multi_loading_bitmap;
744 static int Rank_bitmap;
745 static int Medal_bitmap;
746 static int Badge_bitmap;
747 static int Wings_bitmap;
748 static int Crest_bitmap;
750 static int Rank_text_bitmap;
751 static int Medal_text_bitmap;
752 static int Badge_text_bitmap;
755 static int Debrief_accepted;
756 static int Turned_traitor;
757 static int Must_replay_mission;
759 static int Current_mode;
761 static int Recommend_active;
762 static int Award_active;
763 static int Text_offset;
764 static int Num_text_lines = 0;
765 static int Num_debrief_lines = 0;
766 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
767 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
769 static int Debrief_inited = 0;
770 static int New_stage;
771 static int Current_stage;
772 static int Num_stages = 0;
773 static int Num_debrief_stages = 0;
774 static int Stage_voice = -1;
776 static int Multi_list_size;
777 static int Multi_list_offset;
779 int Debrief_multi_stages_loaded = 0;
780 int Debrief_multi_voice_loaded = 0;
782 // static int Debrief_voice_ask_for_cd;
784 // voice id's for debriefing text
785 static int Debrief_voices[MAX_DEBRIEF_STAGES];
787 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
788 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
789 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
791 // pointer used for getting to debriefing information
792 debriefing Traitor_debriefing; // used when player is a traitor
794 // pointers to the active stages for this debriefing
795 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
796 static debrief_stage Promotion_stage, Badge_stage;
797 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
798 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
799 int Multi_list_select;
801 // flag indicating if we should display info for the given player (in multiplayer)
802 int Debrief_should_show_popup = 1;
804 // already shown skip mission popup?
805 static int Debrief_skip_popup_already_shown = 0;
807 void debrief_text_init();
808 void debrief_accept(int ok_to_post_start_game_event = 1);
809 void debrief_kick_selected_player();
812 // promotion voice selection stuff
813 #define NUM_VOLITION_CAMPAIGNS 1
815 char campaign_name[32];
819 v_campaign Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
821 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
822 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
826 // data for which voice goes w/ which mission
827 typedef struct voice_map {
828 char mission_file[32];
832 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
833 { // FreeSpace2 campaign
865 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
867 { "loop1-1.fs2", 4 },
868 { "loop1-2.fs2", 4 },
869 { "loop1-3.fs2", 5 },
870 { "loop2-1.fs2", 4 },
875 #define DB_AWARD_WINGS 0
876 #define DB_AWARD_MEDAL 1
878 #define DB_AWARD_RANK 2
879 #define DB_AWARD_BADGE 3
880 #define DB_AWARD_BG 4
881 static const char* Debrief_award_filename[GR_NUM_RESOLUTIONS][5] = {
898 #define DB_AWARD_SOC 2
899 #define DB_AWARD_RANK 3
900 #define DB_AWARD_BADGE 4
901 #define DB_AWARD_BG 5
902 static const char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
922 #define AWARD_TEXT_MAX_LINES 5
923 #define AWARD_TEXT_MAX_LINE_LENGTH 128
924 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
925 int Debrief_award_text_num_lines = 0;
929 // prototypes, you know you love 'em
930 void debrief_add_award_text(char *str);
931 void debrief_award_text_clear();
936 const char *debrief_tooltip_handler(const char *str)
938 if (!SDL_strcasecmp(str, NOX("@.Medal"))) {
940 return XSTR( "Medal", 435);
943 } else if (!SDL_strcasecmp(str, NOX("@.Rank"))) {
945 return XSTR( "Rank", 436);
948 } else if (!SDL_strcasecmp(str, NOX("@.Badge"))) {
950 return XSTR( "Badge", 437);
953 } else if (!SDL_strcasecmp(str, NOX("@Medal"))) {
954 if (Medal_bitmap >= 0){
955 return Medals[Player->stats.m_medal_earned].name;
958 } else if (!SDL_strcasecmp(str, NOX("@Rank"))) {
959 if (Rank_bitmap >= 0){
960 return Ranks[Promoted].name;
963 } else if (!SDL_strcasecmp(str, NOX("@Badge"))) {
964 if (Badge_bitmap >= 0){
965 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
972 // initialize the array of handles to the different voice streams
973 void debrief_voice_init()
977 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
978 Debrief_voices[i] = -1;
982 void debrief_load_voice_file(int voice_num, char *name)
984 int load_attempts = 0;
987 if ( load_attempts++ > 5 ) {
991 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
992 if ( Debrief_voices[voice_num] >= 0 ) {
996 // Don't bother to ask for the CD in multiplayer
997 if ( Game_mode & GM_MULTIPLAYER ) {
1001 // couldn't load voice, ask user to insert CD (if necessary)
1003 // if ( Debrief_voice_ask_for_cd ) {
1004 // if ( game_do_cd_check() == 0 ) {
1005 // Debrief_voice_ask_for_cd = 0;
1012 // open and pre-load the stream buffers for the different voice streams
1013 void debrief_voice_load_all()
1017 // Debrief_voice_ask_for_cd = 1;
1019 for ( i=0; i<Num_debrief_stages; i++ ) {
1020 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
1023 if ( SDL_strncasecmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
1024 debrief_load_voice_file(i, Debrief_stages[i]->voice);
1025 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
1030 // close all the briefing voice streams
1031 void debrief_voice_unload_all()
1035 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
1036 if ( Debrief_voices[i] != -1 ) {
1037 audiostream_close_file(Debrief_voices[i], 0);
1038 Debrief_voices[i] = -1;
1043 // start playback of the voice for a particular briefing stage
1044 void debrief_voice_play()
1046 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
1050 // no more stages? We are done then.
1051 if (Stage_voice >= Num_debrief_stages){
1055 // if in delayed start, see if delay has elapsed and start voice if so
1056 if (Debrief_cue_voice) {
1057 if (!timestamp_elapsed(Debrief_cue_voice)){
1061 Stage_voice++; // move up to next voice
1062 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
1063 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
1064 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
1070 // see if voice is still playing. If so, do nothing yet.
1071 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
1075 // set voice to play in a little while from now.
1076 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
1079 // stop playback of the voice for a particular briefing stage
1080 void debrief_voice_stop()
1082 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
1085 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
1089 // function to deal with inserting possible promition and badge stages into the debriefing
1091 void debrief_multi_fixup_stages()
1095 // possibly insert the badge stage first, them the promotion stage since they are
1096 // inserted at the front of the debrief stages.
1097 if ( Badge_bitmap >= 0 ) {
1098 // move all stages forward one. Don't
1099 for ( i = Num_debrief_stages; i > 0; i-- ) {
1100 Debrief_stages[i] = Debrief_stages[i-1];
1102 Debrief_stages[0] = &Badge_stage;
1103 Num_debrief_stages++;
1106 if ( Promoted >= 0) {
1107 // move all stages forward one
1108 for ( i = Num_debrief_stages; i > 0; i-- ) {
1109 Debrief_stages[i] = Debrief_stages[i-1];
1111 Debrief_stages[0] = &Promotion_stage;
1112 Num_debrief_stages++;
1117 // function called from multiplayer clients to set up the debriefing information for them
1118 // (sent from the server).
1119 void debrief_set_multi_clients( int stage_count, int active_stages[] )
1123 // set up the right briefing for this guy
1124 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
1125 Debriefing = &Debriefings[Net_player->p_info.team];
1127 Debriefing = &Debriefings[0];
1130 // see if this client was promoted -- if so, then add the first stage.
1131 Num_debrief_stages = 0;
1133 // set the pointers to the debriefings for this client
1134 for (i = 0; i < stage_count; i++) {
1135 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
1138 Debrief_multi_stages_loaded = 1;
1141 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
1142 // information to all clients after leaving this screen.
1143 void debrief_multi_server_stuff()
1145 debriefing *debriefp;
1147 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1148 int i, j, num_stages, stage_count[MAX_TEAMS];
1150 memset( stage_active, 0, sizeof(stage_active) );
1152 for (i=0; i<Num_teams; i++) {
1153 debriefp = &Debriefings[i];
1155 stages[i] = stage_active[i];
1156 for (j=0; j<debriefp->num_stages; j++) {
1157 if ( eval_sexp(debriefp->stages[j].formula) ) {
1158 stage_active[i][num_stages] = j;
1163 stage_count[i] = num_stages;
1166 // if we're in campaign mode, evaluate campaign stuff
1167 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1168 multi_campaign_eval_debrief();
1171 // send the information to all clients.
1172 send_debrief_info( stage_count, stages );
1176 // --------------------------------------------------------------------------------------
1177 // debrief_set_stages_and_multi_stuff()
1179 // Set up the active stages for this debriefing
1181 // returns: number of active debriefing stages
1183 int debrief_set_stages_and_multi_stuff()
1186 debriefing *debriefp;
1188 if ( MULTIPLAYER_CLIENT ) {
1192 Num_debrief_stages = 0;
1194 if ( Game_mode & GM_MULTIPLAYER ) {
1195 debrief_multi_server_stuff();
1198 // check to see if player is a traitor (looking at his team). If so, use the special
1199 // traitor debriefing. Only done in single player
1200 debriefp = Debriefing;
1201 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1202 if (Player_ship->team == TEAM_TRAITOR)
1203 debriefp = &Traitor_debriefing;
1206 Num_debrief_stages = 0;
1207 if (Promoted >= 0) {
1208 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1211 if (Badge_bitmap >= 0) {
1212 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1215 for (i=0; i<debriefp->num_stages; i++) {
1216 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1217 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1221 return Num_debrief_stages;
1224 // init the buttons that are specific to the debriefing screen
1225 void debrief_buttons_init()
1230 for ( i=0; i<NUM_BUTTONS; i++ ) {
1231 b = &Buttons[gr_screen.res][i];
1232 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1233 // set up callback for when a mouse first goes over a button
1234 b->button.set_highlight_action( common_play_highlight_sound );
1235 b->button.set_bmaps(b->filename);
1236 b->button.link_hotspot(b->hotspot);
1241 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1242 // multiplayer specific text
1243 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1244 // only add if in multiplayer mode
1245 if(Game_mode & GM_MULTIPLAYER){
1246 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1251 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1256 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1257 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(SDLK_RIGHT);
1258 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(SDLK_LEFT);
1259 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | SDLK_RIGHT);
1260 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | SDLK_LEFT);
1261 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(SDLK_UP);
1262 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(SDLK_DOWN);
1263 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+SDLK_RETURN);
1265 // if in multiplayer, disable the button for all players except the host
1266 // also disable for squad war matches
1267 if(Game_mode & GM_MULTIPLAYER){
1268 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1269 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1274 // --------------------------------------------------------------------------------------
1275 // debrief_ui_init()
1277 void debrief_ui_init()
1279 // init ship selection masks and buttons
1280 common_set_interface_palette("DebriefPalette"); // set the interface palette
1281 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1282 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1283 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1284 debrief_buttons_init();
1286 // load in help overlay bitmap
1287 help_overlay_load(DEBRIEFING_OVERLAY);
1288 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1290 if ( Game_mode & GM_MULTIPLAYER ) {
1291 // close down any old instances of the chatbox
1294 // create the new one
1296 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1297 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);
1300 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1303 if ( Background_bitmap < 0 ) {
1304 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1307 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1308 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1311 // sets Promotion_stage.voice
1312 // defaults to number 9 (Petrarch) for non-volition missions
1313 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1314 void debrief_choose_promotion_voice()
1318 if(Campaign.current_mission < 0){
1319 SDL_snprintf(Promotion_stage.voice, sizeof(Promotion_stage.voice), NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1323 // search thru all official campaigns for our current campaign
1324 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1325 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1326 if ((Campaign.filename != NULL) && !SDL_strcasecmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1327 // now search thru the mission filenames,
1328 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1329 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !SDL_strcasecmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1330 // found it! set the persona and bail
1331 SDL_snprintf(Promotion_stage.voice, sizeof(Promotion_stage.voice), NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1339 // default to petrarch
1340 SDL_snprintf(Promotion_stage.voice, sizeof(Promotion_stage.voice), NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1343 // sets Promotion_stage.voice
1344 // defaults to number 9 (Petrarch) for non-volition missions
1345 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1346 void debrief_choose_badge_voice()
1352 if(Campaign.current_mission < 0){
1354 // default to petrarch
1355 SDL_snprintf(Badge_stage.voice, sizeof(Badge_stage.voice), NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1357 // default to FS1 guy
1358 SDL_snprintf(Badge_stage.voice, sizeof(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1362 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1364 if ( Player->on_bastion ) {
1365 SDL_snprintf(Badge_stage.voice, sizeof(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base2);
1368 SDL_snprintf(Badge_stage.voice, sizeof(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1372 // search thru all official campaigns for our current campaign
1373 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1374 if ((Campaign.filename != NULL) && !SDL_strcasecmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1375 // now search thru the mission filenames,
1376 for (j=0; j<Campaign.num_missions; j++) {
1377 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !SDL_strcasecmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1378 // found it! set the persona and bail
1379 SDL_snprintf(Badge_stage.voice, sizeof(Badge_stage.voice), NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1389 // default to petrarch
1390 SDL_snprintf(Badge_stage.voice, sizeof(Badge_stage.voice), NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1392 // default to FS1 guy
1393 SDL_snprintf(Badge_stage.voice, sizeof(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1398 void debrief_award_init()
1410 // be sure there are no old award texts floating around
1412 debrief_award_text_clear();
1415 // handle medal earned
1416 if (Player->stats.m_medal_earned != -1) {
1417 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1419 if ( Player->stats.medals[13] > 1 ) {
1424 SDL_snprintf(buf, sizeof(buf), NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1425 Wings_bitmap = bm_load(buf);
1427 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1428 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1431 SDL_snprintf(buf, sizeof(buf), NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1432 Medal_bitmap = bm_load(buf);
1436 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1440 // handle promotions
1441 if ( Player->stats.m_promotion_earned != -1 ) {
1442 Promoted = Player->stats.m_promotion_earned;
1443 SDL_snprintf(buf, sizeof(buf), NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1444 Rank_bitmap = bm_load(buf);
1446 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1447 Promotion_stage.new_recommendation_text = NULL;
1449 // choose appropriate promotion voice for this mission
1450 debrief_choose_promotion_voice();
1453 debrief_add_award_text(Ranks[Promoted].name);
1457 // handle badge earned
1458 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1459 if ( Player->stats.m_badge_earned != -1 ) {
1460 i = Player->stats.m_badge_earned;
1461 SDL_snprintf(buf, sizeof(buf), NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1462 Badge_bitmap = bm_load(buf);
1464 Badge_stage.new_text = Badge_info[i].promotion_text;
1465 Badge_stage.new_recommendation_text = NULL;
1467 // choose appropriate voice
1468 debrief_choose_badge_voice();
1471 debrief_add_award_text(Medals[Badge_index[i]].name);
1475 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1482 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1483 // mission a traitor. The same debriefing always gets played
1484 void debrief_traitor_init()
1486 static int inited = 0;
1489 debriefing *debrief;
1490 debrief_stage *stagep;
1494 if ((rval = setjmp(parse_abort)) != 0) {
1495 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", rval);
1498 read_file_text("traitor.tbl");
1502 // open localization
1505 // simplied form of the debriefing stuff.
1506 debrief = &Traitor_debriefing;
1507 required_string("#Debriefing_info");
1509 required_string("$Num stages:");
1510 stuff_int(&debrief->num_stages);
1511 SDL_assert(debrief->num_stages == 1);
1514 stagep = &debrief->stages[stage_num++];
1515 required_string("$Formula:");
1516 stagep->formula = get_sexp_main();
1517 required_string("$multi text");
1518 if ( Fred_running ) {
1519 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1521 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1523 required_string("$Voice:");
1524 char traitor_voice_file[NAME_LENGTH];
1525 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1527 // DKA 9/13/99 Only 1 traitor msg for FS2
1529 if ( Player->on_bastion ) {
1530 SDL_strlcpy(stagep->voice, NOX("3_"), sizeof(stagep->voice));
1532 SDL_strlcpy(stagep->voice, NOX("1_"), sizeof(stagep->voice));
1536 SDL_strlcat(stagep->voice, traitor_voice_file, sizeof(stagep->voice));
1538 required_string("$Recommendation text:");
1539 if ( Fred_running ) {
1540 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1542 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1546 // close localization
1550 // disable the accept button if in single player and I am a traitor
1551 Debrief_accepted = 0;
1552 Turned_traitor = Must_replay_mission = 0;
1553 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1554 if (Player_ship->team == TEAM_TRAITOR){
1558 if (Campaign.next_mission == Campaign.current_mission){
1559 Must_replay_mission = 1;
1563 if (Turned_traitor || Must_replay_mission) {
1564 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1566 // kill off any stats
1567 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1568 scoring_level_init( &Player->stats );
1572 // initialization for listing of players in game
1573 void debrief_multi_list_init()
1575 Multi_list_size = 0; // number of net players to choose from
1576 Multi_list_offset = 0;
1578 Multi_list_select = -1;
1580 if ( !(Game_mode & GM_MULTIPLAYER) )
1583 debrief_rebuild_player_list();
1585 // switch stats display to this newly selected player
1586 set_player_stats(Multi_list[0].net_player_index);
1587 SDL_strlcpy(Debrief_current_callsign, Multi_list[0].callsign, sizeof(Debrief_current_callsign));
1588 Debrief_player = Player;
1591 void debrief_multi_list_scroll_up()
1593 // if we're at the beginning of the list, don't do anything
1594 if(Multi_list_offset == 0){
1595 gamesnd_play_iface(SND_GENERAL_FAIL);
1599 // otherwise scroll up
1600 Multi_list_offset--;
1601 gamesnd_play_iface(SND_USER_SELECT);
1604 void debrief_multi_list_scroll_down()
1606 // if we can scroll down no further
1607 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1608 gamesnd_play_iface(SND_GENERAL_FAIL);
1611 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1612 gamesnd_play_iface(SND_GENERAL_FAIL);
1616 // otherwise scroll down
1617 Multi_list_offset++;
1618 gamesnd_play_iface(SND_USER_SELECT);
1621 // draw the connected net players
1622 void debrief_multi_list_draw()
1624 int y, z, font_height,idx;
1625 char str[CALLSIGN_LEN+5];
1628 font_height = gr_get_font_height();
1630 // if we currently have no item picked, pick a reasonable one
1631 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1632 // select the entry which corresponds to the local player
1633 Multi_list_select = 0;
1634 for(idx=0;idx<Multi_list_size;idx++){
1635 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1636 Multi_list_select = idx;
1638 // switch stats display to this newly selected player
1639 set_player_stats(Multi_list[idx].net_player_index);
1640 SDL_strlcpy(Debrief_current_callsign, Multi_list[idx].callsign, sizeof(Debrief_current_callsign));
1641 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1647 // draw the list itself
1649 z = Multi_list_offset;
1650 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1651 np = &Net_players[Multi_list[z].net_player_index];
1653 if (z >= Multi_list_size){
1656 // set the proper text color for the highlight
1657 if(np->flags & NETINFO_FLAG_GAME_HOST){
1658 if(Multi_list_select == z){
1659 gr_set_color_fast(&Color_text_active_hi);
1661 gr_set_color_fast(&Color_bright);
1664 if(Multi_list_select == z){
1665 gr_set_color_fast(&Color_text_active);
1667 gr_set_color_fast(&Color_text_normal);
1671 // blit the proper indicator - skipping observers
1672 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1673 if(Netgame.type_flags & NG_TYPE_TEAM){
1675 if(np->p_info.team == 0){
1676 // draw his "selected" icon
1677 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1678 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1679 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1681 // draw his "normal" icon
1682 else if(Multi_common_icons[MICON_TEAM0] != -1){
1683 gr_set_bitmap(Multi_common_icons[MICON_TEAM0], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1684 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1686 } else if(np->p_info.team == 1){
1687 // draw his "selected" icon
1688 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1689 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1690 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1692 // draw his "normal" icon
1693 else if(Multi_common_icons[MICON_TEAM1] != -1){
1694 gr_set_bitmap(Multi_common_icons[MICON_TEAM1], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1695 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1699 // draw the team 0 selected icon
1700 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1701 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1702 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1707 SDL_strlcpy(str, Multi_list[z].callsign, sizeof(str));
1708 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)){
1709 SDL_strlcat(str, XSTR( "(O)", 438), sizeof(str));
1713 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1720 void debrief_kick_selected_player()
1722 if(Multi_list_select >= 0){
1723 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1724 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1728 // get optional mission popup text
1729 void debrief_assemble_optional_mission_popup_text(char *buffer, const int buf_len, char *mission_loop_desc)
1731 SDL_assert(buffer != NULL);
1734 if (mission_loop_desc == NULL) {
1735 SDL_strlcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490), buf_len);
1736 mprintf(("No mission loop description avail"));
1738 SDL_strlcpy(buffer, mission_loop_desc, buf_len);
1741 SDL_strlcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491), buf_len);
1744 // what to do when the accept button is hit
1745 void debrief_accept(int ok_to_post_start_game_event)
1749 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1753 if (Game_mode & GM_MULTIPLAYER) {
1757 if (Player_ship->team == TEAM_TRAITOR){
1758 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1759 }/* else if (Cheats_enabled) {
1760 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1762 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1765 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1767 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1768 } else if ( z == 1 ) {
1769 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1775 Debrief_accepted = 1;
1776 // save mission stats
1777 if (Game_mode & GM_MULTIPLAYER) {
1778 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1779 // as well as doing stats transfers, etc.
1780 multi_debrief_accept_hit();
1784 int play_commit_sound = 1;
1785 // only write the player's stats if he's accepted
1787 // if we are just playing a single mission, then don't do many of the things
1788 // that need to be done. Nothing much should happen when just playing a single
1789 // mission that isn't in a campaign.
1790 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1792 // check for possible mission loop
1793 // check for (1) mission loop available, (2) dont have to repeat last mission
1794 if(!(Game_mode & GM_MULTIPLAYER)){
1795 int cur = Campaign.current_mission;
1796 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1797 if (Campaign.missions[cur].has_mission_loop) {
1798 SDL_assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1801 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1804 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1806 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1808 Campaign.loop_enabled = 1;
1809 Campaign.next_mission = Campaign.loop_mission;
1818 if(ok_to_post_start_game_event){
1819 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1821 play_commit_sound = 0;
1824 // continue as normal
1827 mission_campaign_mission_over();
1829 // check to see if we are out of the loop now
1830 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1831 Campaign.loop_enabled = 0;
1834 // check if campaign is over
1835 if ( Campaign.next_mission == -1 ) {
1836 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
1837 gameseq_post_event(GS_EVENT_END_DEMO);
1839 gameseq_post_event(GS_EVENT_MAIN_MENU);
1842 if ( ok_to_post_start_game_event ) {
1843 gameseq_post_event(GS_EVENT_START_GAME);
1845 play_commit_sound = 0;
1850 gameseq_post_event(GS_EVENT_MAIN_MENU);
1853 if ( play_commit_sound ) {
1854 gamesnd_play_iface(SND_COMMIT_PRESSED);
1861 void debrief_next_tab()
1863 New_mode = Current_mode + 1;
1864 if (New_mode >= NUM_TABS)
1868 void debrief_prev_tab()
1870 New_mode = Current_mode - 1;
1872 New_mode = NUM_TABS - 1;
1875 // --------------------------------------------------------------------------------------
1876 // debrief_next_stage()
1878 void debrief_next_stage()
1880 if (Current_stage < Num_stages - 1) {
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_prev_stage()
1891 void debrief_prev_stage()
1893 if (Current_stage) {
1894 New_stage = Current_stage - 1;
1895 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1898 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1901 // --------------------------------------------------------------------------------------
1902 // debrief_first_stage()
1903 void debrief_first_stage()
1905 if (Current_stage) {
1907 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1910 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1913 // --------------------------------------------------------------------------------------
1914 // debrief_last_stage()
1915 void debrief_last_stage()
1917 if (Current_stage != Num_stages - 1) {
1918 New_stage = Num_stages - 1;
1919 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1922 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1925 // draw what stage number the debriefing is on
1926 void debrief_render_stagenum()
1934 SDL_snprintf(buf, sizeof(buf), XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1935 gr_get_string_size(&w, NULL, buf);
1936 gr_set_color_fast(&Color_bright_blue);
1937 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1938 gr_set_color_fast(&Color_white);
1941 // render the mission time at the specified y location
1942 void debrief_render_mission_time(int y_loc)
1946 game_format_time(Missiontime, time_str, sizeof(time_str));
1947 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1948 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1951 // render out the debriefing text to the scroll window
1952 void debrief_render()
1954 int y, z, font_height;
1956 if ( Num_stages <= 0 )
1959 font_height = gr_get_font_height();
1961 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]);
1964 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1965 if (z >= Num_text_lines)
1968 if (Text_type[z] == TEXT_TYPE_NORMAL)
1969 gr_set_color_fast(&Color_white);
1971 gr_set_color_fast(&Color_bright_red);
1974 gr_string(0, y, Text[z]);
1983 // render out the stats info to the scroll window
1985 void debrief_stats_render()
1987 int i, y, font_height;
1989 gr_set_color_fast(&Color_blue);
1990 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]);
1991 gr_string(0, 0, Debrief_current_callsign);
1992 font_height = gr_get_font_height();
1995 switch ( Current_stage ) {
1996 case DEBRIEF_MISSION_STATS:
1997 i = Current_stage - 1;
2001 gr_set_color_fast(&Color_white);
2003 // display mission completion time
2004 debrief_render_mission_time(y);
2007 show_stats_label(i, 0, y, font_height);
2008 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2010 case DEBRIEF_ALLTIME_STATS:
2011 i = Current_stage - 1;
2015 gr_set_color_fast(&Color_white);
2016 show_stats_label(i, 0, y, font_height);
2017 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2020 case DEBRIEF_ALLTIME_KILLS:
2021 case DEBRIEF_MISSION_KILLS:
2022 gr_set_color_fast(&Color_white);
2024 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
2025 if (i >= Num_text_lines)
2029 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2030 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
2032 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
2035 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
2036 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
2043 if (Num_text_lines == 2) {
2044 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2045 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
2047 gr_printf(0, y, XSTR( "(No ship kills)", 450));
2060 // do action for when the replay button is pressed
2061 void debrief_replay_pressed()
2063 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2065 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));
2072 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
2073 gamesnd_play_iface(SND_COMMIT_PRESSED);
2076 // -------------------------------------------------------------------
2077 // debrief_redraw_pressed_buttons()
2079 // Redraw any debriefing buttons that are pressed down. This function is needed
2080 // since we sometimes need to draw pressed buttons last to ensure the entire
2081 // button gets drawn (and not overlapped by other buttons)
2083 void debrief_redraw_pressed_buttons()
2088 for ( i=0; i<NUM_BUTTONS; i++ ) {
2089 b = &Buttons[gr_screen.res][i].button;
2090 // don't draw the recommendations button if we're in stats mode
2091 if ( b->button_down() ) {
2097 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
2099 void debrief_button_pressed(int num)
2103 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
2104 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
2105 if (num != Current_mode){
2106 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2111 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
2112 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
2113 if (num != Current_mode){
2114 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2119 case TEXT_SCROLL_UP:
2122 gamesnd_play_iface(SND_SCROLL);
2124 gamesnd_play_iface(SND_GENERAL_FAIL);
2128 case TEXT_SCROLL_DOWN:
2129 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2131 gamesnd_play_iface(SND_SCROLL);
2133 gamesnd_play_iface(SND_GENERAL_FAIL);
2137 case REPLAY_MISSION:
2138 if(Game_mode & GM_MULTIPLAYER){
2139 multi_debrief_replay_hit();
2141 debrief_replay_pressed();
2145 case RECOMMENDATIONS:
2146 gamesnd_play_iface(SND_USER_SELECT);
2147 Recommend_active = !Recommend_active;
2148 debrief_text_init();
2152 debrief_first_stage();
2156 debrief_prev_stage();
2160 debrief_next_stage();
2164 debrief_last_stage();
2168 gamesnd_play_iface(SND_HELP_PRESSED);
2169 launch_context_help();
2172 case OPTIONS_BUTTON:
2173 gamesnd_play_iface(SND_SWITCH_SCREENS);
2174 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2182 gamesnd_play_iface(SND_SWITCH_SCREENS);
2183 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2186 case PLAYER_SCROLL_UP:
2187 debrief_multi_list_scroll_up();
2190 case PLAYER_SCROLL_DOWN:
2191 debrief_multi_list_scroll_down();
2194 case MULTI_PINFO_POPUP:
2195 Debrief_should_show_popup = 1;
2199 debrief_kick_selected_player();
2204 void debrief_setup_ship_kill_stats(int stage_num)
2208 debrief_stats_kill_info *kill_info;
2210 SDL_assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2211 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2214 SDL_assert(Debrief_player != NULL);
2216 // kill_ar points to an array of MAX_SHIP_TYPE ints
2217 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2218 kill_arr = Debrief_player->stats.m_okKills;
2220 kill_arr = Debrief_player->stats.kills;
2224 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2226 // code used to add in mission kills, but the new system assumes that the player will accept, so
2227 // all time stats already have mission stats added in.
2228 if ( kill_arr[i] <= 0 ){
2233 kill_info = &Debrief_stats_kills[Num_text_lines++];
2235 kill_info->num = kill_arr[i];
2237 SDL_strlcpy(kill_info->text, Ship_info[i].name, sizeof(kill_info->text));
2238 SDL_strlcat(kill_info->text, NOX(":"), sizeof(kill_info->text));
2241 Num_text_lines += 2;
2244 // Iterate through the debriefing buttons, checking if they are pressed
2245 void debrief_check_buttons()
2249 for ( i=0; i<NUM_BUTTONS; i++ ) {
2250 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2251 debrief_button_pressed(i);
2255 if ( !(Game_mode & GM_MULTIPLAYER) )
2258 if (List_region.pressed()) {
2259 List_region.get_mouse_pos(NULL, &y);
2260 z = Multi_list_offset + y / gr_get_font_height();
2261 if ((z >= 0) && (z < Multi_list_size)) {
2262 // switch stats display to this newly selected player
2263 set_player_stats(Multi_list[z].net_player_index);
2264 SDL_strlcpy(Debrief_current_callsign, Multi_list[z].callsign, sizeof(Debrief_current_callsign));
2265 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2266 Multi_list_select = z;
2267 debrief_setup_ship_kill_stats(Current_stage);
2268 gamesnd_play_iface(SND_USER_SELECT);
2272 // if the player was double clicked on - we should popup a player info popup
2274 if (List_region.double_clicked()) {
2275 Debrief_should_show_popup = 1;
2280 void debrief_text_stage_init(const char *src, int type)
2282 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2283 char line[MAX_DEBRIEF_LINE_LEN];
2284 char *p_str[MAX_DEBRIEF_LINES];
2287 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2288 SDL_assert(n_lines >= 0);
2290 // if you hit this, you proba
2291 if(n_lines >= MAX_DEBRIEF_LINES){
2292 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2295 for ( i=0; i<n_lines; i++ ) {
2296 SDL_assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2297 SDL_assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2298 len = min(n_chars[i] + 1, MAX_DEBRIEF_LINE_LEN);
2299 SDL_strlcpy(line, p_str[i], len);
2300 line[n_chars[i]] = 0;
2301 drop_white_space(line);
2302 Text_type[Num_text_lines] = type;
2303 Text[Num_text_lines++] = strdup(line);
2309 void debrief_free_text()
2313 for (i=0; i<Num_debrief_lines; i++)
2317 Num_debrief_lines = 0;
2320 // setup the debriefing text lines for rendering
2321 void debrief_text_init()
2326 // release old text lines first
2327 debrief_free_text();
2328 Num_text_lines = Text_offset = 0;
2330 if (Current_mode == DEBRIEF_TAB) {
2331 for (i=0; i<Num_debrief_stages; i++) {
2333 Text[Num_text_lines++] = NULL; // add a blank line between stages
2335 src = Debrief_stages[i]->new_text;
2337 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2339 if (Recommend_active) {
2340 src = Debrief_stages[i]->new_recommendation_text;
2341 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2342 src = XSTR( "We have no recommendations for you.", 1054);
2345 Text[Num_text_lines++] = NULL;
2346 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2352 Num_debrief_lines = Num_text_lines;
2356 // not in debriefing mode, must be in stats mode
2358 debrief_setup_ship_kill_stats(Current_stage);
2362 // --------------------------------------------------------------------------------------
2366 SDL_assert(!Debrief_inited);
2367 // Campaign.loop_enabled = 0;
2368 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2370 // set up the right briefing for this guy
2371 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2372 Debriefing = &Debriefings[Net_player->p_info.team];
2374 Debriefing = &Debriefings[0];
2377 // no longer is mission
2378 Game_mode &= ~(GM_IN_MISSION);
2382 New_mode = DEBRIEF_TAB;
2383 Recommend_active = Award_active = 0;
2388 Debrief_cue_voice = 0;
2389 Num_text_lines = Num_debrief_lines = 0;
2390 Debrief_first_voice_flag = 1;
2392 Debrief_multi_voice_loaded = 0;
2395 Medal_text_bitmap = bm_load(NOX("DebriefText01"));
2396 Rank_text_bitmap = bm_load(NOX("DebriefText02"));
2397 Badge_text_bitmap = bm_load(NOX("DebriefText03"));
2400 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2401 // MUST store goals and events first - may be used to evaluate next mission
2402 // store goals and events
2403 mission_campaign_store_goals_and_events();
2405 // evaluate next mission
2406 mission_campaign_eval_next_mission();
2409 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2411 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2412 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2415 // call scoring level close for my stats. Needed for award_init. The stats will
2416 // be backed out if used chooses to replace them.
2417 scoring_level_close();
2419 debrief_ui_init(); // init UI items
2420 debrief_award_init();
2422 debrief_voice_init();
2423 debrief_multi_list_init();
2424 // rank_bitmaps_clear();
2425 // rank_bitmaps_load();
2427 SDL_strlcpy(Debrief_current_callsign, Player->callsign, sizeof(Debrief_current_callsign));
2428 Debrief_player = Player;
2429 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2431 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2432 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2433 // info directly from the server.
2434 if ( !MULTIPLAYER_CLIENT ) {
2435 debrief_set_stages_and_multi_stuff();
2437 if ( Num_debrief_stages <= 0 ) {
2438 Num_debrief_stages = 0;
2440 debrief_voice_load_all();
2443 // multiplayer client may have already received their debriefing info. If they have not,
2444 // then set the num debrief stages to 0
2445 if ( !Debrief_multi_stages_loaded ) {
2446 Num_debrief_stages = 0;
2451 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2452 common_music_init(SCORE_DEBRIEF_SUCCESS);
2454 common_music_init(SCORE_DEBRIEF_FAIL);
2458 // start up the appropriate music
2459 if (Campaign.next_mission == Campaign.current_mission) {
2460 // you failed the mission because you suck, so you get the suck music
2461 common_music_init(SCORE_DEBRIEF_FAIL);
2462 } else if (mission_goals_met()) {
2463 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2464 common_music_init(SCORE_DEBRIEF_SUCCESS);
2466 // you somehow passed the mission, so you get a little something for your efforts.
2467 common_music_init(SCORE_DEBRIEF_AVERAGE);
2470 if (Campaign.next_mission == Campaign.current_mission) {
2471 // better luck next time, increase his retries
2472 Player->failures_this_session++;
2474 // clear his retries info regardless of whether or not he accepts
2475 Player->failures_this_session = 0;
2478 if (Game_mode & GM_MULTIPLAYER) {
2479 multi_debrief_init();
2481 // if i'm not the host of the game, disable the multi kick button
2482 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2483 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2486 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2487 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2488 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2489 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2490 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2491 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2492 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2493 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2496 if (!Award_active) {
2497 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2498 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2501 Debrief_skip_popup_already_shown = 0;
2506 // --------------------------------------------------------------------------------------
2508 void debrief_close()
2512 SDL_assert(Debrief_inited);
2514 // if the mission wasn't accepted, clear out my stats
2515 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2516 // are a little bit different
2517 if (Game_mode & GM_MULTIPLAYER) {
2518 // if stats weren't accepted, backout my own stats
2519 if (multi_debrief_stats_accept_code() != 1) {
2520 if(MULTIPLAYER_MASTER){
2521 for(idx=0; idx<MAX_PLAYERS; idx++){
2522 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2523 scoring_backout_accept(&Net_players[idx].player->stats);
2527 scoring_backout_accept( &Player->stats );
2532 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2533 scoring_backout_accept( &Player->stats );
2537 // if dude passed the misson and accepted, reset his show skip popup flag
2538 if (Debrief_accepted) {
2539 Player->show_skip_popup = 1;
2542 if (Num_debrief_lines) {
2543 for (i=0; i<Num_debrief_lines; i++){
2550 // clear out debrief info parsed from mission file
2551 mission_debrief_common_reset();
2553 // unload the overlay bitmap
2555 help_overlay_unload(DEBRIEFING_OVERLAY);
2558 // clear out award text
2559 Debrief_award_text_num_lines = 0;
2561 debrief_voice_unload_all();
2562 common_music_close();
2565 // rank_bitmaps_release();
2568 if (Background_bitmap >= 0){
2569 bm_unload(Background_bitmap);
2572 if (Award_bg_bitmap >= 0){
2573 bm_unload(Award_bg_bitmap);
2576 if (Rank_bitmap >= 0){
2577 bm_unload(Rank_bitmap);
2580 if (Medal_bitmap >= 0){
2581 bm_unload(Medal_bitmap);
2584 if (Badge_bitmap >= 0){
2585 bm_unload(Badge_bitmap);
2588 if (Wings_bitmap >= 0) {
2589 bm_unload(Wings_bitmap);
2592 if (Crest_bitmap >= 0) {
2593 bm_unload(Crest_bitmap);
2597 if (Medal_text_bitmap >= 0) {
2598 bm_unload(Medal_text_bitmap);
2601 if (Badge_text_bitmap >= 0) {
2602 bm_unload(Badge_text_bitmap);
2605 if (Rank_text_bitmap >= 0) {
2606 bm_unload(Rank_text_bitmap);
2610 Debrief_ui_window.destroy();
2611 common_free_interface_palette(); // restore game palette
2614 if (Game_mode & GM_MULTIPLAYER){
2615 multi_debrief_close();
2625 // handle keypresses in debriefing
2626 void debrief_do_keys(int new_k)
2633 case KEY_SHIFTED | SDLK_TAB:
2641 // multiplayer accept popup is a little bit different
2642 if (Game_mode & GM_MULTIPLAYER) {
2643 multi_debrief_esc_hit();
2645 // display the normal debrief popup
2647 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2648 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2649 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2650 if (choice == 1) { // accept and continue on
2652 gameseq_post_event(GS_EVENT_MAIN_MENU);
2658 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2659 // need to popup saying that mission was a failure and must be replayed
2660 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));
2665 // Return to Main Hall
2666 gameseq_post_event(GS_EVENT_END_GAME);
2677 void debrief_draw_award_text()
2679 int start_y, curr_y, i, x, sw;
2680 int fh = gr_get_font_height();
2681 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];
2683 // vertically centered within field
2684 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);
2688 for (i=0; i<Debrief_award_text_num_lines; i++) {
2689 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2690 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2691 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2692 gr_set_color_fast(&Color_white);
2693 gr_string(x, curr_y, Debrief_award_text[i]);
2695 // adjust y pos, including a little extra between the "pairs"
2697 if ((i == 1) || (i == 3)) {
2698 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2703 // clears out text array so we dont have old award text showing up on new awards.
2704 void debrief_award_text_clear() {
2707 Debrief_award_text_num_lines = 0;
2708 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2709 //Debrief_award_text[i][0] = 0;
2710 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2714 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2715 void debrief_add_award_text(char *str)
2717 SDL_assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2718 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2723 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];
2726 SDL_strlcpy(Debrief_award_text[Debrief_award_text_num_lines], str, AWARD_TEXT_MAX_LINE_LENGTH);
2728 // maybe translate for displaying
2730 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2731 } else if (Lcl_pl) {
2732 medals_translate_name_pl(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2735 Debrief_award_text_num_lines++;
2737 // if its too long, split once ONLY
2738 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2739 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2740 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2741 if (line2 != NULL) {
2742 SDL_snprintf(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH, " %s", line2); // indent a space
2744 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2747 #endif // !MAKE_FS1: No text for FS1, it's all bitmaps
2749 // called once per frame to drive all the input reading and rendering
2750 void debrief_do_frame(float frametime)
2753 const char *please_wait_str = XSTR("Please Wait", 1242);
2757 SDL_assert(Debrief_inited);
2759 // first thing is to load the files
2760 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2761 // draw the background, etc
2762 GR_MAYBE_CLEAR_RES(Background_bitmap);
2763 if (Background_bitmap >= 0) {
2764 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2768 Debrief_ui_window.draw();
2770 if ( Debrief_multi_loading_bitmap > -1 ){
2771 gr_set_bitmap(Debrief_multi_loading_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2772 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2775 // draw "Please Wait"
2776 gr_set_color_fast(&Color_normal);
2778 gr_get_string_size(&str_w, &str_h, please_wait_str);
2779 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2784 // make sure we run the debrief do frame
2785 if (Game_mode & GM_MULTIPLAYER) {
2786 multi_debrief_do_frame();
2791 int keypress = game_check_key();
2792 if(keypress == SDLK_ESCAPE){
2794 multi_quit_game(PROMPT_CLIENT);
2800 // if multiplayer client, and not loaded voice, then load it
2801 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2802 debrief_multi_fixup_stages();
2803 debrief_voice_load_all();
2804 Debrief_multi_voice_loaded = 1;
2807 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2808 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2809 Debrief_ui_window.set_ignore_gadgets(1);
2812 k = chatbox_process();
2813 if ( Game_mode & GM_NORMAL ) {
2814 new_k = Debrief_ui_window.process(k);
2816 new_k = Debrief_ui_window.process(k, 0);
2819 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2820 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2821 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2822 Debrief_ui_window.set_ignore_gadgets(0);
2828 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2829 Debrief_ui_window.set_ignore_gadgets(0);
2832 // don't show pilot info popup by default
2833 Debrief_should_show_popup = 0;
2835 // see if the mode has changed and handle it if so.
2836 if ( Current_mode != New_mode ) {
2837 debrief_voice_stop();
2838 Current_mode = New_mode;
2841 if (New_mode == DEBRIEF_TAB) {
2843 Debrief_cue_voice = 0;
2845 if (Debrief_first_voice_flag) {
2846 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2847 Debrief_first_voice_flag = 0;
2850 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2854 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2855 Current_stage = New_stage;
2856 debrief_text_init();
2859 debrief_voice_play();
2862 if (Game_mode & GM_MULTIPLAYER) {
2863 multi_debrief_do_frame();
2866 // Now do all the rendering for the frame
2867 GR_MAYBE_CLEAR_RES(Background_bitmap);
2868 if (Background_bitmap >= 0) {
2869 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2873 // draw the damn awarded stuff, G
2874 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2875 gr_set_bitmap(Award_bg_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2876 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2877 if (Rank_bitmap >= 0) {
2878 gr_set_bitmap(Rank_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2880 gr_bitmap(Debrief_rank_coords[0], Debrief_rank_coords[1]);
2882 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2886 if (Medal_bitmap >= 0) {
2887 gr_set_bitmap(Medal_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2888 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2891 if (Badge_bitmap >= 0) {
2892 gr_set_bitmap(Badge_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2894 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2896 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2900 if (Wings_bitmap >= 0) {
2901 gr_set_bitmap(Wings_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2903 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2905 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2909 // this isn't used in FS1 but doesn't hurt to leave it
2910 if (Crest_bitmap >= 0) {
2911 gr_set_bitmap(Crest_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2912 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2915 // draw medal/badge/rank labels
2917 debrief_draw_award_text();
2919 if (Rank_text_bitmap >= 0) {
2920 gr_set_bitmap(Rank_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2921 gr_bitmap(Debrief_rank_text_coords[gr_screen.res][0], Debrief_rank_text_coords[gr_screen.res][1]);
2924 if (Medal_text_bitmap >= 0) {
2925 gr_set_bitmap(Medal_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2926 gr_bitmap(Debrief_medal_text_coords[gr_screen.res][0], Debrief_medal_text_coords[gr_screen.res][1]);
2929 if (Badge_text_bitmap >= 0) {
2930 gr_set_bitmap(Badge_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2931 gr_bitmap(Debrief_badge_text_coords[gr_screen.res][0], Debrief_badge_text_coords[gr_screen.res][1]);
2936 Debrief_ui_window.draw();
2937 debrief_redraw_pressed_buttons();
2938 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2939 if (Recommend_active && (Current_mode != STATS_TAB)) {
2940 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2943 // draw the title of the mission
2944 gr_set_color_fast(&Color_bright_white);
2945 SDL_strlcpy(buf, The_mission.name, sizeof(buf));
2946 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2947 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2949 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2950 gr_set_color_fast(&Color_normal);
2951 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);
2954 // draw the screen-specific text
2955 switch (Current_mode) {
2957 if ( Num_debrief_stages <= 0 ) {
2958 gr_set_color_fast(&Color_white);
2959 SDL_assert( Game_current_mission_filename != NULL );
2960 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);
2969 debrief_stats_render();
2973 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2976 gr_set_color_fast(&Color_red);
2977 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2978 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));
2981 debrief_render_stagenum();
2982 debrief_multi_list_draw();
2984 // render some extra stuff in multiplayer
2985 if (Game_mode & GM_MULTIPLAYER) {
2986 // render the chatbox last
2990 Debrief_ui_window.draw_tooltip();
2992 // render the status indicator for the voice system
2993 multi_common_voice_display_status();
2996 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2997 // want to include the mouse pointer which is drawn in the flip
2999 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
3000 debrief_check_buttons();
3001 debrief_do_keys(new_k);
3004 // blit help overlay if active
3005 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
3009 // dont let dude skip 3-09. hack.
3010 if(Game_mode & GM_CAMPAIGN_MODE){
3011 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
3012 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !SDL_strcasecmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
3013 Debrief_skip_popup_already_shown = 1;
3018 // maybe show skip mission popup
3019 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)) {
3020 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
3021 XSTR("Advance To The Next Mission", 1474),
3022 XSTR("Don't Show Me This Again", 1475),
3023 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
3024 switch (popup_choice) {
3026 // stay on this mission, so proceed to normal debrief
3027 // in other words, do nothing.
3030 // skip this mission
3031 mission_campaign_skip_to_next();
3032 gameseq_post_event(GS_EVENT_START_GAME);
3035 // dont show this again
3036 Player->show_skip_popup = 0;
3040 Debrief_skip_popup_already_shown = 1;
3043 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
3044 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
3045 SDL_assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
3046 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
3048 Debrief_should_show_popup = 0;
3052 void debrief_rebuild_player_list()
3056 debrief_multi_list_info *list;
3058 Multi_list_size = 0; // number of net players to choose from
3060 for ( i=0; i<MAX_PLAYERS; i++ ) {
3061 np = &Net_players[i];
3062 // remember not to include the standalone.
3063 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
3064 list = &Multi_list[Multi_list_size++];
3065 list->net_player_index = i;
3066 SDL_strlcpy(list->callsign, np->player->callsign, sizeof(list->callsign));
3068 // make sure to leave some room to blit the team indicator
3069 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
3074 void debrief_handle_player_drop()
3076 debrief_rebuild_player_list();
3079 void debrief_disable_accept()