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 #include "techmenu.h"
401 #define MAX_TOTAL_DEBRIEF_LINES 200
403 #define TEXT_TYPE_NORMAL 1
404 #define TEXT_TYPE_RECOMMENDATION 2
406 #define DEBRIEF_NUM_STATS_PAGES 4
407 #define DEBRIEF_MISSION_STATS 0
408 #define DEBRIEF_MISSION_KILLS 1
409 #define DEBRIEF_ALLTIME_STATS 2
410 #define DEBRIEF_ALLTIME_KILLS 3
412 // 3rd coord is max width in pixels
413 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
426 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
439 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
444 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
457 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
470 #define MULTI_LIST_TEAM_OFFSET 16
472 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
477 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
486 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
499 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
513 int Debrief_rank_coords[2] = {
517 int Debrief_badge_coords[2] = {
523 // 0=x, 1=y, 2=width of the field
524 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
533 // 0=x, 1=y, 2=height of the field
534 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
543 // the medal text in FS1 is a bitmap
544 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][2] = {
553 int Debrief_rank_text_coords[GR_NUM_RESOLUTIONS][2] = {
562 int Debrief_badge_text_coords[GR_NUM_RESOLUTIONS][2] = {
573 // 1 = without medal (text will use medal space)
574 #define DB_WITH_MEDAL 0
575 #define DB_WITHOUT_MEDAL 1
576 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
585 const char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
586 "DebriefSingle", // GR_640
587 "2_DebriefSingle" // GR_1024
589 const char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
590 "DebriefMulti", // GR_640
591 "2_DebriefMulti" // GR_1024
593 const char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
594 "Debrief-m", // GR_640
595 "2_Debrief-m" // GR_1024
598 #define NUM_BUTTONS 18
601 #define DEBRIEF_TAB 0
603 #define TEXT_SCROLL_UP 2
604 #define TEXT_SCROLL_DOWN 3
605 #define REPLAY_MISSION 4
606 #define RECOMMENDATIONS 5
607 #define FIRST_STAGE 6
611 #define MULTI_PINFO_POPUP 10
612 #define MULTI_KICK 11
613 #define MEDALS_BUTTON 12
614 #define PLAYER_SCROLL_UP 13
615 #define PLAYER_SCROLL_DOWN 14
616 #define HELP_BUTTON 15
617 #define OPTIONS_BUTTON 16
618 #define ACCEPT_BUTTON 17
623 const char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
624 "PleaseWait", // GR_640
625 "2_PleaseWait" // GR_1024
631 char text[NAME_LENGTH+1]; // name of ship type with a colon
632 int num; // how many ships of this type player has killed
633 } debrief_stats_kill_info;
636 int net_player_index; // index into Net_players[] array
637 int rank_bitmap; // bitmap id for rank
638 char callsign[CALLSIGN_LEN];
639 } debrief_multi_list_info;
641 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
644 ui_button_info("DB_00", 0, 2, -1, -1, 0), // debriefing
645 ui_button_info("DB_01", 0, 20, -1, -1, 1), // statistics
646 ui_button_info("DB_02", 0, 195, -1, -1, 2), // scroll stats up
647 ui_button_info("DB_03", 0, 232, -1, -1, 3), // scroll stats down
648 ui_button_info("DB_04", 24, 424, -1, -1, 4), // replay mission
649 ui_button_info("DB_05", 30, 451, -1, -1, 5), // recommendations
650 ui_button_info("DB_06", 211, 445, -1, -1, 6), // first page
651 ui_button_info("DB_07", 234, 445, -1, -1, 7), // prev page
652 ui_button_info("DB_08", 259, 445, -1, -1, 8), // next page
653 ui_button_info("DB_09", 283, 445, -1, -1, 9), // last page
654 ui_button_info("DB_21", 441, 384, -1, -1, 21), // pilot info
655 ui_button_info("DB_25", 511, 384, -1, -1, 25), // kick
656 ui_button_info("DB_15", 604, 224, -1, -1, 15), // medals
657 ui_button_info("DB_16", 615, 329, -1, -1, 16), // scroll pilots up
658 ui_button_info("DB_17", 615, 371, -1, -1, 17), // scroll pilots down
659 ui_button_info("DB_10", 469, 428, -1, -1, 10), // help
660 ui_button_info("DB_11", 447, 452, -1, -1, 11), // options
661 ui_button_info("DB_12", 562, 410, -1, -1, 12), // accept
663 ui_button_info("DB_00", 6, 1, 37, 7, 0), // debriefing
664 ui_button_info("DB_01", 6, 21, 37, 23, 1), // statistics
665 ui_button_info("DB_02", 1, 195, -1, -1, 2), // scroll stats up
666 ui_button_info("DB_03", 1, 236, -1, -1, 3), // scroll stats down
667 ui_button_info("DB_04", 1, 428, 49, 447, 4), // replay mission
668 ui_button_info("DB_05", 17, 459, 49, 464, 5), // recommendations
669 ui_button_info("DB_06", 323, 454, -1, -1, 6), // first page
670 ui_button_info("DB_07", 348, 454, -1, -1, 7), // prev page
671 ui_button_info("DB_08", 372, 454, -1, -1, 8), // next page
672 ui_button_info("DB_09", 396, 454, -1, -1, 9), // last page
673 ui_button_info("DB_10", 441, 384, 433, 413, 10), // pilot info
674 ui_button_info("DB_11", 511, 384, 510, 413, 11), // kick
675 ui_button_info("DB_12", 613, 226, -1, -1, 12), // medals
676 ui_button_info("DB_13", 615, 329, -1, -1, 13), // scroll pilots up
677 ui_button_info("DB_14", 615, 371, -1, -1, 14), // scroll pilots down
678 ui_button_info("DB_15", 538, 431, 500, 440, 15), // help
679 ui_button_info("DB_16", 538, 455, 479, 464, 16), // options
680 ui_button_info("DB_17", 573, 432, 572, 413, 17), // accept
684 ui_button_info("2_DB_00", 10, 1, 59, 12, 0), // debriefing
685 ui_button_info("2_DB_01", 10, 33, 59, 37, 1), // statistics
686 ui_button_info("2_DB_02", 1, 312, -1, -1, 2), // scroll stats up
687 ui_button_info("2_DB_03", 1, 378, -1, -1, 3), // scroll stats down
688 ui_button_info("2_DB_04", 1, 685, 79, 715, 4), // replay mission
689 ui_button_info("2_DB_05", 28, 735, 79, 743, 5), // recommendations
690 ui_button_info("2_DB_06", 517, 726, -1, -1, 6), // first page
691 ui_button_info("2_DB_07", 556, 726, -1, -1, 7), // prev page
692 ui_button_info("2_DB_08", 595, 726, -1, -1, 8), // next page
693 ui_button_info("2_DB_09", 633, 726, -1, -1, 9), // last page
694 ui_button_info("2_DB_10", 706, 615, 700, 661, 10), // pilot info
695 ui_button_info("2_DB_11", 817, 615, 816, 661, 11), // kick
696 ui_button_info("2_DB_12", 981, 362, -1, -1, 12), // medals
697 ui_button_info("2_DB_13", 984, 526, -1, -1, 13), // scroll pilots up
698 ui_button_info("2_DB_14", 984, 594, -1, -1, 14), // scroll pilots down
699 ui_button_info("2_DB_15", 861, 689, 801, 705, 15), // help
700 ui_button_info("2_DB_16", 861, 728, 777, 744, 16), // options
701 ui_button_info("2_DB_17", 917, 692, 917, 692, 17), // accept
707 #define NUM_DEBRIEF_TEXT 10
708 #define MP_TEXT_INDEX_1 4
709 #define MP_TEXT_INDEX_2 5
710 #define MP_TEXT_INDEX_3 6
711 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
713 { "Debriefing", 804, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][DEBRIEF_TAB].button },
714 { "Statistics", 1333, 37, 26, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][STATS_TAB].button },
715 { "Replay Mission", 444, 49, 447, UI_XSTR_COLOR_PINK, -1, &Buttons[0][REPLAY_MISSION].button },
716 { "Recommendations", 1334, 49, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][RECOMMENDATIONS].button },
717 { "Pilot", 1310, 433, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
718 { "Info", 1311, 433, 423, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_PINFO_POPUP].button },
719 { "Kick", 1266, 510, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][MULTI_KICK].button },
720 { "Help", 928, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][HELP_BUTTON].button },
721 { "Options", 1036, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][OPTIONS_BUTTON].button },
722 { "Accept", 1035, 572, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][ACCEPT_BUTTON].button },
725 { "Debriefing", 804, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][DEBRIEF_TAB].button },
726 { "Statistics", 1333, 59, 47, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][STATS_TAB].button },
727 { "Replay Mission", 444, 79, 715, UI_XSTR_COLOR_PINK, -1, &Buttons[1][REPLAY_MISSION].button },
728 { "Recommendations", 1334, 79, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][RECOMMENDATIONS].button },
729 { "Pilot", 1310, 700, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
730 { "Info", 1311, 700, 679, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_PINFO_POPUP].button },
731 { "Kick", 1266, 816, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][MULTI_KICK].button },
732 { "Help", 928, 801, 705, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][HELP_BUTTON].button },
733 { "Options", 1036, 780, 744, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][OPTIONS_BUTTON].button },
734 { "Accept", 1035, 917, 672, UI_XSTR_COLOR_PINK, -1, &Buttons[1][ACCEPT_BUTTON].button },
740 char Debrief_current_callsign[CALLSIGN_LEN+10];
741 player *Debrief_player;
743 static UI_WINDOW Debrief_ui_window;
744 static UI_BUTTON List_region;
745 static int Background_bitmap; // bitmap for the background of the debriefing
746 static int Award_bg_bitmap;
747 static int Debrief_multi_loading_bitmap;
748 static int Rank_bitmap;
749 static int Medal_bitmap;
750 static int Badge_bitmap;
751 static int Wings_bitmap;
752 static int Crest_bitmap;
754 static int Rank_text_bitmap;
755 static int Medal_text_bitmap;
756 static int Badge_text_bitmap;
759 static int Debrief_accepted;
760 static int Turned_traitor;
761 static int Must_replay_mission;
763 static int Current_mode;
765 static int Recommend_active;
766 static int Award_active;
767 static int Text_offset;
768 static int Num_text_lines = 0;
769 static int Num_debrief_lines = 0;
770 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
771 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
773 static int Debrief_inited = 0;
774 static int New_stage;
775 static int Current_stage;
776 static int Num_stages = 0;
777 static int Num_debrief_stages = 0;
778 static int Stage_voice = -1;
780 static int Multi_list_size;
781 static int Multi_list_offset;
783 int Debrief_multi_stages_loaded = 0;
784 int Debrief_multi_voice_loaded = 0;
786 // static int Debrief_voice_ask_for_cd;
788 // voice id's for debriefing text
789 static int Debrief_voices[MAX_DEBRIEF_STAGES];
791 #define DEBRIEF_VOICE_DELAY 400 // time to delay voice playback when a new stage starts
792 static int Debrief_cue_voice; // timestamp to cue the playback of the voice
793 static int Debrief_first_voice_flag = 1; // used to delay the first voice playback extra long
795 // pointer used for getting to debriefing information
796 debriefing Traitor_debriefing; // used when player is a traitor
798 // pointers to the active stages for this debriefing
799 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
800 static debrief_stage Promotion_stage, Badge_stage;
801 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
802 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
803 int Multi_list_select;
805 // flag indicating if we should display info for the given player (in multiplayer)
806 int Debrief_should_show_popup = 1;
808 // already shown skip mission popup?
809 static int Debrief_skip_popup_already_shown = 0;
811 void debrief_text_init();
812 void debrief_accept(int ok_to_post_start_game_event = 1);
813 void debrief_kick_selected_player();
816 // promotion voice selection stuff
817 #define NUM_VOLITION_CAMPAIGNS 1
819 char campaign_name[32];
823 v_campaign Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
825 BUILTIN_CAMPAIGN, // the only campaign for now, but this leaves room for a mission pack
826 35 // make sure this is equal to the number of missions you gave in the corresponding Debrief_promotion_voice_mapping
830 // data for which voice goes w/ which mission
831 typedef struct voice_map {
832 char mission_file[32];
836 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
837 { // FreeSpace2 campaign
869 { "SM3-10.fs2", 9 }, // no debriefing for 3-10
871 { "loop1-1.fs2", 4 },
872 { "loop1-2.fs2", 4 },
873 { "loop1-3.fs2", 5 },
874 { "loop2-1.fs2", 4 },
880 #define DB_AWARD_WINGS 0
881 #define DB_AWARD_MEDAL 1
883 #define DB_AWARD_RANK 2
884 #define DB_AWARD_BADGE 3
885 #define DB_AWARD_BG 4
886 static const char* Debrief_award_filename[GR_NUM_RESOLUTIONS][5] = {
903 #define DB_AWARD_SOC 2
904 #define DB_AWARD_RANK 3
905 #define DB_AWARD_BADGE 4
906 #define DB_AWARD_BG 5
907 static const char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
927 #define AWARD_TEXT_MAX_LINES 5
928 #define AWARD_TEXT_MAX_LINE_LENGTH 128
929 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
930 int Debrief_award_text_num_lines = 0;
934 // prototypes, you know you love 'em
935 void debrief_add_award_text(char *str);
936 void debrief_award_text_clear();
941 const char *debrief_tooltip_handler(const char *str)
943 if (!SDL_strcasecmp(str, NOX("@.Medal"))) {
945 return XSTR( "Medal", 435);
948 } else if (!SDL_strcasecmp(str, NOX("@.Rank"))) {
950 return XSTR( "Rank", 436);
953 } else if (!SDL_strcasecmp(str, NOX("@.Badge"))) {
955 return XSTR( "Badge", 437);
958 } else if (!SDL_strcasecmp(str, NOX("@Medal"))) {
959 if (Medal_bitmap >= 0){
960 return Medals[Player->stats.m_medal_earned].name;
963 } else if (!SDL_strcasecmp(str, NOX("@Rank"))) {
964 if (Rank_bitmap >= 0){
965 return Ranks[Promoted].name;
968 } else if (!SDL_strcasecmp(str, NOX("@Badge"))) {
969 if (Badge_bitmap >= 0){
970 return Medals[Badge_index[Player->stats.m_badge_earned]].name;
977 // initialize the array of handles to the different voice streams
978 void debrief_voice_init()
982 for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
983 Debrief_voices[i] = -1;
987 void debrief_load_voice_file(int voice_num, char *name)
989 int load_attempts = 0;
992 if ( load_attempts++ > 5 ) {
996 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
997 if ( Debrief_voices[voice_num] >= 0 ) {
1001 // Don't bother to ask for the CD in multiplayer
1002 if ( Game_mode & GM_MULTIPLAYER ) {
1006 // couldn't load voice, ask user to insert CD (if necessary)
1008 // if ( Debrief_voice_ask_for_cd ) {
1009 // if ( game_do_cd_check() == 0 ) {
1010 // Debrief_voice_ask_for_cd = 0;
1017 // open and pre-load the stream buffers for the different voice streams
1018 void debrief_voice_load_all()
1022 // Debrief_voice_ask_for_cd = 1;
1024 for ( i=0; i<Num_debrief_stages; i++ ) {
1025 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
1028 if ( SDL_strncasecmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
1029 debrief_load_voice_file(i, Debrief_stages[i]->voice);
1030 // Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
1035 // close all the briefing voice streams
1036 void debrief_voice_unload_all()
1040 for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
1041 if ( Debrief_voices[i] != -1 ) {
1042 audiostream_close_file(Debrief_voices[i], 0);
1043 Debrief_voices[i] = -1;
1048 // start playback of the voice for a particular briefing stage
1049 void debrief_voice_play()
1051 if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
1055 // no more stages? We are done then.
1056 if (Stage_voice >= Num_debrief_stages){
1060 // if in delayed start, see if delay has elapsed and start voice if so
1061 if (Debrief_cue_voice) {
1062 if (!timestamp_elapsed(Debrief_cue_voice)){
1066 Stage_voice++; // move up to next voice
1067 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
1068 audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
1069 Debrief_cue_voice = 0; // indicate no longer in delayed start checking
1075 // see if voice is still playing. If so, do nothing yet.
1076 if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
1080 // set voice to play in a little while from now.
1081 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
1084 // stop playback of the voice for a particular briefing stage
1085 void debrief_voice_stop()
1087 if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
1090 audiostream_stop(Debrief_voices[Stage_voice]); // stream is automatically rewound
1094 // function to deal with inserting possible promition and badge stages into the debriefing
1096 void debrief_multi_fixup_stages()
1100 // possibly insert the badge stage first, them the promotion stage since they are
1101 // inserted at the front of the debrief stages.
1102 if ( Badge_bitmap >= 0 ) {
1103 // move all stages forward one. Don't
1104 for ( i = Num_debrief_stages; i > 0; i-- ) {
1105 Debrief_stages[i] = Debrief_stages[i-1];
1107 Debrief_stages[0] = &Badge_stage;
1108 Num_debrief_stages++;
1111 if ( Promoted >= 0) {
1112 // move all stages forward one
1113 for ( i = Num_debrief_stages; i > 0; i-- ) {
1114 Debrief_stages[i] = Debrief_stages[i-1];
1116 Debrief_stages[0] = &Promotion_stage;
1117 Num_debrief_stages++;
1122 // function called from multiplayer clients to set up the debriefing information for them
1123 // (sent from the server).
1124 void debrief_set_multi_clients( int stage_count, int active_stages[] )
1128 // set up the right briefing for this guy
1129 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
1130 Debriefing = &Debriefings[Net_player->p_info.team];
1132 Debriefing = &Debriefings[0];
1135 // see if this client was promoted -- if so, then add the first stage.
1136 Num_debrief_stages = 0;
1138 // set the pointers to the debriefings for this client
1139 for (i = 0; i < stage_count; i++) {
1140 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
1143 Debrief_multi_stages_loaded = 1;
1146 // evaluate all stages for all teams. Server of a multiplayer game will have to send that
1147 // information to all clients after leaving this screen.
1148 void debrief_multi_server_stuff()
1150 debriefing *debriefp;
1152 int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1153 int i, j, num_stages, stage_count[MAX_TEAMS];
1155 memset( stage_active, 0, sizeof(stage_active) );
1157 for (i=0; i<Num_teams; i++) {
1158 debriefp = &Debriefings[i];
1160 stages[i] = stage_active[i];
1161 for (j=0; j<debriefp->num_stages; j++) {
1162 if ( eval_sexp(debriefp->stages[j].formula) ) {
1163 stage_active[i][num_stages] = j;
1168 stage_count[i] = num_stages;
1171 // if we're in campaign mode, evaluate campaign stuff
1172 if (Netgame.campaign_mode == MP_CAMPAIGN) {
1173 multi_campaign_eval_debrief();
1176 // send the information to all clients.
1177 send_debrief_info( stage_count, stages );
1181 // --------------------------------------------------------------------------------------
1182 // debrief_set_stages_and_multi_stuff()
1184 // Set up the active stages for this debriefing
1186 // returns: number of active debriefing stages
1188 int debrief_set_stages_and_multi_stuff()
1191 debriefing *debriefp;
1193 if ( MULTIPLAYER_CLIENT ) {
1197 Num_debrief_stages = 0;
1199 if ( Game_mode & GM_MULTIPLAYER ) {
1200 debrief_multi_server_stuff();
1203 // check to see if player is a traitor (looking at his team). If so, use the special
1204 // traitor debriefing. Only done in single player
1205 debriefp = Debriefing;
1206 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1207 if (Player_ship->team == TEAM_TRAITOR)
1208 debriefp = &Traitor_debriefing;
1211 Num_debrief_stages = 0;
1212 if (Promoted >= 0) {
1213 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1216 if (Badge_bitmap >= 0) {
1217 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1220 for (i=0; i<debriefp->num_stages; i++) {
1221 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1222 Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1226 return Num_debrief_stages;
1229 // init the buttons that are specific to the debriefing screen
1230 void debrief_buttons_init()
1235 for ( i=0; i<NUM_BUTTONS; i++ ) {
1236 b = &Buttons[gr_screen.res][i];
1237 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1238 // set up callback for when a mouse first goes over a button
1239 b->button.set_highlight_action( common_play_highlight_sound );
1240 b->button.set_bmaps(b->filename);
1241 b->button.link_hotspot(b->hotspot);
1246 for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1247 // multiplayer specific text
1248 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1249 // only add if in multiplayer mode
1250 if(Game_mode & GM_MULTIPLAYER){
1251 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1256 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1261 // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1262 Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(SDLK_RIGHT);
1263 Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(SDLK_LEFT);
1264 Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | SDLK_RIGHT);
1265 Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | SDLK_LEFT);
1266 Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(SDLK_UP);
1267 Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(SDLK_DOWN);
1268 Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+SDLK_RETURN);
1270 // if in multiplayer, disable the button for all players except the host
1271 // also disable for squad war matches
1272 if(Game_mode & GM_MULTIPLAYER){
1273 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1274 Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1279 // --------------------------------------------------------------------------------------
1280 // debrief_ui_init()
1282 void debrief_ui_init()
1284 // init ship selection masks and buttons
1285 common_set_interface_palette("DebriefPalette"); // set the interface palette
1286 Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1287 Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1288 Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1289 debrief_buttons_init();
1291 // load in help overlay bitmap
1292 help_overlay_load(DEBRIEFING_OVERLAY);
1293 help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1295 if ( Game_mode & GM_MULTIPLAYER ) {
1296 // close down any old instances of the chatbox
1299 // create the new one
1301 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1302 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);
1305 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1308 if ( Background_bitmap < 0 ) {
1309 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1312 Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1313 Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1316 // sets Promotion_stage.voice
1317 // defaults to number 9 (Petrarch) for non-volition missions
1318 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1319 void debrief_choose_promotion_voice()
1321 if(Campaign.current_mission < 0){
1323 SDL_snprintf(Promotion_stage.voice, SDL_arraysize(Promotion_stage.voice), NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1325 SDL_snprintf(Promotion_stage.voice, SDL_arraysize(Promotion_stage.voice), NOX("1_%s"), Ranks[Promoted].promotion_voice_base);
1330 // search thru all official campaigns for our current campaign
1331 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename[0])) {
1333 if (Player->on_bastion) {
1334 SDL_snprintf(Promotion_stage.voice, SDL_arraysize(Promotion_stage.voice), NOX("3_%s"), Ranks[Promoted].promotion_voice_base);
1336 SDL_snprintf(Promotion_stage.voice, SDL_arraysize(Promotion_stage.voice), NOX("1_%s"), Ranks[Promoted].promotion_voice_base);
1341 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1342 if ((Campaign.filename[0]) && !SDL_strcasecmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1343 // now search thru the mission filenames,
1344 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1345 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !SDL_strcasecmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1346 // found it! set the persona and bail
1347 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);
1357 // default to petrarch
1358 SDL_snprintf(Promotion_stage.voice, SDL_arraysize(Promotion_stage.voice), NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1360 // default to FS1 guy
1361 SDL_snprintf(Promotion_stage.voice, SDL_arraysize(Promotion_stage.voice), NOX("1_%s"), Ranks[Promoted].promotion_voice_base);
1365 // sets Promotion_stage.voice
1366 // defaults to number 9 (Petrarch) for non-volition missions
1367 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1368 void debrief_choose_badge_voice()
1370 if(Campaign.current_mission < 0){
1372 // default to petrarch
1373 SDL_snprintf(Badge_stage.voice, SDL_arraysize(Badge_stage.voice), NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1375 // default to FS1 guy
1376 SDL_snprintf(Badge_stage.voice, SDL_arraysize(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1381 if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename[0])) {
1383 if ( Player->on_bastion ) {
1384 SDL_snprintf(Badge_stage.voice, SDL_arraysize(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base2);
1387 SDL_snprintf(Badge_stage.voice, SDL_arraysize(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1393 // search thru all official campaigns for our current campaign
1394 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1395 if ((Campaign.filename[0]) && !SDL_strcasecmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {
1396 // now search thru the mission filenames,
1397 for (j=0; j<Campaign.num_missions; j++) {
1398 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !SDL_strcasecmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1399 // found it! set the persona and bail
1400 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);
1410 // default to petrarch
1411 SDL_snprintf(Badge_stage.voice, SDL_arraysize(Badge_stage.voice), NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1413 // default to FS1 guy
1414 SDL_snprintf(Badge_stage.voice, SDL_arraysize(Badge_stage.voice), NOX("%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1419 void debrief_award_init()
1431 // be sure there are no old award texts floating around
1433 debrief_award_text_clear();
1436 // handle medal earned
1437 if (Player->stats.m_medal_earned != -1) {
1438 if (Player->stats.m_medal_earned == 13) { // special hack for the wings..
1440 if ( Player->stats.medals[13] > 1 ) {
1445 SDL_snprintf(buf, SDL_arraysize(buf), NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);
1446 Wings_bitmap = bm_load(buf);
1448 } else if (Player->stats.m_medal_earned == 17) { // special hack for the soc crest
1449 Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1452 SDL_snprintf(buf, SDL_arraysize(buf), NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1453 Medal_bitmap = bm_load(buf);
1457 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1461 // handle promotions
1462 if ( Player->stats.m_promotion_earned != -1 ) {
1463 Promoted = Player->stats.m_promotion_earned;
1464 SDL_snprintf(buf, SDL_arraysize(buf), NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1465 Rank_bitmap = bm_load(buf);
1467 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1468 Promotion_stage.new_recommendation_text = NULL;
1470 // choose appropriate promotion voice for this mission
1471 debrief_choose_promotion_voice();
1474 debrief_add_award_text(Ranks[Promoted].name);
1478 // handle badge earned
1479 // only grant badge if earned and allowed. (no_promotion really means no promotion and no badges)
1480 if ( Player->stats.m_badge_earned != -1 ) {
1481 i = Player->stats.m_badge_earned;
1482 SDL_snprintf(buf, SDL_arraysize(buf), NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1483 Badge_bitmap = bm_load(buf);
1485 Badge_stage.new_text = Badge_info[i].promotion_text;
1486 Badge_stage.new_recommendation_text = NULL;
1488 // choose appropriate voice
1489 debrief_choose_badge_voice();
1492 debrief_add_award_text(Medals[Badge_index[i]].name);
1496 if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1503 // debrief_traitor_init() initializes local data which could be used if the player leaves the
1504 // mission a traitor. The same debriefing always gets played
1505 void debrief_traitor_init()
1507 static int inited = 0;
1510 debriefing *debrief;
1511 debrief_stage *stagep;
1514 // open localization
1518 read_file_text("traitor.tbl");
1521 // simplied form of the debriefing stuff.
1522 debrief = &Traitor_debriefing;
1523 required_string("#Debriefing_info");
1525 required_string("$Num stages:");
1526 stuff_int(&debrief->num_stages);
1527 SDL_assert(debrief->num_stages == 1);
1530 stagep = &debrief->stages[stage_num++];
1531 required_string("$Formula:");
1532 stagep->formula = get_sexp_main();
1533 required_string("$multi text");
1534 if ( Fred_running ) {
1535 stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1537 stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1539 required_string("$Voice:");
1540 char traitor_voice_file[NAME_LENGTH];
1541 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1543 // DKA 9/13/99 Only 1 traitor msg for FS2
1545 if ( Player->on_bastion ) {
1546 SDL_strlcpy(stagep->voice, NOX("3_"), SDL_arraysize(stagep->voice));
1548 SDL_strlcpy(stagep->voice, NOX("1_"), SDL_arraysize(stagep->voice));
1552 SDL_strlcat(stagep->voice, traitor_voice_file, SDL_arraysize(stagep->voice));
1554 required_string("$Recommendation text:");
1555 if ( Fred_running ) {
1556 stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1558 stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1562 } catch (parse_error_t rval) {
1563 Error(LOCATION, "Unable to parse traitor.tbl! Code = %i.\n", (int)rval);
1566 // close localization
1570 // disable the accept button if in single player and I am a traitor
1571 Debrief_accepted = 0;
1572 Turned_traitor = Must_replay_mission = 0;
1573 if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1574 if (Player_ship->team == TEAM_TRAITOR){
1578 if (Campaign.next_mission == Campaign.current_mission){
1579 Must_replay_mission = 1;
1583 if (Turned_traitor || Must_replay_mission) {
1584 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1586 // kill off any stats
1587 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1588 scoring_level_init( &Player->stats );
1592 // initialization for listing of players in game
1593 void debrief_multi_list_init()
1595 Multi_list_size = 0; // number of net players to choose from
1596 Multi_list_offset = 0;
1598 Multi_list_select = -1;
1600 if ( !(Game_mode & GM_MULTIPLAYER) )
1603 debrief_rebuild_player_list();
1605 // switch stats display to this newly selected player
1606 set_player_stats(Multi_list[0].net_player_index);
1607 SDL_strlcpy(Debrief_current_callsign, Multi_list[0].callsign, SDL_arraysize(Debrief_current_callsign));
1608 Debrief_player = Player;
1611 void debrief_multi_list_scroll_up()
1613 // if we're at the beginning of the list, don't do anything
1614 if(Multi_list_offset == 0){
1615 gamesnd_play_iface(SND_GENERAL_FAIL);
1619 // otherwise scroll up
1620 Multi_list_offset--;
1621 gamesnd_play_iface(SND_USER_SELECT);
1624 void debrief_multi_list_scroll_down()
1626 // if we can scroll down no further
1627 if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1628 gamesnd_play_iface(SND_GENERAL_FAIL);
1631 if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1632 gamesnd_play_iface(SND_GENERAL_FAIL);
1636 // otherwise scroll down
1637 Multi_list_offset++;
1638 gamesnd_play_iface(SND_USER_SELECT);
1641 // draw the connected net players
1642 void debrief_multi_list_draw()
1644 int y, z, font_height,idx;
1645 char str[CALLSIGN_LEN+5];
1648 font_height = gr_get_font_height();
1650 // if we currently have no item picked, pick a reasonable one
1651 if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1652 // select the entry which corresponds to the local player
1653 Multi_list_select = 0;
1654 for(idx=0;idx<Multi_list_size;idx++){
1655 if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1656 Multi_list_select = idx;
1658 // switch stats display to this newly selected player
1659 set_player_stats(Multi_list[idx].net_player_index);
1660 SDL_strlcpy(Debrief_current_callsign, Multi_list[idx].callsign, SDL_arraysize(Debrief_current_callsign));
1661 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;
1667 // draw the list itself
1669 z = Multi_list_offset;
1670 while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1671 np = &Net_players[Multi_list[z].net_player_index];
1673 if (z >= Multi_list_size){
1676 // set the proper text color for the highlight
1677 if(np->flags & NETINFO_FLAG_GAME_HOST){
1678 if(Multi_list_select == z){
1679 gr_set_color_fast(&Color_text_active_hi);
1681 gr_set_color_fast(&Color_bright);
1684 if(Multi_list_select == z){
1685 gr_set_color_fast(&Color_text_active);
1687 gr_set_color_fast(&Color_text_normal);
1691 // blit the proper indicator - skipping observers
1692 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1693 if(Netgame.type_flags & NG_TYPE_TEAM){
1695 if(np->p_info.team == 0){
1696 // draw his "selected" icon
1697 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1698 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1699 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1701 // draw his "normal" icon
1702 else if(Multi_common_icons[MICON_TEAM0] != -1){
1703 gr_set_bitmap(Multi_common_icons[MICON_TEAM0], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1704 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1706 } else if(np->p_info.team == 1){
1707 // draw his "selected" icon
1708 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){
1709 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1710 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1712 // draw his "normal" icon
1713 else if(Multi_common_icons[MICON_TEAM1] != -1){
1714 gr_set_bitmap(Multi_common_icons[MICON_TEAM1], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1715 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1719 // draw the team 0 selected icon
1720 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1721 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1722 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1727 SDL_strlcpy(str, Multi_list[z].callsign, SDL_arraysize(str));
1728 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)){
1729 SDL_strlcat(str, XSTR( "(O)", 438), SDL_arraysize(str));
1733 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1740 void debrief_kick_selected_player()
1742 if(Multi_list_select >= 0){
1743 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1744 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1748 // get optional mission popup text
1749 void debrief_assemble_optional_mission_popup_text(char *buffer, const int buf_len, char *mission_loop_desc)
1751 SDL_assert(buffer != NULL);
1754 if (mission_loop_desc == NULL) {
1755 SDL_strlcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490), buf_len);
1756 mprintf(("No mission loop description avail"));
1758 SDL_strlcpy(buffer, mission_loop_desc, buf_len);
1761 SDL_strlcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491), buf_len);
1764 static void debrief_accept_callback(int choice)
1769 // do nothing, will return to debrief
1770 } else if (choice == 1) {
1771 // return to main hall, tossing stats
1772 gameseq_post_event(GS_EVENT_END_GAME);
1773 } else if (choice == 2) {
1774 // replay mission (cycle back to briefing)
1775 gameseq_post_event(GS_EVENT_START_BRIEFING);
1779 // what to do when the accept button is hit
1780 void debrief_accept(int ok_to_post_start_game_event)
1784 if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1787 if (Game_mode & GM_MULTIPLAYER) {
1791 if (Player_ship->team == TEAM_TRAITOR){
1792 str = XSTR( "Your career is over, Traitor! You can't accept new missions!", 439);
1793 }/* else if (Cheats_enabled) {
1794 str = XSTR( "You are a cheater. You cannot accept this mission!", 440);
1796 str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441);
1799 popup_callback(debrief_accept_callback, 0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1804 Debrief_accepted = 1;
1805 // save mission stats
1806 if (Game_mode & GM_MULTIPLAYER) {
1807 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1808 // as well as doing stats transfers, etc.
1809 multi_debrief_accept_hit();
1813 int play_commit_sound = 1;
1814 // only write the player's stats if he's accepted
1816 // if we are just playing a single mission, then don't do many of the things
1817 // that need to be done. Nothing much should happen when just playing a single
1818 // mission that isn't in a campaign.
1819 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1821 // check for possible mission loop
1822 // check for (1) mission loop available, (2) dont have to repeat last mission
1823 if(!(Game_mode & GM_MULTIPLAYER)){
1824 int cur = Campaign.current_mission;
1825 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1826 if (Campaign.missions[cur].has_mission_loop) {
1827 SDL_assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1830 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1833 debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1835 int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1837 Campaign.loop_enabled = 1;
1838 Campaign.next_mission = Campaign.loop_mission;
1847 if(ok_to_post_start_game_event){
1848 gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1850 play_commit_sound = 0;
1853 // continue as normal
1856 // if single player campagin, maybe mark shivans as visible in
1857 // tech room at completion of mission 5
1858 if ( !(Game_mode & GM_MULTIPLAYER) && (Intel_info[2].in_tech_db == 0) ) {
1859 char *m_name = Campaign.missions[Campaign.current_mission].name;
1861 if ( m_name && !SDL_strcasecmp(m_name, "sm1-05a.fsm") ) {
1862 Intel_info[2].in_tech_db = 1;
1868 mission_campaign_mission_over();
1870 // check to see if we are out of the loop now
1871 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1872 Campaign.loop_enabled = 0;
1875 // check if campaign is over
1876 if ( Campaign.next_mission == -1 ) {
1877 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
1878 gameseq_post_event(GS_EVENT_END_DEMO);
1880 gameseq_post_event(GS_EVENT_MAIN_MENU);
1883 if ( ok_to_post_start_game_event ) {
1884 gameseq_post_event(GS_EVENT_START_GAME);
1886 play_commit_sound = 0;
1891 gameseq_post_event(GS_EVENT_MAIN_MENU);
1894 if ( play_commit_sound ) {
1895 gamesnd_play_iface(SND_COMMIT_PRESSED);
1902 void debrief_next_tab()
1904 New_mode = Current_mode + 1;
1905 if (New_mode >= NUM_TABS)
1909 void debrief_prev_tab()
1911 New_mode = Current_mode - 1;
1913 New_mode = NUM_TABS - 1;
1916 // --------------------------------------------------------------------------------------
1917 // debrief_next_stage()
1919 void debrief_next_stage()
1921 if (Current_stage < Num_stages - 1) {
1922 New_stage = Current_stage + 1;
1923 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1926 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1929 // --------------------------------------------------------------------------------------
1930 // debrief_prev_stage()
1932 void debrief_prev_stage()
1934 if (Current_stage) {
1935 New_stage = Current_stage - 1;
1936 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1939 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1942 // --------------------------------------------------------------------------------------
1943 // debrief_first_stage()
1944 void debrief_first_stage()
1946 if (Current_stage) {
1948 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1951 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1954 // --------------------------------------------------------------------------------------
1955 // debrief_last_stage()
1956 void debrief_last_stage()
1958 if (Current_stage != Num_stages - 1) {
1959 New_stage = Num_stages - 1;
1960 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1963 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1966 // draw what stage number the debriefing is on
1967 void debrief_render_stagenum()
1975 SDL_snprintf(buf, SDL_arraysize(buf), XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1976 gr_get_string_size(&w, NULL, buf);
1977 gr_set_color_fast(&Color_bright_blue);
1978 gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1979 gr_set_color_fast(&Color_white);
1982 // render the mission time at the specified y location
1983 void debrief_render_mission_time(int y_loc)
1987 game_format_time(Missiontime, time_str, SDL_arraysize(time_str));
1988 gr_string(0, y_loc, XSTR( "Mission Time", 446));
1989 gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);
1992 // render out the debriefing text to the scroll window
1993 void debrief_render()
1995 int y, z, font_height;
1997 if ( Num_stages <= 0 )
2000 font_height = gr_get_font_height();
2002 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]);
2005 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
2006 if (z >= Num_text_lines)
2009 if (Text_type[z] == TEXT_TYPE_NORMAL)
2010 gr_set_color_fast(&Color_white);
2012 gr_set_color_fast(&Color_bright_red);
2015 gr_string(0, y, Text[z]);
2024 // render out the stats info to the scroll window
2026 void debrief_stats_render()
2028 int i, y, font_height;
2030 gr_set_color_fast(&Color_blue);
2031 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]);
2032 gr_string(0, 0, Debrief_current_callsign);
2033 font_height = gr_get_font_height();
2036 switch ( Current_stage ) {
2037 case DEBRIEF_MISSION_STATS:
2038 i = Current_stage - 1;
2042 gr_set_color_fast(&Color_white);
2044 // display mission completion time
2045 debrief_render_mission_time(y);
2048 show_stats_label(i, 0, y, font_height);
2049 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2051 case DEBRIEF_ALLTIME_STATS:
2052 i = Current_stage - 1;
2056 gr_set_color_fast(&Color_white);
2057 show_stats_label(i, 0, y, font_height);
2058 show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
2061 case DEBRIEF_ALLTIME_KILLS:
2062 case DEBRIEF_MISSION_KILLS:
2063 gr_set_color_fast(&Color_white);
2065 while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
2066 if (i >= Num_text_lines)
2070 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2071 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
2073 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
2076 gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
2077 gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
2084 if (Num_text_lines == 2) {
2085 if ( Current_stage == DEBRIEF_MISSION_KILLS )
2086 gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
2088 gr_printf(0, y, XSTR( "(No ship kills)", 450));
2101 static void debrief_replay_callback(int choice)
2107 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
2108 gamesnd_play_iface(SND_COMMIT_PRESSED);
2112 // do action for when the replay button is pressed
2113 void debrief_replay_pressed()
2115 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2116 popup_callback(debrief_replay_callback, 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));
2118 // the callback will handle replay
2122 gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing
2123 gamesnd_play_iface(SND_COMMIT_PRESSED);
2126 // -------------------------------------------------------------------
2127 // debrief_redraw_pressed_buttons()
2129 // Redraw any debriefing buttons that are pressed down. This function is needed
2130 // since we sometimes need to draw pressed buttons last to ensure the entire
2131 // button gets drawn (and not overlapped by other buttons)
2133 void debrief_redraw_pressed_buttons()
2138 for ( i=0; i<NUM_BUTTONS; i++ ) {
2139 b = &Buttons[gr_screen.res][i].button;
2140 // don't draw the recommendations button if we're in stats mode
2141 if ( b->button_down() ) {
2147 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
2149 void debrief_button_pressed(int num)
2153 Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();
2154 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
2155 if (num != Current_mode){
2156 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2161 // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1; // allows failure sound to be played
2162 Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();
2163 if (num != Current_mode){
2164 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
2169 case TEXT_SCROLL_UP:
2172 gamesnd_play_iface(SND_SCROLL);
2174 gamesnd_play_iface(SND_GENERAL_FAIL);
2178 case TEXT_SCROLL_DOWN:
2179 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2181 gamesnd_play_iface(SND_SCROLL);
2183 gamesnd_play_iface(SND_GENERAL_FAIL);
2187 case REPLAY_MISSION:
2188 if(Game_mode & GM_MULTIPLAYER){
2189 multi_debrief_replay_hit();
2191 debrief_replay_pressed();
2195 case RECOMMENDATIONS:
2196 gamesnd_play_iface(SND_USER_SELECT);
2197 Recommend_active = !Recommend_active;
2198 debrief_text_init();
2202 debrief_first_stage();
2206 debrief_prev_stage();
2210 debrief_next_stage();
2214 debrief_last_stage();
2218 gamesnd_play_iface(SND_HELP_PRESSED);
2219 launch_context_help();
2222 case OPTIONS_BUTTON:
2223 gamesnd_play_iface(SND_SWITCH_SCREENS);
2224 gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2232 gamesnd_play_iface(SND_SWITCH_SCREENS);
2233 gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2236 case PLAYER_SCROLL_UP:
2237 debrief_multi_list_scroll_up();
2240 case PLAYER_SCROLL_DOWN:
2241 debrief_multi_list_scroll_down();
2244 case MULTI_PINFO_POPUP:
2245 Debrief_should_show_popup = 1;
2249 debrief_kick_selected_player();
2254 void debrief_setup_ship_kill_stats(int stage_num)
2262 debrief_stats_kill_info *kill_info;
2264 SDL_assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2265 if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2268 SDL_assert(Debrief_player != NULL);
2270 // kill_ar points to an array of MAX_SHIP_TYPE ints
2271 if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2272 kill_arr = Debrief_player->stats.m_okKills;
2274 kill_arr = Debrief_player->stats.kills;
2278 for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2280 // code used to add in mission kills, but the new system assumes that the player will accept, so
2281 // all time stats already have mission stats added in.
2282 if ( kill_arr[i] <= 0 ){
2287 kill_info = &Debrief_stats_kills[Num_text_lines++];
2289 kill_info->num = kill_arr[i];
2291 SDL_strlcpy(kill_info->text, Ship_info[i].name, SDL_arraysize(kill_info->text));
2292 SDL_strlcat(kill_info->text, NOX(":"), SDL_arraysize(kill_info->text));
2295 Num_text_lines += 2;
2298 // Iterate through the debriefing buttons, checking if they are pressed
2299 void debrief_check_buttons()
2303 for ( i=0; i<NUM_BUTTONS; i++ ) {
2304 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2305 debrief_button_pressed(i);
2309 if ( !(Game_mode & GM_MULTIPLAYER) )
2312 if (List_region.pressed()) {
2313 List_region.get_mouse_pos(NULL, &y);
2314 z = Multi_list_offset + y / gr_get_font_height();
2315 if ((z >= 0) && (z < Multi_list_size)) {
2316 // switch stats display to this newly selected player
2317 set_player_stats(Multi_list[z].net_player_index);
2318 SDL_strlcpy(Debrief_current_callsign, Multi_list[z].callsign, SDL_arraysize(Debrief_current_callsign));
2319 Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2320 Multi_list_select = z;
2321 debrief_setup_ship_kill_stats(Current_stage);
2322 gamesnd_play_iface(SND_USER_SELECT);
2326 // if the player was double clicked on - we should popup a player info popup
2328 if (List_region.double_clicked()) {
2329 Debrief_should_show_popup = 1;
2334 void debrief_text_stage_init(const char *src, int type)
2336 int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2337 char line[MAX_DEBRIEF_LINE_LEN];
2338 char *p_str[MAX_DEBRIEF_LINES];
2341 n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2342 SDL_assert(n_lines >= 0);
2344 // if you hit this, you proba
2345 if(n_lines >= MAX_DEBRIEF_LINES){
2346 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");
2349 for ( i=0; i<n_lines; i++ ) {
2350 SDL_assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2351 SDL_assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2352 len = SDL_min(n_chars[i] + 1, MAX_DEBRIEF_LINE_LEN);
2353 SDL_strlcpy(line, p_str[i], len);
2354 line[n_chars[i]] = 0;
2355 drop_white_space(line);
2356 Text_type[Num_text_lines] = type;
2357 Text[Num_text_lines++] = strdup(line);
2363 void debrief_free_text()
2367 for (i=0; i<Num_debrief_lines; i++)
2371 Num_debrief_lines = 0;
2374 // setup the debriefing text lines for rendering
2375 void debrief_text_init()
2380 // release old text lines first
2381 debrief_free_text();
2382 Num_text_lines = Text_offset = 0;
2384 if (Current_mode == DEBRIEF_TAB) {
2385 for (i=0; i<Num_debrief_stages; i++) {
2387 Text[Num_text_lines++] = NULL; // add a blank line between stages
2389 src = Debrief_stages[i]->new_text;
2391 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2393 if (Recommend_active) {
2394 src = Debrief_stages[i]->new_recommendation_text;
2395 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2396 src = XSTR( "We have no recommendations for you.", 1054);
2399 Text[Num_text_lines++] = NULL;
2400 debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2406 Num_debrief_lines = Num_text_lines;
2410 // not in debriefing mode, must be in stats mode
2412 debrief_setup_ship_kill_stats(Current_stage);
2416 // --------------------------------------------------------------------------------------
2420 SDL_assert(!Debrief_inited);
2421 // Campaign.loop_enabled = 0;
2422 Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2424 // set up the right briefing for this guy
2425 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2426 Debriefing = &Debriefings[Net_player->p_info.team];
2428 Debriefing = &Debriefings[0];
2431 // no longer is mission
2432 Game_mode &= ~(GM_IN_MISSION);
2436 New_mode = DEBRIEF_TAB;
2437 Recommend_active = Award_active = 0;
2442 Debrief_cue_voice = 0;
2443 Num_text_lines = Num_debrief_lines = 0;
2444 Debrief_first_voice_flag = 1;
2446 Debrief_multi_voice_loaded = 0;
2449 Medal_text_bitmap = bm_load(NOX("DebriefText01"));
2450 Rank_text_bitmap = bm_load(NOX("DebriefText02"));
2451 Badge_text_bitmap = bm_load(NOX("DebriefText03"));
2454 if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT ) ) {
2455 // MUST store goals and events first - may be used to evaluate next mission
2456 // store goals and events
2457 mission_campaign_store_goals_and_events();
2459 // evaluate next mission
2460 mission_campaign_eval_next_mission();
2463 // call traitor init before calling scoring_level_close. traitor init will essentially nullify
2465 if ( !(Game_mode & GM_MULTIPLAYER) ) { // only do for single player
2466 debrief_traitor_init(); // initialize data needed if player becomes traitor.
2469 // call scoring level close for my stats. Needed for award_init. The stats will
2470 // be backed out if used chooses to replace them.
2471 scoring_level_close();
2473 debrief_ui_init(); // init UI items
2474 debrief_award_init();
2476 debrief_voice_init();
2477 debrief_multi_list_init();
2478 // rank_bitmaps_clear();
2479 // rank_bitmaps_load();
2481 SDL_strlcpy(Debrief_current_callsign, Player->callsign, SDL_arraysize(Debrief_current_callsign));
2482 Debrief_player = Player;
2483 // Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2485 // set up the Debrief_stages[] and Recommendations[] arrays. Only do the following stuff
2486 // for non-clients (i.e. single and game server). Multiplayer clients will get their debriefing
2487 // info directly from the server.
2488 if ( !MULTIPLAYER_CLIENT ) {
2489 debrief_set_stages_and_multi_stuff();
2491 if ( Num_debrief_stages <= 0 ) {
2492 Num_debrief_stages = 0;
2494 debrief_voice_load_all();
2497 // multiplayer client may have already received their debriefing info. If they have not,
2498 // then set the num debrief stages to 0
2499 if ( !Debrief_multi_stages_loaded ) {
2500 Num_debrief_stages = 0;
2505 if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2506 common_music_init(SCORE_DEBRIEF_SUCCESS);
2508 common_music_init(SCORE_DEBRIEF_FAIL);
2512 // start up the appropriate music
2513 if (Campaign.next_mission == Campaign.current_mission) {
2514 // you failed the mission because you suck, so you get the suck music
2515 common_music_init(SCORE_DEBRIEF_FAIL);
2516 } else if (mission_goals_met()) {
2517 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2518 common_music_init(SCORE_DEBRIEF_SUCCESS);
2520 // you somehow passed the mission, so you get a little something for your efforts.
2521 common_music_init(SCORE_DEBRIEF_AVERAGE);
2524 if (Campaign.next_mission == Campaign.current_mission) {
2525 // better luck next time, increase his retries
2526 Player->failures_this_session++;
2528 // clear his retries info regardless of whether or not he accepts
2529 Player->failures_this_session = 0;
2532 if (Game_mode & GM_MULTIPLAYER) {
2533 multi_debrief_init();
2535 // if i'm not the host of the game, disable the multi kick button
2536 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2537 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2540 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2541 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2542 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2543 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2544 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2545 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2546 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();
2547 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2550 if (!Award_active) {
2551 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2552 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2555 Debrief_skip_popup_already_shown = 0;
2560 // --------------------------------------------------------------------------------------
2562 void debrief_close()
2566 SDL_assert(Debrief_inited);
2568 // if the mission wasn't accepted, clear out my stats
2569 // we need to evaluate a little differently for multiplayer since the conditions for "accepting"
2570 // are a little bit different
2571 if (Game_mode & GM_MULTIPLAYER) {
2572 // if stats weren't accepted, backout my own stats
2573 if (multi_debrief_stats_accept_code() != 1) {
2574 if(MULTIPLAYER_MASTER){
2575 for(idx=0; idx<MAX_PLAYERS; idx++){
2576 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2577 scoring_backout_accept(&Net_players[idx].player->stats);
2581 scoring_backout_accept( &Player->stats );
2586 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2587 scoring_backout_accept( &Player->stats );
2591 // if dude passed the misson and accepted, reset his show skip popup flag
2592 if (Debrief_accepted) {
2593 Player->show_skip_popup = 1;
2596 if (Num_debrief_lines) {
2597 for (i=0; i<Num_debrief_lines; i++){
2604 // clear out debrief info parsed from mission file
2605 mission_debrief_common_reset();
2607 // unload the overlay bitmap
2609 help_overlay_unload(DEBRIEFING_OVERLAY);
2612 // clear out award text
2613 Debrief_award_text_num_lines = 0;
2615 debrief_voice_unload_all();
2616 common_music_close();
2619 // rank_bitmaps_release();
2622 if (Background_bitmap >= 0){
2623 bm_unload(Background_bitmap);
2626 if (Award_bg_bitmap >= 0){
2627 bm_unload(Award_bg_bitmap);
2630 if (Rank_bitmap >= 0){
2631 bm_unload(Rank_bitmap);
2634 if (Medal_bitmap >= 0){
2635 bm_unload(Medal_bitmap);
2638 if (Badge_bitmap >= 0){
2639 bm_unload(Badge_bitmap);
2642 if (Wings_bitmap >= 0) {
2643 bm_unload(Wings_bitmap);
2646 if (Crest_bitmap >= 0) {
2647 bm_unload(Crest_bitmap);
2651 if (Medal_text_bitmap >= 0) {
2652 bm_unload(Medal_text_bitmap);
2655 if (Badge_text_bitmap >= 0) {
2656 bm_unload(Badge_text_bitmap);
2659 if (Rank_text_bitmap >= 0) {
2660 bm_unload(Rank_text_bitmap);
2664 Debrief_ui_window.destroy();
2665 common_free_interface_palette(); // restore game palette
2668 if (Game_mode & GM_MULTIPLAYER){
2669 multi_debrief_close();
2679 static void mission_replay_esc_callback(int choice)
2684 // accept and continue
2686 gameseq_post_event(GS_EVENT_MAIN_MENU);
2688 // return to main hall
2689 gameseq_post_event(GS_EVENT_END_GAME);
2693 static void mission_must_replay_callback(int choice)
2698 // return to main hall
2699 gameseq_post_event(GS_EVENT_END_GAME);
2703 // handle keypresses in debriefing
2704 void debrief_do_keys(int new_k)
2711 case KEY_SHIFTED | SDLK_TAB:
2716 // multiplayer accept popup is a little bit different
2717 if (Game_mode & GM_MULTIPLAYER) {
2718 multi_debrief_esc_hit();
2720 // display the normal debrief popup
2722 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2723 int pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2724 popup_callback(mission_replay_esc_callback, pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2726 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2727 // need to popup saying that mission was a failure and must be replayed
2728 popup_callback(mission_must_replay_callback, 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));
2740 void debrief_draw_award_text()
2742 int start_y, curr_y, i, x, sw;
2743 int fh = gr_get_font_height();
2744 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];
2746 // vertically centered within field
2747 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);
2751 for (i=0; i<Debrief_award_text_num_lines; i++) {
2752 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2753 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2754 if (i==AWARD_TEXT_MAX_LINES-1) x += 7; // hack because of the shape of the box
2755 gr_set_color_fast(&Color_white);
2756 gr_string(x, curr_y, Debrief_award_text[i]);
2758 // adjust y pos, including a little extra between the "pairs"
2760 if ((i == 1) || (i == 3)) {
2761 curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2766 // clears out text array so we dont have old award text showing up on new awards.
2767 void debrief_award_text_clear() {
2770 Debrief_award_text_num_lines = 0;
2771 for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2772 //Debrief_award_text[i][0] = 0;
2773 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2777 // this is the nastiest code I have ever written. if you are modifying this, i feel bad for you.
2778 void debrief_add_award_text(char *str)
2780 SDL_assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2781 if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2786 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];
2789 SDL_strlcpy(Debrief_award_text[Debrief_award_text_num_lines], str, AWARD_TEXT_MAX_LINE_LENGTH);
2791 // maybe translate for displaying
2793 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2794 } else if (Lcl_pl) {
2795 medals_translate_name_pl(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2798 Debrief_award_text_num_lines++;
2800 // if its too long, split once ONLY
2801 // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2802 if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2803 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2804 if (line2 != NULL) {
2805 SDL_snprintf(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH, " %s", line2); // indent a space
2807 Debrief_award_text_num_lines++; // leave blank line even if it all fits into 1
2810 #endif // !MAKE_FS1: No text for FS1, it's all bitmaps
2812 static void skip_mission_callback(int choice)
2817 // stay on this mission, so proceed to normal death popup
2818 // in other words, do nothing.
2819 } else if (choice == 1) {
2820 // skip this mission
2821 mission_campaign_skip_to_next();
2822 gameseq_post_event(GS_EVENT_START_GAME);
2823 } else if (choice == 2) {
2824 // don't show this popup again
2825 Player->show_skip_popup = 0;
2829 // called once per frame to drive all the input reading and rendering
2830 void debrief_do_frame(float frametime)
2833 const char *please_wait_str = XSTR("Please Wait", 1242);
2837 SDL_assert(Debrief_inited);
2839 // first thing is to load the files
2840 if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2841 // draw the background, etc
2842 GR_MAYBE_CLEAR_RES(Background_bitmap);
2843 if (Background_bitmap >= 0) {
2844 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2848 Debrief_ui_window.draw();
2850 if ( Debrief_multi_loading_bitmap > -1 ){
2851 gr_set_bitmap(Debrief_multi_loading_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2852 gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2855 // draw "Please Wait"
2856 gr_set_color_fast(&Color_normal);
2858 gr_get_string_size(&str_w, &str_h, please_wait_str);
2859 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2864 // make sure we run the debrief do frame
2865 if (Game_mode & GM_MULTIPLAYER) {
2866 multi_debrief_do_frame();
2871 int keypress = game_check_key();
2872 if(keypress == SDLK_ESCAPE){
2874 multi_quit_game(PROMPT_CLIENT);
2880 // if multiplayer client, and not loaded voice, then load it
2881 if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2882 debrief_multi_fixup_stages();
2883 debrief_voice_load_all();
2884 Debrief_multi_voice_loaded = 1;
2887 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2888 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2889 Debrief_ui_window.set_ignore_gadgets(1);
2892 k = chatbox_process();
2893 if ( Game_mode & GM_NORMAL ) {
2894 new_k = Debrief_ui_window.process(k);
2896 new_k = Debrief_ui_window.process(k, 0);
2899 if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2900 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2901 help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2902 Debrief_ui_window.set_ignore_gadgets(0);
2908 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2909 Debrief_ui_window.set_ignore_gadgets(0);
2912 // don't show pilot info popup by default
2913 Debrief_should_show_popup = 0;
2915 // see if the mode has changed and handle it if so.
2916 if ( Current_mode != New_mode ) {
2917 debrief_voice_stop();
2918 Current_mode = New_mode;
2921 if (New_mode == DEBRIEF_TAB) {
2923 Debrief_cue_voice = 0;
2925 if (Debrief_first_voice_flag) {
2926 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2927 Debrief_first_voice_flag = 0;
2930 Num_stages = DEBRIEF_NUM_STATS_PAGES;
2934 if ((Num_stages > 0) && (New_stage != Current_stage)) {
2935 Current_stage = New_stage;
2936 debrief_text_init();
2939 debrief_voice_play();
2942 if (Game_mode & GM_MULTIPLAYER) {
2943 multi_debrief_do_frame();
2946 // Now do all the rendering for the frame
2947 GR_MAYBE_CLEAR_RES(Background_bitmap);
2948 if (Background_bitmap >= 0) {
2949 gr_set_bitmap(Background_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2953 // draw the damn awarded stuff, G
2954 if ( Award_active && (Award_bg_bitmap >= 0) ) {
2955 gr_set_bitmap(Award_bg_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2956 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2957 if (Rank_bitmap >= 0) {
2958 gr_set_bitmap(Rank_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2960 gr_bitmap(Debrief_rank_coords[0], Debrief_rank_coords[1]);
2962 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2966 if (Medal_bitmap >= 0) {
2967 gr_set_bitmap(Medal_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2968 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2971 if (Badge_bitmap >= 0) {
2972 gr_set_bitmap(Badge_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2974 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2976 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2980 if (Wings_bitmap >= 0) {
2981 gr_set_bitmap(Wings_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2983 gr_bitmap(Debrief_badge_coords[0], Debrief_badge_coords[1]);
2985 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2989 // this isn't used in FS1 but doesn't hurt to leave it
2990 if (Crest_bitmap >= 0) {
2991 gr_set_bitmap(Crest_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2992 gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2995 // draw medal/badge/rank labels
2997 debrief_draw_award_text();
2999 if (Rank_text_bitmap >= 0) {
3000 gr_set_bitmap(Rank_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
3001 gr_bitmap(Debrief_rank_text_coords[gr_screen.res][0], Debrief_rank_text_coords[gr_screen.res][1]);
3004 if (Medal_text_bitmap >= 0) {
3005 gr_set_bitmap(Medal_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
3006 gr_bitmap(Debrief_medal_text_coords[gr_screen.res][0], Debrief_medal_text_coords[gr_screen.res][1]);
3009 if (Badge_text_bitmap >= 0) {
3010 gr_set_bitmap(Badge_text_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
3011 gr_bitmap(Debrief_badge_text_coords[gr_screen.res][0], Debrief_badge_text_coords[gr_screen.res][1]);
3016 Debrief_ui_window.draw();
3017 debrief_redraw_pressed_buttons();
3018 Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
3019 if (Recommend_active && (Current_mode != STATS_TAB)) {
3020 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
3023 // draw the title of the mission
3024 gr_set_color_fast(&Color_bright_white);
3025 SDL_strlcpy(buf, The_mission.name, SDL_arraysize(buf));
3026 gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
3027 gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf);
3029 #if !defined(NDEBUG) || defined(INTERPLAYQA)
3030 gr_set_color_fast(&Color_normal);
3031 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);
3034 // draw the screen-specific text
3035 switch (Current_mode) {
3037 if ( Num_debrief_stages <= 0 ) {
3038 gr_set_color_fast(&Color_white);
3039 SDL_assert( Game_current_mission_filename != NULL );
3040 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);
3049 debrief_stats_render();
3053 if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
3056 gr_set_color_fast(&Color_red);
3057 gr_get_string_size(&w, NULL, XSTR( "More", 459));
3058 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));
3061 debrief_render_stagenum();
3062 debrief_multi_list_draw();
3064 // render some extra stuff in multiplayer
3065 if (Game_mode & GM_MULTIPLAYER) {
3066 // render the chatbox last
3070 Debrief_ui_window.draw_tooltip();
3072 // render the status indicator for the voice system
3073 multi_common_voice_display_status();
3076 // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
3077 // want to include the mouse pointer which is drawn in the flip
3079 if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
3080 debrief_check_buttons();
3081 debrief_do_keys(new_k);
3084 // blit help overlay if active
3085 help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
3089 // dont let dude skip 3-09. hack.
3090 if(Game_mode & GM_CAMPAIGN_MODE){
3091 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
3092 if ((Campaign.missions[Campaign.current_mission].name != NULL) && !SDL_strcasecmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
3093 Debrief_skip_popup_already_shown = 1;
3098 // maybe show skip mission popup
3099 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)) {
3100 popup_callback(skip_mission_callback, 0, 3,
3101 XSTR("Do Not Skip This Mission", 1473),
3102 XSTR("Advance To The Next Mission", 1474),
3103 XSTR("Don't Show Me This Again", 1475),
3104 XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) );
3106 Debrief_skip_popup_already_shown = 1;
3109 // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
3110 if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
3111 SDL_assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
3112 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
3114 Debrief_should_show_popup = 0;
3118 void debrief_rebuild_player_list()
3122 debrief_multi_list_info *list;
3124 Multi_list_size = 0; // number of net players to choose from
3126 for ( i=0; i<MAX_PLAYERS; i++ ) {
3127 np = &Net_players[i];
3128 // remember not to include the standalone.
3129 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
3130 list = &Multi_list[Multi_list_size++];
3131 list->net_player_index = i;
3132 SDL_strlcpy(list->callsign, np->player->callsign, SDL_arraysize(list->callsign));
3134 // make sure to leave some room to blit the team indicator
3135 gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
3140 void debrief_handle_player_drop()
3142 debrief_rebuild_player_list();
3145 void debrief_disable_accept()