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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base2);
1368 SDL_snprintf(Badge_stage.voice, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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, SDL_arraysize(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;
1493 // open localization
1497 read_file_text("traitor.tbl");
1500 // simplied form of the debriefing stuff.
1501 debrief = &Traitor_debriefing;
1502 required_string("#Debriefing_info");
1504 required_string("$Num stages:");
1505 stuff_int(&debrief->num_stages);
1506 SDL_assert(debrief->num_stages == 1);
1509 stagep = &debrief->stages[stage_num++];
1510 required_string("$Formula:");
1511 stagep->formula = get_sexp_main();
1512 required_string("$multi text");
1513 if ( Fred_running ) {
1514 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1516 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1518 required_string("$Voice:");
1519 char traitor_voice_file[NAME_LENGTH];
1520 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1522 // DKA 9/13/99 Only 1 traitor msg for FS2
1524 if ( Player->on_bastion ) {
1525 SDL_strlcpy(stagep->voice, NOX("3_"), SDL_arraysize(stagep->voice));
1527 SDL_strlcpy(stagep->voice, NOX("1_"), SDL_arraysize(stagep->voice));
1531 SDL_strlcat(stagep->voice, traitor_voice_file, SDL_arraysize(stagep->voice));
1533 required_string("$Recommendation text:");
1534 if ( Fred_running ) {
1535 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1537 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1541 } catch (parse_error_t rval) {
1542 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", (int)rval);
1545 // close localization
1549 // disable the accept button if in single player and I am a traitor
1550 Debrief_accepted = 0;
1551 Turned_traitor = Must_replay_mission = 0;
1552 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1553 if (Player_ship->team == TEAM_TRAITOR){
1557 if (Campaign.next_mission == Campaign.current_mission){
1558 Must_replay_mission = 1;
1562 if (Turned_traitor || Must_replay_mission) {
1563 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1565 // kill off any stats
1566 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1567 scoring_level_init( &Player->stats );
1571 // initialization for listing of players in game
1572 void debrief_multi_list_init()
1574 Multi_list_size = 0; // number of net players to choose from
1575 Multi_list_offset = 0;
1577 Multi_list_select = -1;
1579 if ( !(Game_mode & GM_MULTIPLAYER) )
1582 debrief_rebuild_player_list();
1584 // switch stats display to this newly selected player
1585 set_player_stats(Multi_list[0].net_player_index);
1586 SDL_strlcpy(Debrief_current_callsign, Multi_list[0].callsign, SDL_arraysize(Debrief_current_callsign));
1587 Debrief_player = Player;
1590 void debrief_multi_list_scroll_up()
1592 // if we're at the beginning of the list, don't do anything
1593 if(Multi_list_offset == 0){
1594 gamesnd_play_iface(SND_GENERAL_FAIL);
1598 // otherwise scroll up
1599 Multi_list_offset--;
1600 gamesnd_play_iface(SND_USER_SELECT);
1603 void debrief_multi_list_scroll_down()
1605 // if we can scroll down no further
1606 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1607 gamesnd_play_iface(SND_GENERAL_FAIL);
1610 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1611 gamesnd_play_iface(SND_GENERAL_FAIL);
1615 // otherwise scroll down
1616 Multi_list_offset++;
1617 gamesnd_play_iface(SND_USER_SELECT);
1620 // draw the connected net players
1621 void debrief_multi_list_draw()
1623 int y, z, font_height,idx;
1624 char str[CALLSIGN_LEN+5];
1627 font_height = gr_get_font_height();
1629 // if we currently have no item picked, pick a reasonable one
1630 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1631 // select the entry which corresponds to the local player
1632 Multi_list_select = 0;
1633 for(idx=0;idx<Multi_list_size;idx++){
1634 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1635 Multi_list_select = idx;
1637 // switch stats display to this newly selected player
1638 set_player_stats(Multi_list[idx].net_player_index);
1639 SDL_strlcpy(Debrief_current_callsign, Multi_list[idx].callsign, SDL_arraysize(Debrief_current_callsign));
1640 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1646 // draw the list itself
1648 z = Multi_list_offset;
1649 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1650 np = &Net_players[Multi_list[z].net_player_index];
1652 if (z >= Multi_list_size){
1655 // set the proper text color for the highlight
1656 if(np->flags & NETINFO_FLAG_GAME_HOST){
1657 if(Multi_list_select == z){
1658 gr_set_color_fast(&Color_text_active_hi);
1660 gr_set_color_fast(&Color_bright);
1663 if(Multi_list_select == z){
1664 gr_set_color_fast(&Color_text_active);
1666 gr_set_color_fast(&Color_text_normal);
1670 // blit the proper indicator - skipping observers
1671 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1672 if(Netgame.type_flags & NG_TYPE_TEAM){
1674 if(np->p_info.team == 0){
1675 // draw his "selected" icon
1676 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1677 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1678 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1680 // draw his "normal" icon
1681 else if(Multi_common_icons[MICON_TEAM0] != -1){
1682 gr_set_bitmap(Multi_common_icons[MICON_TEAM0], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1683 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1685 } else if(np->p_info.team == 1){
1686 // draw his "selected" icon
1687 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1688 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1689 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1691 // draw his "normal" icon
1692 else if(Multi_common_icons[MICON_TEAM1] != -1){
1693 gr_set_bitmap(Multi_common_icons[MICON_TEAM1], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1694 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1698 // draw the team 0 selected icon
1699 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1700 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1701 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1706 SDL_strlcpy(str, Multi_list[z].callsign, SDL_arraysize(str));
1707 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)){
1708 SDL_strlcat(str, XSTR( "(O)", 438), SDL_arraysize(str));
1712 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1719 void debrief_kick_selected_player()
1721 if(Multi_list_select >= 0){
1722 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1723 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1727 // get optional mission popup text
1728 void debrief_assemble_optional_mission_popup_text(char *buffer, const int buf_len, char *mission_loop_desc)
1730 SDL_assert(buffer != NULL);
1733 if (mission_loop_desc == NULL) {
1734 SDL_strlcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490), buf_len);
1735 mprintf(("No mission loop description avail"));
1737 SDL_strlcpy(buffer, mission_loop_desc, buf_len);
1740 SDL_strlcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491), buf_len);
1743 // what to do when the accept button is hit
1744 void debrief_accept(int ok_to_post_start_game_event)
1748 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1752 if (Game_mode & GM_MULTIPLAYER) {
1756 if (Player_ship->team == TEAM_TRAITOR){
1757 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1758 }/* else if (Cheats_enabled) {
1759 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1761 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1764 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1766 gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing
1767 } else if ( z == 1 ) {
1768 gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats
1774 Debrief_accepted = 1;
1775 // save mission stats
1776 if (Game_mode & GM_MULTIPLAYER) {
1777 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1778 // as well as doing stats transfers, etc.
1779 multi_debrief_accept_hit();
1783 int play_commit_sound = 1;
1784 // only write the player's stats if he's accepted
1786 // if we are just playing a single mission, then don't do many of the things
1787 // that need to be done. Nothing much should happen when just playing a single
1788 // mission that isn't in a campaign.
1789 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1791 // check for possible mission loop
1792 // check for (1) mission loop available, (2) dont have to repeat last mission
1793 if(!(Game_mode & GM_MULTIPLAYER)){
1794 int cur = Campaign.current_mission;
1795 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1796 if (Campaign.missions[cur].has_mission_loop) {
1797 SDL_assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1800 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1803 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1805 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1807 Campaign.loop_enabled = 1;
1808 Campaign.next_mission = Campaign.loop_mission;
1817 if(ok_to_post_start_game_event){
1818 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1820 play_commit_sound = 0;
1823 // continue as normal
1826 mission_campaign_mission_over();
1828 // check to see if we are out of the loop now
1829 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1830 Campaign.loop_enabled = 0;
1833 // check if campaign is over
1834 if ( Campaign.next_mission == -1 ) {
1835 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
1836 gameseq_post_event(GS_EVENT_END_DEMO);
1838 gameseq_post_event(GS_EVENT_MAIN_MENU);
1841 if ( ok_to_post_start_game_event ) {
1842 gameseq_post_event(GS_EVENT_START_GAME);
1844 play_commit_sound = 0;
1849 gameseq_post_event(GS_EVENT_MAIN_MENU);
1852 if ( play_commit_sound ) {
1853 gamesnd_play_iface(SND_COMMIT_PRESSED);
1860 void debrief_next_tab()
1862 New_mode = Current_mode + 1;
1863 if (New_mode >= NUM_TABS)
1867 void debrief_prev_tab()
1869 New_mode = Current_mode - 1;
1871 New_mode = NUM_TABS - 1;
1874 // --------------------------------------------------------------------------------------
1875 // debrief_next_stage()
1877 void debrief_next_stage()
1879 if (Current_stage < Num_stages - 1) {
1880 New_stage = Current_stage + 1;
1881 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1884 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1887 // --------------------------------------------------------------------------------------
1888 // debrief_prev_stage()
1890 void debrief_prev_stage()
1892 if (Current_stage) {
1893 New_stage = Current_stage - 1;
1894 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1897 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1900 // --------------------------------------------------------------------------------------
1901 // debrief_first_stage()
1902 void debrief_first_stage()
1904 if (Current_stage) {
1906 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1909 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1912 // --------------------------------------------------------------------------------------
1913 // debrief_last_stage()
1914 void debrief_last_stage()
1916 if (Current_stage != Num_stages - 1) {
1917 New_stage = Num_stages - 1;
1918 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1921 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1924 // draw what stage number the debriefing is on
1925 void debrief_render_stagenum()
1933 SDL_snprintf(buf, SDL_arraysize(buf), XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1934 gr_get_string_size(&w, NULL, buf);
1935 gr_set_color_fast(&Color_bright_blue);
1936 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1937 gr_set_color_fast(&Color_white);
1940 // render the mission time at the specified y location
1941 void debrief_render_mission_time(int y_loc)
1945 game_format_time(Missiontime, time_str, SDL_arraysize(time_str));
1946 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1947 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1950 // render out the debriefing text to the scroll window
1951 void debrief_render()
1953 int y, z, font_height;
1955 if ( Num_stages <= 0 )
1958 font_height = gr_get_font_height();
1960 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]);
1963 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1964 if (z >= Num_text_lines)
1967 if (Text_type[z] == TEXT_TYPE_NORMAL)
1968 gr_set_color_fast(&Color_white);
1970 gr_set_color_fast(&Color_bright_red);
1973 gr_string(0, y, Text[z]);
1982 // render out the stats info to the scroll window
1984 void debrief_stats_render()
1986 int i, y, font_height;
1988 gr_set_color_fast(&Color_blue);
1989 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]);
1990 gr_string(0, 0, Debrief_current_callsign);
1991 font_height = gr_get_font_height();
1994 switch ( Current_stage ) {
1995 case DEBRIEF_MISSION_STATS:
1996 i = Current_stage - 1;
2000 gr_set_color_fast(&Color_white);
2002 // display mission completion time
2003 debrief_render_mission_time(y);
2006 show_stats_label(i, 0, y, font_height);
2007 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2009 case DEBRIEF_ALLTIME_STATS:
2010 i = Current_stage - 1;
2014 gr_set_color_fast(&Color_white);
2015 show_stats_label(i, 0, y, font_height);
2016 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2019 case DEBRIEF_ALLTIME_KILLS:
2020 case DEBRIEF_MISSION_KILLS:
2021 gr_set_color_fast(&Color_white);
2023 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
2024 if (i >= Num_text_lines)
2028 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2029 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
2031 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
2034 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
2035 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
2042 if (Num_text_lines == 2) {
2043 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2044 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
2046 gr_printf(0, y, XSTR( "(No ship kills)", 450));
2059 // do action for when the replay button is pressed
2060 void debrief_replay_pressed()
2062 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2064 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));
2071 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
2072 gamesnd_play_iface(SND_COMMIT_PRESSED);
2075 // -------------------------------------------------------------------
2076 // debrief_redraw_pressed_buttons()
2078 // Redraw any debriefing buttons that are pressed down. This function is needed
2079 // since we sometimes need to draw pressed buttons last to ensure the entire
2080 // button gets drawn (and not overlapped by other buttons)
2082 void debrief_redraw_pressed_buttons()
2087 for ( i=0; i<NUM_BUTTONS; i++ ) {
2088 b = &Buttons[gr_screen.res][i].button;
2089 // don't draw the recommendations button if we're in stats mode
2090 if ( b->button_down() ) {
2096 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
2098 void debrief_button_pressed(int num)
2102 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
2103 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
2104 if (num != Current_mode){
2105 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2110 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
2111 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
2112 if (num != Current_mode){
2113 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2118 case TEXT_SCROLL_UP:
2121 gamesnd_play_iface(SND_SCROLL);
2123 gamesnd_play_iface(SND_GENERAL_FAIL);
2127 case TEXT_SCROLL_DOWN:
2128 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2130 gamesnd_play_iface(SND_SCROLL);
2132 gamesnd_play_iface(SND_GENERAL_FAIL);
2136 case REPLAY_MISSION:
2137 if(Game_mode & GM_MULTIPLAYER){
2138 multi_debrief_replay_hit();
2140 debrief_replay_pressed();
2144 case RECOMMENDATIONS:
2145 gamesnd_play_iface(SND_USER_SELECT);
2146 Recommend_active = !Recommend_active;
2147 debrief_text_init();
2151 debrief_first_stage();
2155 debrief_prev_stage();
2159 debrief_next_stage();
2163 debrief_last_stage();
2167 gamesnd_play_iface(SND_HELP_PRESSED);
2168 launch_context_help();
2171 case OPTIONS_BUTTON:
2172 gamesnd_play_iface(SND_SWITCH_SCREENS);
2173 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2181 gamesnd_play_iface(SND_SWITCH_SCREENS);
2182 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2185 case PLAYER_SCROLL_UP:
2186 debrief_multi_list_scroll_up();
2189 case PLAYER_SCROLL_DOWN:
2190 debrief_multi_list_scroll_down();
2193 case MULTI_PINFO_POPUP:
2194 Debrief_should_show_popup = 1;
2198 debrief_kick_selected_player();
2203 void debrief_setup_ship_kill_stats(int stage_num)
2211 debrief_stats_kill_info *kill_info;
2213 SDL_assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2214 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2217 SDL_assert(Debrief_player != NULL);
2219 // kill_ar points to an array of MAX_SHIP_TYPE ints
2220 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2221 kill_arr = Debrief_player->stats.m_okKills;
2223 kill_arr = Debrief_player->stats.kills;
2227 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2229 // code used to add in mission kills, but the new system assumes that the player will accept, so
2230 // all time stats already have mission stats added in.
2231 if ( kill_arr[i] <= 0 ){
2236 kill_info = &Debrief_stats_kills[Num_text_lines++];
2238 kill_info->num = kill_arr[i];
2240 SDL_strlcpy(kill_info->text, Ship_info[i].name, SDL_arraysize(kill_info->text));
2241 SDL_strlcat(kill_info->text, NOX(":"), SDL_arraysize(kill_info->text));
2244 Num_text_lines += 2;
2247 // Iterate through the debriefing buttons, checking if they are pressed
2248 void debrief_check_buttons()
2252 for ( i=0; i<NUM_BUTTONS; i++ ) {
2253 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2254 debrief_button_pressed(i);
2258 if ( !(Game_mode & GM_MULTIPLAYER) )
2261 if (List_region.pressed()) {
2262 List_region.get_mouse_pos(NULL, &y);
2263 z = Multi_list_offset + y / gr_get_font_height();
2264 if ((z >= 0) && (z < Multi_list_size)) {
2265 // switch stats display to this newly selected player
2266 set_player_stats(Multi_list[z].net_player_index);
2267 SDL_strlcpy(Debrief_current_callsign, Multi_list[z].callsign, SDL_arraysize(Debrief_current_callsign));
2268 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2269 Multi_list_select = z;
2270 debrief_setup_ship_kill_stats(Current_stage);
2271 gamesnd_play_iface(SND_USER_SELECT);
2275 // if the player was double clicked on - we should popup a player info popup
2277 if (List_region.double_clicked()) {
2278 Debrief_should_show_popup = 1;
2283 void debrief_text_stage_init(const char *src, int type)
2285 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2286 char line[MAX_DEBRIEF_LINE_LEN];
2287 char *p_str[MAX_DEBRIEF_LINES];
2290 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2291 SDL_assert(n_lines >= 0);
2293 // if you hit this, you proba
2294 if(n_lines >= MAX_DEBRIEF_LINES){
2295 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2298 for ( i=0; i<n_lines; i++ ) {
2299 SDL_assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2300 SDL_assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2301 len = min(n_chars[i] + 1, MAX_DEBRIEF_LINE_LEN);
2302 SDL_strlcpy(line, p_str[i], len);
2303 line[n_chars[i]] = 0;
2304 drop_white_space(line);
2305 Text_type[Num_text_lines] = type;
2306 Text[Num_text_lines++] = strdup(line);
2312 void debrief_free_text()
2316 for (i=0; i<Num_debrief_lines; i++)
2320 Num_debrief_lines = 0;
2323 // setup the debriefing text lines for rendering
2324 void debrief_text_init()
2329 // release old text lines first
2330 debrief_free_text();
2331 Num_text_lines = Text_offset = 0;
2333 if (Current_mode == DEBRIEF_TAB) {
2334 for (i=0; i<Num_debrief_stages; i++) {
2336 Text[Num_text_lines++] = NULL; // add a blank line between stages
2338 src = Debrief_stages[i]->new_text;
2340 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2342 if (Recommend_active) {
2343 src = Debrief_stages[i]->new_recommendation_text;
2344 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2345 src = XSTR( "We have no recommendations for you.", 1054);
2348 Text[Num_text_lines++] = NULL;
2349 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2355 Num_debrief_lines = Num_text_lines;
2359 // not in debriefing mode, must be in stats mode
2361 debrief_setup_ship_kill_stats(Current_stage);
2365 // --------------------------------------------------------------------------------------
2369 SDL_assert(!Debrief_inited);
2370 // Campaign.loop_enabled = 0;
2371 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2373 // set up the right briefing for this guy
2374 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2375 Debriefing = &Debriefings[Net_player->p_info.team];
2377 Debriefing = &Debriefings[0];
2380 // no longer is mission
2381 Game_mode &= ~(GM_IN_MISSION);
2385 New_mode = DEBRIEF_TAB;
2386 Recommend_active = Award_active = 0;
2391 Debrief_cue_voice = 0;
2392 Num_text_lines = Num_debrief_lines = 0;
2393 Debrief_first_voice_flag = 1;
2395 Debrief_multi_voice_loaded = 0;
2398 Medal_text_bitmap = bm_load(NOX("DebriefText01"));
2399 Rank_text_bitmap = bm_load(NOX("DebriefText02"));
2400 Badge_text_bitmap = bm_load(NOX("DebriefText03"));
2403 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2404 // MUST store goals and events first - may be used to evaluate next mission
2405 // store goals and events
2406 mission_campaign_store_goals_and_events();
2408 // evaluate next mission
2409 mission_campaign_eval_next_mission();
2412 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2414 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2415 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2418 // call scoring level close for my stats. Needed for award_init. The stats will
2419 // be backed out if used chooses to replace them.
2420 scoring_level_close();
2422 debrief_ui_init(); // init UI items
2423 debrief_award_init();
2425 debrief_voice_init();
2426 debrief_multi_list_init();
2427 // rank_bitmaps_clear();
2428 // rank_bitmaps_load();
2430 SDL_strlcpy(Debrief_current_callsign, Player->callsign, SDL_arraysize(Debrief_current_callsign));
2431 Debrief_player = Player;
2432 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2434 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2435 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2436 // info directly from the server.
2437 if ( !MULTIPLAYER_CLIENT ) {
2438 debrief_set_stages_and_multi_stuff();
2440 if ( Num_debrief_stages <= 0 ) {
2441 Num_debrief_stages = 0;
2443 debrief_voice_load_all();
2446 // multiplayer client may have already received their debriefing info. If they have not,
2447 // then set the num debrief stages to 0
2448 if ( !Debrief_multi_stages_loaded ) {
2449 Num_debrief_stages = 0;
2454 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2455 common_music_init(SCORE_DEBRIEF_SUCCESS);
2457 common_music_init(SCORE_DEBRIEF_FAIL);
2461 // start up the appropriate music
2462 if (Campaign.next_mission == Campaign.current_mission) {
2463 // you failed the mission because you suck, so you get the suck music
2464 common_music_init(SCORE_DEBRIEF_FAIL);
2465 } else if (mission_goals_met()) {
2466 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2467 common_music_init(SCORE_DEBRIEF_SUCCESS);
2469 // you somehow passed the mission, so you get a little something for your efforts.
2470 common_music_init(SCORE_DEBRIEF_AVERAGE);
2473 if (Campaign.next_mission == Campaign.current_mission) {
2474 // better luck next time, increase his retries
2475 Player->failures_this_session++;
2477 // clear his retries info regardless of whether or not he accepts
2478 Player->failures_this_session = 0;
2481 if (Game_mode & GM_MULTIPLAYER) {
2482 multi_debrief_init();
2484 // if i'm not the host of the game, disable the multi kick button
2485 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2486 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2489 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2490 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2491 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2492 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2493 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2494 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2495 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2496 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2499 if (!Award_active) {
2500 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2501 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2504 Debrief_skip_popup_already_shown = 0;
2509 // --------------------------------------------------------------------------------------
2511 void debrief_close()
2515 SDL_assert(Debrief_inited);
2517 // if the mission wasn't accepted, clear out my stats
2518 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2519 // are a little bit different
2520 if (Game_mode & GM_MULTIPLAYER) {
2521 // if stats weren't accepted, backout my own stats
2522 if (multi_debrief_stats_accept_code() != 1) {
2523 if(MULTIPLAYER_MASTER){
2524 for(idx=0; idx<MAX_PLAYERS; idx++){
2525 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2526 scoring_backout_accept(&Net_players[idx].player->stats);
2530 scoring_backout_accept( &Player->stats );
2535 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2536 scoring_backout_accept( &Player->stats );
2540 // if dude passed the misson and accepted, reset his show skip popup flag
2541 if (Debrief_accepted) {
2542 Player->show_skip_popup = 1;
2545 if (Num_debrief_lines) {
2546 for (i=0; i<Num_debrief_lines; i++){
2553 // clear out debrief info parsed from mission file
2554 mission_debrief_common_reset();
2556 // unload the overlay bitmap
2558 help_overlay_unload(DEBRIEFING_OVERLAY);
2561 // clear out award text
2562 Debrief_award_text_num_lines = 0;
2564 debrief_voice_unload_all();
2565 common_music_close();
2568 // rank_bitmaps_release();
2571 if (Background_bitmap >= 0){
2572 bm_unload(Background_bitmap);
2575 if (Award_bg_bitmap >= 0){
2576 bm_unload(Award_bg_bitmap);
2579 if (Rank_bitmap >= 0){
2580 bm_unload(Rank_bitmap);
2583 if (Medal_bitmap >= 0){
2584 bm_unload(Medal_bitmap);
2587 if (Badge_bitmap >= 0){
2588 bm_unload(Badge_bitmap);
2591 if (Wings_bitmap >= 0) {
2592 bm_unload(Wings_bitmap);
2595 if (Crest_bitmap >= 0) {
2596 bm_unload(Crest_bitmap);
2600 if (Medal_text_bitmap >= 0) {
2601 bm_unload(Medal_text_bitmap);
2604 if (Badge_text_bitmap >= 0) {
2605 bm_unload(Badge_text_bitmap);
2608 if (Rank_text_bitmap >= 0) {
2609 bm_unload(Rank_text_bitmap);
2613 Debrief_ui_window.destroy();
2614 common_free_interface_palette(); // restore game palette
2617 if (Game_mode & GM_MULTIPLAYER){
2618 multi_debrief_close();
2628 // handle keypresses in debriefing
2629 void debrief_do_keys(int new_k)
2636 case KEY_SHIFTED | SDLK_TAB:
2644 // multiplayer accept popup is a little bit different
2645 if (Game_mode & GM_MULTIPLAYER) {
2646 multi_debrief_esc_hit();
2648 // display the normal debrief popup
2650 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2651 pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2652 choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2653 if (choice == 1) { // accept and continue on
2655 gameseq_post_event(GS_EVENT_MAIN_MENU);
2661 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2662 // need to popup saying that mission was a failure and must be replayed
2663 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));
2668 // Return to Main Hall
2669 gameseq_post_event(GS_EVENT_END_GAME);
2680 void debrief_draw_award_text()
2682 int start_y, curr_y, i, x, sw;
2683 int fh = gr_get_font_height();
2684 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];
2686 // vertically centered within field
2687 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);
2691 for (i=0; i<Debrief_award_text_num_lines; i++) {
2692 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2693 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2694 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2695 gr_set_color_fast(&Color_white);
2696 gr_string(x, curr_y, Debrief_award_text[i]);
2698 // adjust y pos, including a little extra between the "pairs"
2700 if ((i == 1) || (i == 3)) {
2701 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2706 // clears out text array so we dont have old award text showing up on new awards.
2707 void debrief_award_text_clear() {
2710 Debrief_award_text_num_lines = 0;
2711 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2712 //Debrief_award_text[i][0] = 0;
2713 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2717 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2718 void debrief_add_award_text(char *str)
2720 SDL_assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2721 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2726 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];
2729 SDL_strlcpy(Debrief_award_text[Debrief_award_text_num_lines], str, AWARD_TEXT_MAX_LINE_LENGTH);
2731 // maybe translate for displaying
2733 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2734 } else if (Lcl_pl) {
2735 medals_translate_name_pl(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2738 Debrief_award_text_num_lines++;
2740 // if its too long, split once ONLY
2741 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2742 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2743 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2744 if (line2 != NULL) {
2745 SDL_snprintf(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH, " %s", line2); // indent a space
2747 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2750 #endif // !MAKE_FS1: No text for FS1, it's all bitmaps
2752 // called once per frame to drive all the input reading and rendering
2753 void debrief_do_frame(float frametime)
2756 const char *please_wait_str = XSTR("Please Wait", 1242);
2760 SDL_assert(Debrief_inited);
2762 // first thing is to load the files
2763 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2764 // draw the background, etc
2765 GR_MAYBE_CLEAR_RES(Background_bitmap);
2766 if (Background_bitmap >= 0) {
2767 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2771 Debrief_ui_window.draw();
2773 if ( Debrief_multi_loading_bitmap > -1 ){
2774 gr_set_bitmap(Debrief_multi_loading_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2775 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2778 // draw "Please Wait"
2779 gr_set_color_fast(&Color_normal);
2781 gr_get_string_size(&str_w, &str_h, please_wait_str);
2782 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2787 // make sure we run the debrief do frame
2788 if (Game_mode & GM_MULTIPLAYER) {
2789 multi_debrief_do_frame();
2794 int keypress = game_check_key();
2795 if(keypress == SDLK_ESCAPE){
2797 multi_quit_game(PROMPT_CLIENT);
2803 // if multiplayer client, and not loaded voice, then load it
2804 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2805 debrief_multi_fixup_stages();
2806 debrief_voice_load_all();
2807 Debrief_multi_voice_loaded = 1;
2810 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2811 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2812 Debrief_ui_window.set_ignore_gadgets(1);
2815 k = chatbox_process();
2816 if ( Game_mode & GM_NORMAL ) {
2817 new_k = Debrief_ui_window.process(k);
2819 new_k = Debrief_ui_window.process(k, 0);
2822 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2823 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2824 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2825 Debrief_ui_window.set_ignore_gadgets(0);
2831 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2832 Debrief_ui_window.set_ignore_gadgets(0);
2835 // don't show pilot info popup by default
2836 Debrief_should_show_popup = 0;
2838 // see if the mode has changed and handle it if so.
2839 if ( Current_mode != New_mode ) {
2840 debrief_voice_stop();
2841 Current_mode = New_mode;
2844 if (New_mode == DEBRIEF_TAB) {
2846 Debrief_cue_voice = 0;
2848 if (Debrief_first_voice_flag) {
2849 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2850 Debrief_first_voice_flag = 0;
2853 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2857 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2858 Current_stage = New_stage;
2859 debrief_text_init();
2862 debrief_voice_play();
2865 if (Game_mode & GM_MULTIPLAYER) {
2866 multi_debrief_do_frame();
2869 // Now do all the rendering for the frame
2870 GR_MAYBE_CLEAR_RES(Background_bitmap);
2871 if (Background_bitmap >= 0) {
2872 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2876 // draw the damn awarded stuff, G
2877 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2878 gr_set_bitmap(Award_bg_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2879 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2880 if (Rank_bitmap >= 0) {
2881 gr_set_bitmap(Rank_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2883 gr_bitmap(Debrief_rank_coords[0], Debrief_rank_coords[1]);
2885 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2889 if (Medal_bitmap >= 0) {
2890 gr_set_bitmap(Medal_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2891 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2894 if (Badge_bitmap >= 0) {
2895 gr_set_bitmap(Badge_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2897 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2899 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2903 if (Wings_bitmap >= 0) {
2904 gr_set_bitmap(Wings_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2906 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2908 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2912 // this isn't used in FS1 but doesn't hurt to leave it
2913 if (Crest_bitmap >= 0) {
2914 gr_set_bitmap(Crest_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2915 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2918 // draw medal/badge/rank labels
2920 debrief_draw_award_text();
2922 if (Rank_text_bitmap >= 0) {
2923 gr_set_bitmap(Rank_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2924 gr_bitmap(Debrief_rank_text_coords[gr_screen.res][0], Debrief_rank_text_coords[gr_screen.res][1]);
2927 if (Medal_text_bitmap >= 0) {
2928 gr_set_bitmap(Medal_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2929 gr_bitmap(Debrief_medal_text_coords[gr_screen.res][0], Debrief_medal_text_coords[gr_screen.res][1]);
2932 if (Badge_text_bitmap >= 0) {
2933 gr_set_bitmap(Badge_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2934 gr_bitmap(Debrief_badge_text_coords[gr_screen.res][0], Debrief_badge_text_coords[gr_screen.res][1]);
2939 Debrief_ui_window.draw();
2940 debrief_redraw_pressed_buttons();
2941 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2942 if (Recommend_active && (Current_mode != STATS_TAB)) {
2943 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2946 // draw the title of the mission
2947 gr_set_color_fast(&Color_bright_white);
2948 SDL_strlcpy(buf, The_mission.name, SDL_arraysize(buf));
2949 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2950 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
2952 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2953 gr_set_color_fast(&Color_normal);
2954 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);
2957 // draw the screen-specific text
2958 switch (Current_mode) {
2960 if ( Num_debrief_stages <= 0 ) {
2961 gr_set_color_fast(&Color_white);
2962 SDL_assert( Game_current_mission_filename != NULL );
2963 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);
2972 debrief_stats_render();
2976 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2979 gr_set_color_fast(&Color_red);
2980 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2981 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));
2984 debrief_render_stagenum();
2985 debrief_multi_list_draw();
2987 // render some extra stuff in multiplayer
2988 if (Game_mode & GM_MULTIPLAYER) {
2989 // render the chatbox last
2993 Debrief_ui_window.draw_tooltip();
2995 // render the status indicator for the voice system
2996 multi_common_voice_display_status();
2999 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
3000 // want to include the mouse pointer which is drawn in the flip
3002 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
3003 debrief_check_buttons();
3004 debrief_do_keys(new_k);
3007 // blit help overlay if active
3008 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
3012 // dont let dude skip 3-09. hack.
3013 if(Game_mode & GM_CAMPAIGN_MODE){
3014 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
3015 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !SDL_strcasecmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
3016 Debrief_skip_popup_already_shown = 1;
3021 // maybe show skip mission popup
3022 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)) {
3023 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
3024 XSTR("Advance To The Next Mission", 1474),
3025 XSTR("Don't Show Me This Again", 1475),
3026 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
3027 switch (popup_choice) {
3029 // stay on this mission, so proceed to normal debrief
3030 // in other words, do nothing.
3033 // skip this mission
3034 mission_campaign_skip_to_next();
3035 gameseq_post_event(GS_EVENT_START_GAME);
3038 // dont show this again
3039 Player->show_skip_popup = 0;
3043 Debrief_skip_popup_already_shown = 1;
3046 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
3047 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
3048 SDL_assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
3049 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
3051 Debrief_should_show_popup = 0;
3055 void debrief_rebuild_player_list()
3059 debrief_multi_list_info *list;
3061 Multi_list_size = 0; // number of net players to choose from
3063 for ( i=0; i<MAX_PLAYERS; i++ ) {
3064 np = &Net_players[i];
3065 // remember not to include the standalone.
3066 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
3067 list = &Multi_list[Multi_list_size++];
3068 list->net_player_index = i;
3069 SDL_strlcpy(list->callsign, np->player->callsign, SDL_arraysize(list->callsign));
3071 // make sure to leave some room to blit the team indicator
3072 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
3077 void debrief_handle_player_drop()
3079 debrief_rebuild_player_list();
3082 void debrief_disable_accept()