]> icculus.org git repositories - taylor/freespace2.git/blob - src/missionui/missiondebrief.cpp
Warning cleanups
[taylor/freespace2.git] / src / missionui / missiondebrief.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/MissionUI/MissionDebrief.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module for running the debriefing
16  *
17  * $Log$
18  * Revision 1.6  2002/07/13 06:46:48  theoddone33
19  * Warning cleanups
20  *
21  * Revision 1.5  2002/06/09 04:41:23  relnev
22  * added copyright header
23  *
24  * Revision 1.4  2002/06/02 04:26:34  relnev
25  * warning cleanup
26  *
27  * Revision 1.3  2002/05/26 22:06:17  relnev
28  * makefile: disable stand_gui for now.
29  *
30  * rest: staticize some globals
31  *
32  * Revision 1.2  2002/05/07 03:16:46  theoddone33
33  * The Great Newline Fix
34  *
35  * Revision 1.1.1.1  2002/05/03 03:28:10  root
36  * Initial import.
37  *
38  * 
39  * 57    10/29/99 10:40p Jefff
40  * hack to make german medal names display without actually changing them
41  * 
42  * 56    10/13/99 3:26p Jefff
43  * fixed unnumbered XSTRs
44  * 
45  * 55    10/06/99 10:28a Jefff
46  * updates for OEM
47  * 
48  * 54    9/30/99 5:57p Jefff
49  * show upsell at end of campaign in OEM builds
50  * 
51  * 53    9/15/99 3:42a Jefff
52  * badge voice fix
53  * 
54  * 52    9/14/99 4:35a Dave
55  * Argh. Added all kinds of code to handle potential crashes in debriefing
56  * code.
57  * 
58  * 51    9/14/99 3:26a Dave
59  * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
60  * respawn-too-early problem. Made a few crash points safe.
61  * 
62  * 50    9/14/99 12:51a Jefff
63  * 
64  * 49    9/13/99 6:01p Jefff
65  * fixed wrong promotion voice mapping for sm1-08
66  * 
67  * 48    9/13/99 11:15a Jefff
68  * clear out award text bug fixed
69  * 
70  * 47    9/13/99 12:17p Andsager
71  * Fix traitor debrief not playinf for FS2.  Don't append _3 or _1 as in
72  * FS1.
73  * 
74  * 46    9/07/99 9:35p Jefff
75  * fixed bug where award text was not getting cleared properly between
76  * debriefs.
77  * 
78  * 45    9/07/99 6:56p Jefff
79  * a few adjustments to loop detection
80  * 
81  * 44    9/07/99 1:54p Jefff
82  * skip mission cleanup
83  * 
84  * 43    9/06/99 9:45p Jefff
85  * skip mission support
86  * 
87  * 42    9/06/99 6:38p Dave
88  * Improved CD detection code.
89  * 
90  * 41    9/03/99 1:32a Dave
91  * CD checking by act. Added support to play 2 cutscenes in a row
92  * seamlessly. Fixed super low level cfile bug related to files in the
93  * root directory of a CD. Added cheat code to set campaign mission # in
94  * main hall.
95  * 
96  * 40    9/02/99 3:45p Jefff
97  * forgot to remove some debug code.  doh.
98  * 
99  * 39    9/02/99 3:41p Jefff
100  * changed badge voice handling to be similar to promotion voice handling
101  * 
102  * 38    9/01/99 4:41p Jefff
103  * fixed stoopid text color bug
104  * 
105  * 37    8/31/99 11:54a Jefff
106  * minor debrief music tweak
107  * 
108  * 36    8/27/99 9:57a Dave
109  * Enabled standard cheat codes. Allow player to continue in a campaing
110  * after using cheat codes.
111  * 
112  * 35    8/27/99 12:04a Dave
113  * Campaign loop screen.
114  * 
115  * 34    8/26/99 8:49p Jefff
116  * Updated medals screen and about everything that ever touches medals in
117  * one way or another.  Sheesh.
118  * 
119  * 33    8/20/99 4:20p Jefff
120  * hack for choosing the correct promotion voice
121  * 
122  * 32    8/16/99 4:05p Dave
123  * Big honking checkin.
124  * 
125  * 31    8/16/99 9:49a Jefff
126  * mission title length fix in multi
127  * 
128  * 30    8/11/99 5:33p Jefff
129  * added 3rd debrief music track
130  * 
131  * 29    8/10/99 7:28p Jefff
132  * shuffled some text around
133  * 
134  * 28    8/04/99 5:36p Andsager
135  * Show upsell screens at end of demo campaign before returning to main
136  * hall.
137  * 
138  * 27    8/04/99 2:07p Jefff
139  * mission title no longer overwrites popup
140  * 
141  * 26    8/02/99 5:37p Jefff
142  * 
143  * 25    8/02/99 4:52p Jefff
144  * negative feedback sound when recommendations button pressed and
145  * disabled.
146  * 
147  * 24    7/21/99 6:21p Jefff
148  * added hotkeys to the "you cannot accept" popup
149  * 
150  * 23    6/15/99 12:04p Anoop
151  * Added a warning for running out of debrief text lines.
152  * 
153  * 22    6/09/99 2:17p Dave
154  * Fixed up pleasewait bitmap rendering.
155  * 
156  * 21    6/01/99 6:07p Dave
157  * New loading/pause/please wait bar.
158  * 
159  * 20    5/22/99 6:05p Dave
160  * Fixed a few localization # problems.
161  * 
162  * 19    5/22/99 5:35p Dave
163  * Debrief and chatbox screens. Fixed small hi-res HUD bug.
164  * 
165  * 18    3/20/99 3:47p Andsager
166  * Fix crash with no mission loop description.
167  * 
168  * 17    2/23/99 2:29p Dave
169  * First run of oldschool dogfight mode. 
170  * 
171  * 16    2/21/99 6:01p Dave
172  * Fixed standalone WSS packets. 
173  * 
174  * 15    2/11/99 3:08p Dave
175  * PXO refresh button. Very preliminary squad war support.
176  * 
177  * 14    1/30/99 5:08p Dave
178  * More new hi-res stuff.Support for nice D3D textures.
179  * 
180  * 13    1/29/99 2:08a Dave
181  * Fixed beam weapon collisions with players. Reduced size of scoring
182  * struct for multiplayer. Disabled PXO.
183  * 
184  * 12    1/14/99 5:15p Neilk
185  * changed credits, command debrief interfaces to high resolution support
186  * 
187  * 11    1/13/99 2:11p Andsager
188  * change default debriefing string text
189  * 
190  * 10    12/17/98 4:50p Andsager
191  * Added debrief_assemble_optional_mission_popup_text() for single and
192  * multiplayer
193  * 
194  * 9     12/12/98 3:17p Andsager
195  * Clean up mission eval, goal, event and mission scoring.
196  * 
197  * 8     12/10/98 10:19a Andsager
198  * Fix mission loop assert
199  * 
200  * 7     12/10/98 9:59a Andsager
201  * Fix some bugs with mission loops
202  * 
203  * 6     12/09/98 1:56p Andsager
204  * Initial checkin of mission loop
205  * 
206  * 5     11/05/98 4:18p Dave
207  * First run nebula support. Beefed up localization a bit. Removed all
208  * conditional compiles for foreign versions. Modified mission file
209  * format.
210  * 
211  * 4     10/23/98 3:51p Dave
212  * Full support for tstrings.tbl and foreign languages. All that remains
213  * is to make it active in Fred.
214  * 
215  * 3     10/13/98 9:28a Dave
216  * Started neatening up freespace.h. Many variables renamed and
217  * reorganized. Added AlphaColors.[h,cpp]
218  * 
219  * 2     10/07/98 10:53a Dave
220  * Initial checkin.
221  * 
222  * 1     10/07/98 10:49a Dave
223  * 
224  * 178   9/17/98 3:08p Dave
225  * PXO to non-pxo game warning popup. Player icon stuff in create and join
226  * game screens. Upped server count refresh time in PXO to 35 secs (from
227  * 20).
228  * 
229  * 177   7/07/98 1:46p Dave
230  * Fixed nasty debriefing badge/promotion bug. Added extra physics info
231  * for capital ships. 
232  * 
233  * 175   6/09/98 10:31a Hoffoss
234  * Created index numbers for all xstr() references.  Any new xstr() stuff
235  * added from here on out should be added to the end if the list.  The
236  * current list count can be found in FreeSpace.cpp (search for
237  * XSTR_SIZE).
238  * 
239  * 174   6/07/98 3:26p Lawrance
240  * Fix bug with cut-off popup text
241  * 
242  * 173   6/05/98 9:54a Lawrance
243  * OEM changes
244  * 
245  * 172   6/01/98 11:43a John
246  * JAS & MK:  Classified all strings for localization.
247  * 
248  * 171   5/27/98 1:24p Allender
249  * make targeting dots work (as well as other targeting features) properly
250  * in multiplayer.  Don't query for CD when entering debrief in
251  * multiplayer
252  * 
253  * 170   5/26/98 11:10a Lawrance
254  * Fix bug where window controls get disabled when F1 pressed twice
255  * 
256  * 169   5/24/98 12:55a Mike
257  * Prevent Assert() when no debriefing text for a stage.
258  * 
259  * 168   5/23/98 10:38p Lawrance
260  * Avoid doing a cfile refresh when running debug
261  * 
262  * 167   5/23/98 6:49p Lawrance
263  * Fix problems with refreshing the file list when a CD is inserted
264  * 
265  * 166   5/21/98 6:57p Lawrance
266  * Don't prompt for the CD if voice not found
267  * 
268  * 165   5/20/98 2:24a Dave
269  * Fixed server side voice muting. Tweaked multi debrief/endgame
270  * sequencing a bit. Much friendlier for stats tossing/accepting now.
271  * 
272  * 164   5/19/98 8:35p Dave
273  * Revamp PXO channel listing system. Send campaign goals/events to
274  * clients for evaluation. Made lock button pressable on all screens. 
275  * 
276  * 163   5/19/98 11:13a Hoffoss
277  * Fixed bug where wrong wings award was being displayed in debriefing.
278  * 
279  * 162   5/19/98 12:28a Mike
280  * Cheat stuff.
281  * 
282  * 161   5/18/98 8:08p Hoffoss
283  * Moved placement of 'More' text.
284  * 
285  * 160   5/18/98 3:50p Dan
286  * AL: Pick correct traitor debriefing voice file
287  * 
288  * 159   5/17/98 6:32p Dave
289  * Make sure clients/servers aren't kicked out of the debriefing when team
290  * captains leave a game. Fixed chatbox off-by-one error. Fixed image
291  * xfer/pilot info popup stuff.
292  * 
293  * 158   5/16/98 9:14p Allender
294  * fix scoring ckise fir training missions to actually count medals, but
295  * nothing else.  Code used to Assert when wings were granted then taken
296  * away because they were actually never granted in scoring structure
297  * 
298  * 157   5/15/98 5:15p Dave
299  * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
300  * status for team vs. team. Put in asserts to check for invalid team vs.
301  * team situations.
302  * 
303  * 156   5/15/98 4:36p Allender
304  * fixed minor bug with wings
305  * 
306  * 155   5/15/98 4:12p Allender
307  * removed redbook code.  Put back in ingame join timer.  Major fixups for
308  * stats in multiplayer.  Pass correct score, medals, etc when leaving
309  * game.  Be sure clients display medals, badges, etc.
310  * 
311  * 154   5/15/98 2:25p Jasen
312  * temporarily disable granting of promotion and badges for clients
313  * 
314  * 153   5/15/98 10:57a Allender
315  * fixed client side debriefings
316  * 
317  * 152   5/15/98 10:36a Dave
318  * Removed 2 bogus bitmap drawing Int3()'s
319  * 
320  * 151   5/14/98 2:44p Hoffoss
321  * Added wings awarding to debrief screen.
322  * 
323  * 150   5/13/98 9:11p Lawrance
324  * Make 'replay mission' popup warn users about the loss of mission stats. 
325  *
326  * $NoKeywords: $
327  */
328
329 #include "missiondebrief.h"
330 #include "missionbriefcommon.h"
331 #include "missionscreencommon.h"
332 #include "missiongoals.h"
333 #include "missionpause.h"
334 #include "freespace.h"
335 #include "gamesequence.h"
336 #include "key.h"
337 #include "2d.h"
338 #include "ui.h"
339 #include "uidefs.h"
340 #include "gamesnd.h"
341 #include "sexp.h"
342 #include "parselo.h"
343 #include "audiostr.h"
344 #include "timer.h"
345 #include "bmpman.h"
346 #include "contexthelp.h"
347 #include "stats.h"
348 #include "player.h"
349 #include "chatbox.h"
350 #include "mouse.h"
351 #include "multi.h"
352 #include "multimsgs.h"
353 #include "multiutil.h"
354 #include "multiteamselect.h"
355 #include "multiui.h"
356 #include "eventmusic.h"
357 #include "font.h"
358 #include "popup.h"
359 #include "medals.h"
360 #include "multi_pinfo.h"
361 #include "contexthelp.h"
362 #include "multi_kick.h"
363 #include "multi_campaign.h"
364 #include "alphacolors.h"
365 #include "localize.h"
366 #include "multi_endgame.h"
367 #include "osapi.h"
368
369 #define MAX_TOTAL_DEBRIEF_LINES 200
370
371 #define TEXT_TYPE_NORMAL                        1
372 #define TEXT_TYPE_RECOMMENDATION        2
373
374 #define DEBRIEF_NUM_STATS_PAGES 4
375 #define DEBRIEF_MISSION_STATS           0
376 #define DEBRIEF_MISSION_KILLS           1
377 #define DEBRIEF_ALLTIME_STATS           2
378 #define DEBRIEF_ALLTIME_KILLS           3
379
380 // 3rd coord is max width in pixels
381 int Debrief_title_coords[GR_NUM_RESOLUTIONS][3] = {
382         { // GR_640
383                 18, 118, 174
384         },
385         { // GR_1024
386                 28, 193, 280
387         }
388 };
389
390 int Debrief_text_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
391         {       // GR_640
392                 43, 140, 339, 303                       
393         },      
394         {       // GR_1024
395                 69, 224, 535, 485               
396         }
397 };
398
399 int Debrief_text_x2[GR_NUM_RESOLUTIONS] = {
400         276,    // GR_640
401         450     // GR_1024
402 };
403         
404 int Debrief_stage_info_coords[GR_NUM_RESOLUTIONS][2] = {
405         {       // GR_640
406                 379, 137                
407         },      
408         {       // GR_1024
409                 578, 224
410         }
411 };
412
413 int Debrief_more_coords[GR_NUM_RESOLUTIONS][2] = {
414         {       // GR_640
415                 323, 453        
416         },
417         {       // GR_1024
418                 323, 453        
419         }
420 };
421
422 #define MULTI_LIST_TEAM_OFFSET                                  16              
423
424 int Debrief_multi_list_team_max_display[GR_NUM_RESOLUTIONS] = {
425         9,      // GR_640
426         12      // GR_1024
427 };
428
429 int Debrief_list_coords[GR_NUM_RESOLUTIONS][4] = {
430         {       // GR_640
431                 416, 280, 195, 101
432         },
433         {       // GR_1024
434                 666, 448, 312, 162
435         }
436 };
437
438 int Debrief_award_wnd_coords[GR_NUM_RESOLUTIONS][2] = {
439         {       // GR_640
440                 411, 126
441         },
442         {       // GR_1024
443                 658, 203        
444         }
445 };
446
447
448 int Debrief_award_coords[GR_NUM_RESOLUTIONS][2] = {
449         {       // GR_640
450                 416, 140
451         },
452         {       // GR_1024
453                 666, 224        
454         }
455 };
456
457 // 0=x, 1=y, 2=width of the field
458 int Debrief_medal_text_coords[GR_NUM_RESOLUTIONS][3] = {
459         {       // GR_640
460                 423, 247, 189
461         },
462         {       // GR_1024
463                 666, 333, 67
464         }
465 };
466
467 // 0=x, 1=y, 2=height of the field
468 int Debrief_award_text_coords[GR_NUM_RESOLUTIONS][3] = {
469         {       // GR_640
470                 416, 210, 42
471         },
472         {       // GR_1024
473                 666, 333, 67
474         }
475 };
476
477 // 0 = with medal
478 // 1 = without medal (text will use medal space)
479 #define DB_WITH_MEDAL           0
480 #define DB_WITHOUT_MEDAL        1
481 int Debrief_award_text_width[GR_NUM_RESOLUTIONS][2] = {
482         {       // GR_640
483                 123, 203
484         },
485         {       // GR_1024
486                 196, 312        
487         }
488 };
489
490 char *Debrief_single_name[GR_NUM_RESOLUTIONS] = {
491         "DebriefSingle",                // GR_640
492         "2_DebriefSingle"               // GR_1024
493 };
494 char *Debrief_multi_name[GR_NUM_RESOLUTIONS] = {
495         "DebriefMulti",         // GR_640
496         "2_DebriefMulti"                // GR_1024
497 };
498 char *Debrief_mask_name[GR_NUM_RESOLUTIONS] = {
499         "Debrief-m",                    // GR_640
500         "2_Debrief-m"                   // GR_1024
501 };
502
503 #define NUM_BUTTONS     18
504 #define NUM_TABS                2
505
506 #define DEBRIEF_TAB                             0
507 #define STATS_TAB                                       1
508 #define TEXT_SCROLL_UP                  2
509 #define TEXT_SCROLL_DOWN                3
510 #define REPLAY_MISSION                  4
511 #define RECOMMENDATIONS                 5
512 #define FIRST_STAGE                             6
513 #define PREV_STAGE                              7
514 #define NEXT_STAGE                              8
515 #define LAST_STAGE                              9
516 #define MULTI_PINFO_POPUP               10
517 #define MULTI_KICK                              11
518 #define MEDALS_BUTTON                   12
519 #define PLAYER_SCROLL_UP                13
520 #define PLAYER_SCROLL_DOWN              14
521 #define HELP_BUTTON                             15
522 #define OPTIONS_BUTTON                  16
523 #define ACCEPT_BUTTON                   17
524
525 #define REPEAT  1
526
527 //XSTR:OFF
528 char* Debrief_loading_bitmap_fname[GR_NUM_RESOLUTIONS] = {
529         "PleaseWait",           // GR_640
530         "2_PleaseWait"          // GR_1024
531 };
532
533 //XSTR:ON
534
535 typedef struct {
536         char    text[NAME_LENGTH+1];    // name of ship type with a colon
537         int     num;                                            // how many ships of this type player has killed
538 } debrief_stats_kill_info;
539
540 typedef struct {
541         int net_player_index;   // index into Net_players[] array
542         int rank_bitmap;                        // bitmap id for rank
543         char callsign[CALLSIGN_LEN];
544 } debrief_multi_list_info;
545
546 static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
547         { // GR_640
548                 ui_button_info("DB_00",         6,              1,              37,     7,              0),             // debriefing
549                 ui_button_info("DB_01",         6,              21,     37,     23,     1),             // statistics
550                 ui_button_info("DB_02",         1,              195,    -1,     -1,     2),             // scroll stats up
551                 ui_button_info("DB_03",         1,              236,    -1,     -1,     3),             // scroll stats down
552                 ui_button_info("DB_04",         1,              428,    49,     447,    4),             // replay mission
553                 ui_button_info("DB_05",         17,     459,    49,     464,    5),             // recommendations
554                 ui_button_info("DB_06",         323,    454,    -1,     -1,     6),             // first page
555                 ui_button_info("DB_07",         348,    454,    -1,     -1,     7),             // prev page
556                 ui_button_info("DB_08",         372,    454,    -1,     -1,     8),             // next page
557                 ui_button_info("DB_09",         396,    454,    -1,     -1,     9),             // last page
558                 ui_button_info("DB_10",         441,    384,    433,    413,    10),            // pilot info
559                 ui_button_info("DB_11",         511,    384,    510,    413,    11),            // kick
560                 ui_button_info("DB_12",         613,    226,    -1,     -1,     12),            // medals
561                 ui_button_info("DB_13",         615,    329,    -1,     -1,     13),            // scroll pilots up
562                 ui_button_info("DB_14",         615,    371,    -1,     -1,     14),            // scroll pilots down
563                 ui_button_info("DB_15",         538,    431,    500,    440,    15),            // help
564                 ui_button_info("DB_16",         538,    455,    479,    464,    16),            // options
565                 ui_button_info("DB_17",         573,    432,    572,    413,    17),            // accept
566         },
567         { // GR_1024
568                 ui_button_info("2_DB_00",               10,     1,              59,     12,     0),             // debriefing
569                 ui_button_info("2_DB_01",               10,     33,     59,     37,     1),             // statistics
570                 ui_button_info("2_DB_02",               1,              312,    -1,     -1,     2),             // scroll stats up
571                 ui_button_info("2_DB_03",               1,              378,    -1,     -1,     3),             // scroll stats down
572                 ui_button_info("2_DB_04",               1,              685,    79,     715,    4),             // replay mission
573                 ui_button_info("2_DB_05",               28,     735,    79,     743,    5),             // recommendations
574                 ui_button_info("2_DB_06",               517,    726,    -1,     -1,     6),             // first page
575                 ui_button_info("2_DB_07",               556,    726,    -1,     -1,     7),             // prev page
576                 ui_button_info("2_DB_08",               595,    726,    -1,     -1,     8),             // next page
577                 ui_button_info("2_DB_09",               633,    726,    -1,     -1,     9),             // last page
578                 ui_button_info("2_DB_10",               706,    615,    700,    661,    10),            // pilot info
579                 ui_button_info("2_DB_11",               817,    615,    816,    661,    11),            // kick
580                 ui_button_info("2_DB_12",               981,    362,    -1,     -1,     12),            // medals
581                 ui_button_info("2_DB_13",               984,    526,    -1,     -1,     13),            // scroll pilots up
582                 ui_button_info("2_DB_14",               984,    594,    -1,     -1,     14),            // scroll pilots down
583                 ui_button_info("2_DB_15",               861,    689,    801,    705,    15),            // help
584                 ui_button_info("2_DB_16",               861,    728,    777,    744,    16),            // options
585                 ui_button_info("2_DB_17",               917,    692,    917,    692,    17),            // accept
586         }
587 };
588
589 // text
590 #define NUM_DEBRIEF_TEXT                                10
591 #define MP_TEXT_INDEX_1                                 4
592 #define MP_TEXT_INDEX_2                                 5
593 #define MP_TEXT_INDEX_3                                 6
594 UI_XSTR Debrief_strings[GR_NUM_RESOLUTIONS][NUM_DEBRIEF_TEXT] = {
595         { // GR_640
596                 { "Debriefing",         804,            37,     7,              UI_XSTR_COLOR_GREEN,    -1,     &Buttons[0][DEBRIEF_TAB].button },
597                 { "Statistics",         1333,           37,     26,     UI_XSTR_COLOR_GREEN,    -1,     &Buttons[0][STATS_TAB].button },
598                 { "Replay Mission",     444,            49,     447,    UI_XSTR_COLOR_PINK,     -1,     &Buttons[0][REPLAY_MISSION].button },
599                 { "Recommendations",    1334,           49,     464,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[0][RECOMMENDATIONS].button },
600                 { "Pilot",                              1310,           433,    413,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[0][MULTI_PINFO_POPUP].button },
601                 { "Info",                               1311,           433,    423,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[0][MULTI_PINFO_POPUP].button },
602                 { "Kick",                               1266,           510,    413,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[0][MULTI_KICK].button },
603                 { "Help",                               928,            500,    440,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[0][HELP_BUTTON].button },
604                 { "Options",                    1036,           479,    464,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[0][OPTIONS_BUTTON].button },
605                 { "Accept",                             1035,           572,    413,    UI_XSTR_COLOR_PINK,     -1,     &Buttons[0][ACCEPT_BUTTON].button },
606         },
607         { // GR_1024
608                 { "Debriefing",         804,            59,     12,     UI_XSTR_COLOR_GREEN,    -1,     &Buttons[1][DEBRIEF_TAB].button },
609                 { "Statistics",         1333,           59,     47,     UI_XSTR_COLOR_GREEN,    -1,     &Buttons[1][STATS_TAB].button },
610                 { "Replay Mission",     444,            79,     715,    UI_XSTR_COLOR_PINK,     -1,     &Buttons[1][REPLAY_MISSION].button },
611                 { "Recommendations",    1334,           79,     743,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[1][RECOMMENDATIONS].button },
612                 { "Pilot",                              1310,           700,    661,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[1][MULTI_PINFO_POPUP].button },
613                 { "Info",                               1311,           700,    679,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[1][MULTI_PINFO_POPUP].button },
614                 { "Kick",                               1266,           816,    661,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[1][MULTI_KICK].button },
615                 { "Help",                               928,            801,    705,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[1][HELP_BUTTON].button },
616                 { "Options",                    1036,           780,    744,    UI_XSTR_COLOR_GREEN,    -1,     &Buttons[1][OPTIONS_BUTTON].button },
617                 { "Accept",                             1035,           917,    672,    UI_XSTR_COLOR_PINK,     -1,     &Buttons[1][ACCEPT_BUTTON].button },
618         }
619 };
620
621
622 char Debrief_current_callsign[CALLSIGN_LEN+10];
623 player *Debrief_player;
624
625 static UI_WINDOW Debrief_ui_window;
626 static UI_BUTTON List_region;
627 static int Background_bitmap;                                   // bitmap for the background of the debriefing
628 static int Award_bg_bitmap;
629 static int Debrief_multi_loading_bitmap;
630 static int Rank_bitmap;
631 static int Medal_bitmap;
632 static int Badge_bitmap;
633 static int Wings_bitmap;
634 static int Crest_bitmap;
635 //static int Rank_text_bitmap;
636 //static int Medal_text_bitmap;
637 //static int Badge_text_bitmap;
638 static int Promoted;
639 static int Debrief_accepted;
640 static int Turned_traitor;
641 static int Must_replay_mission;
642
643 static int Current_mode;
644 static int New_mode;
645 static int Recommend_active;
646 static int Award_active;
647 static int Text_offset;
648 static int Num_text_lines = 0;
649 static int Num_debrief_lines = 0;
650 static int Text_type[MAX_TOTAL_DEBRIEF_LINES];
651 static char *Text[MAX_TOTAL_DEBRIEF_LINES];
652
653 static int Debrief_inited = 0;
654 static int New_stage;
655 static int Current_stage;
656 static int Num_stages;
657 static int Num_debrief_stages;
658 static int Stage_voice;
659
660 static int Multi_list_size;
661 static int Multi_list_offset;
662
663 int Debrief_multi_stages_loaded = 0;
664 int Debrief_multi_voice_loaded = 0;
665
666 // static int Debrief_voice_ask_for_cd;
667
668 // voice id's for debriefing text
669 static int Debrief_voices[MAX_DEBRIEF_STAGES];
670
671 #define DEBRIEF_VOICE_DELAY 400                         // time to delay voice playback when a new stage starts
672 static int Debrief_cue_voice;                                   // timestamp to cue the playback of the voice
673 static int Debrief_first_voice_flag = 1;        // used to delay the first voice playback extra long
674
675 // pointer used for getting to debriefing information
676 debriefing      Traitor_debriefing;                             // used when player is a traitor
677
678 // pointers to the active stages for this debriefing
679 static debrief_stage *Debrief_stages[MAX_DEBRIEF_STAGES];
680 static debrief_stage Promotion_stage, Badge_stage;
681 static debrief_stats_kill_info Debrief_stats_kills[MAX_SHIP_TYPES];
682 static debrief_multi_list_info Multi_list[MAX_PLAYERS];
683 int Multi_list_select;
684
685 // flag indicating if we should display info for the given player (in multiplayer)
686 int Debrief_should_show_popup = 1;
687
688 // already shown skip mission popup?
689 static int Debrief_skip_popup_already_shown = 0;
690
691 void debrief_text_init();
692 void debrief_accept(int ok_to_post_start_game_event = 1);
693 void debrief_kick_selected_player();
694
695
696 // promotion voice selection stuff
697 #define NUM_VOLITION_CAMPAIGNS  1
698 struct {
699         char  campaign_name[32];
700         int     num_missions;
701 } Volition_campaigns[NUM_VOLITION_CAMPAIGNS] = {
702         {
703                 BUILTIN_CAMPAIGN,               // the only campaign for now, but this leaves room for a mission pack
704                 35                                              // make sure this is equal to the  number of missions you gave in the corresponding Debrief_promotion_voice_mapping
705         }
706 };
707
708 // data for which voice goes w/ which mission
709 typedef struct voice_map {
710         char  mission_file[32];
711         int     persona_index;
712 } voice_map;
713
714 voice_map Debrief_promotion_voice_mapping[NUM_VOLITION_CAMPAIGNS][MAX_CAMPAIGN_MISSIONS] = {
715         {               // FreeSpace2 campaign 
716                 { "SM1-01.fs2",                 1 },
717                 { "SM1-02.fs2",                 1 },
718                 { "SM1-03.fs2",                 1 },
719                 { "SM1-04.fs2",                 2 },
720                 { "SM1-05.fs2",                 2 },
721                 { "SM1-06.fs2",                 2 },
722                 { "SM1-07.fs2",                 2 },
723                 { "SM1-08.fs2",                 3 },
724                 { "SM1-09.fs2",                 3 },
725                 { "SM1-10.fs2",                 3 },
726
727                 { "SM2-01.fs2",                 6 },
728                 { "SM2-02.fs2",                 6 },
729                 { "SM2-03.fs2",                 6 },
730                 { "SM2-04.fs2",                 7 },
731                 { "SM2-05.fs2",                 7 },
732                 { "SM2-06.fs2",                 7 },
733                 { "SM2-07.fs2",                 8 },
734                 { "SM2-08.fs2",                 8 },
735                 { "SM2-09.fs2",                 8 },
736                 { "SM2-10.fs2",                 8 },
737
738                 { "SM3-01.fs2",                 8 },
739                 { "SM3-02.fs2",                 8 },
740                 { "SM3-03.fs2",                 8 },
741                 { "SM3-04.fs2",                 8 },
742                 { "SM3-05.fs2",                 8 },
743                 { "SM3-06.fs2",                 9 },
744                 { "SM3-07.fs2",                 9 },
745                 { "SM3-08.fs2",                 9 },
746                 { "SM3-09.fs2",                 9 },
747                 { "SM3-10.fs2",                 9 },                    // no debriefing for 3-10
748                 
749                 { "loop1-1.fs2",                        4 },
750                 { "loop1-2.fs2",                        4 },
751                 { "loop1-3.fs2",                        5 },
752                 { "loop2-1.fs2",                        4 },
753                 { "loop2-2.fs2",                        4 }
754         }
755 };
756
757 #define DB_AWARD_WINGS          0
758 #define DB_AWARD_MEDAL          1
759 #define DB_AWARD_SOC                    2
760 #define DB_AWARD_RANK           3
761 #define DB_AWARD_BADGE          4
762 #define DB_AWARD_BG                     5
763 static char* Debrief_award_filename[GR_NUM_RESOLUTIONS][6] = {
764         {
765                 "DebriefWings",
766                 "DebriefMedal",
767                 "DebriefCrest",
768                 "DebriefRank",
769                 "DebriefBadge",
770                 "DebriefAward"
771         },
772         {
773                 "2_DebriefWings",
774                 "2_DebriefMedal",
775                 "2_DebriefCrest",
776                 "2_DebriefRank",
777                 "2_DebriefBadge",
778                 "2_DebriefAward"
779         }
780 };
781
782 #define AWARD_TEXT_MAX_LINES                            5
783 #define AWARD_TEXT_MAX_LINE_LENGTH              128
784 char Debrief_award_text[AWARD_TEXT_MAX_LINES][AWARD_TEXT_MAX_LINE_LENGTH];
785 int Debrief_award_text_num_lines = 0;
786
787
788
789 // prototypes, you know you love 'em
790 void debrief_add_award_text(char *str);
791 void debrief_award_text_clear();
792
793
794
795 // functions
796 char *debrief_tooltip_handler(char *str)
797 {
798         if (!stricmp(str, NOX("@.Medal"))) {
799                 if (Award_active){
800                         return XSTR( "Medal", 435);
801                 }
802
803         } else if (!stricmp(str, NOX("@.Rank"))) {
804                 if (Award_active){
805                         return XSTR( "Rank", 436);
806                 }
807
808         } else if (!stricmp(str, NOX("@.Badge"))) {
809                 if (Award_active){
810                         return XSTR( "Badge", 437);
811                 }
812
813         } else if (!stricmp(str, NOX("@Medal"))) {
814                 if (Medal_bitmap >= 0){
815                         return Medals[Player->stats.m_medal_earned].name;
816                 }
817
818         } else if (!stricmp(str, NOX("@Rank"))) {
819                 if (Rank_bitmap >= 0){
820                         return Ranks[Promoted].name;
821                 }
822
823         } else if (!stricmp(str, NOX("@Badge"))) {
824                 if (Badge_bitmap >= 0){
825                         return Medals[Badge_index[Player->stats.m_badge_earned]].name;
826                 }
827         }
828
829         return NULL;
830 }
831
832 // initialize the array of handles to the different voice streams
833 void debrief_voice_init()
834 {
835         int i;
836
837         for (i=0; i<MAX_DEBRIEF_STAGES; i++) {
838                 Debrief_voices[i] = -1;
839         }
840 }
841
842 void debrief_load_voice_file(int voice_num, char *name)
843 {
844         int load_attempts = 0;
845         while(1) {
846
847                 if ( load_attempts++ > 5 ) {
848                         break;
849                 }
850
851                 Debrief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
852                 if ( Debrief_voices[voice_num] >= 0 ) {
853                         break;
854                 }
855
856                 // Don't bother to ask for the CD in multiplayer
857                 if ( Game_mode & GM_MULTIPLAYER ) {
858                         break;
859                 }
860
861                 // couldn't load voice, ask user to insert CD (if necessary)
862
863                 // if ( Debrief_voice_ask_for_cd ) {
864                         // if ( game_do_cd_check() == 0 ) {
865                                 // Debrief_voice_ask_for_cd = 0;
866                                 // break;
867                         // }
868                 // }
869         }
870 }
871
872 // open and pre-load the stream buffers for the different voice streams
873 void debrief_voice_load_all()
874 {
875         int i;
876
877         // Debrief_voice_ask_for_cd = 1;
878
879         for ( i=0; i<Num_debrief_stages; i++ ) {
880                 if ( strlen(Debrief_stages[i]->voice) <= 0 ) {
881                         continue;
882                 }
883                 if ( strnicmp(Debrief_stages[i]->voice, NOX("none"), 4) ) {
884                         debrief_load_voice_file(i, Debrief_stages[i]->voice);
885 //                      Debrief_voices[i] = audiostream_open(Debrief_stages[i]->voice, ASF_VOICE);
886                 }
887         }
888 }
889
890 // close all the briefing voice streams
891 void debrief_voice_unload_all()
892 {
893         int i;
894
895         for ( i=0; i<MAX_DEBRIEF_STAGES; i++ ) {
896                 if ( Debrief_voices[i] != -1 ) {
897                         audiostream_close_file(Debrief_voices[i], 0);
898                         Debrief_voices[i] = -1;
899                 }
900         }
901 }
902
903 // start playback of the voice for a particular briefing stage
904 void debrief_voice_play()
905 {
906         if (!Briefing_voice_enabled || (Current_mode != DEBRIEF_TAB)){
907                 return;
908         }
909
910         // no more stages?  We are done then.
911         if (Stage_voice >= Num_debrief_stages){
912                 return;
913         }
914
915         // if in delayed start, see if delay has elapsed and start voice if so
916         if (Debrief_cue_voice) {
917                 if (!timestamp_elapsed(Debrief_cue_voice)){
918                         return;
919                 }
920
921                 Stage_voice++;  // move up to next voice
922                 if ((Stage_voice < Num_debrief_stages) && (Debrief_voices[Stage_voice] >= 0)) {
923                         audiostream_play(Debrief_voices[Stage_voice], Master_voice_volume, 0);
924                         Debrief_cue_voice = 0;  // indicate no longer in delayed start checking
925                 }
926
927                 return;
928         }
929
930         // see if voice is still playing.  If so, do nothing yet.
931         if ((Stage_voice >= 0) && audiostream_is_playing(Debrief_voices[Stage_voice])){
932                 return;
933         }
934
935         // set voice to play in a little while from now.
936         Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY);
937 }
938
939 // stop playback of the voice for a particular briefing stage
940 void debrief_voice_stop()
941 {
942         if ((Stage_voice < 0) || (Stage_voice > Num_debrief_stages) || (Debrief_voices[Stage_voice] < 0))
943                 return;
944
945         audiostream_stop(Debrief_voices[Stage_voice]);  // stream is automatically rewound
946         Stage_voice = -1;
947 }
948
949 // function to deal with inserting possible promition and badge stages into the debriefing
950 // on the clients
951 void debrief_multi_fixup_stages()
952 {
953         int i;
954
955         // possibly insert the badge stage first, them the promotion stage since they are
956         // inserted at the front of the debrief stages.
957         if ( Badge_bitmap >= 0 ) {
958                 // move all stages forward one.  Don't 
959                 for ( i = Num_debrief_stages; i > 0; i-- ) {
960                         Debrief_stages[i] = Debrief_stages[i-1];
961                 }
962                 Debrief_stages[0] = &Badge_stage;
963                 Num_debrief_stages++;
964         }
965
966         if ( Promoted >= 0) {
967                 // move all stages forward one
968                 for ( i = Num_debrief_stages; i > 0; i-- ) {
969                         Debrief_stages[i] = Debrief_stages[i-1];
970                 }
971                 Debrief_stages[0] = &Promotion_stage;
972                 Num_debrief_stages++;
973         }
974 }
975
976
977 // function called from multiplayer clients to set up the debriefing information for them
978 // (sent from the server).  
979 void debrief_set_multi_clients( int stage_count, int active_stages[] )
980 {
981         int i;
982
983         // set up the right briefing for this guy
984         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
985                 Debriefing = &Debriefings[Net_player->p_info.team];
986         } else {
987                 Debriefing = &Debriefings[0];                   
988         }
989
990         // see if this client was promoted -- if so, then add the first stage.
991         Num_debrief_stages = 0;
992
993         // set the pointers to the debriefings for this client
994         for (i = 0; i < stage_count; i++) {
995                 Debrief_stages[Num_debrief_stages++] = &Debriefing->stages[active_stages[i]];
996         }
997
998         Debrief_multi_stages_loaded = 1;
999 }
1000
1001 // evaluate all stages for all teams.  Server of a multiplayer game will have to send that
1002 // information to all clients after leaving this screen.
1003 void debrief_multi_server_stuff()
1004 {
1005         debriefing *debriefp;
1006
1007         int stage_active[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
1008         int i, j, num_stages, stage_count[MAX_TEAMS];
1009
1010         memset( stage_active, 0, sizeof(stage_active) );
1011
1012         for (i=0; i<Num_teams; i++) {
1013                 debriefp = &Debriefings[i];
1014                 num_stages = 0;
1015                 stages[i] = stage_active[i];
1016                 for (j=0; j<debriefp->num_stages; j++) {
1017                         if ( eval_sexp(debriefp->stages[j].formula) ) {
1018                                 stage_active[i][num_stages] = j;
1019                                 num_stages++;
1020                         }
1021                 }
1022
1023                 stage_count[i] = num_stages;
1024         }
1025
1026         // if we're in campaign mode, evaluate campaign stuff
1027         if (Netgame.campaign_mode == MP_CAMPAIGN) {
1028                 multi_campaign_eval_debrief();
1029         }
1030
1031         // send the information to all clients.
1032         send_debrief_info( stage_count, stages );
1033 }
1034
1035
1036 // --------------------------------------------------------------------------------------
1037 //      debrief_set_stages_and_multi_stuff()
1038 //
1039 // Set up the active stages for this debriefing
1040 //
1041 // returns:             number of active debriefing stages
1042 //
1043 int debrief_set_stages_and_multi_stuff()
1044 {
1045         int i;
1046         debriefing      *debriefp;
1047
1048         if ( MULTIPLAYER_CLIENT ) {
1049                 return 0;
1050         }
1051
1052         Num_debrief_stages = 0;
1053
1054         if ( Game_mode & GM_MULTIPLAYER ) {
1055                 debrief_multi_server_stuff();
1056         }
1057
1058         // check to see if player is a traitor (looking at his team).  If so, use the special
1059         // traitor debriefing.  Only done in single player
1060         debriefp = Debriefing;
1061         if ( !(Game_mode & GM_MULTIPLAYER) ) {
1062                 if (Player_ship->team == TEAM_TRAITOR)
1063                         debriefp = &Traitor_debriefing;
1064         }
1065
1066         Num_debrief_stages = 0;
1067         if (Promoted >= 0) {
1068                 Debrief_stages[Num_debrief_stages++] = &Promotion_stage;
1069         }
1070
1071         if (Badge_bitmap >= 0) {
1072                 Debrief_stages[Num_debrief_stages++] = &Badge_stage;
1073         }
1074
1075         for (i=0; i<debriefp->num_stages; i++) {
1076                 if (eval_sexp(debriefp->stages[i].formula) == 1) {
1077                         Debrief_stages[Num_debrief_stages++] = &debriefp->stages[i];
1078                 }
1079         }
1080
1081         return Num_debrief_stages;
1082 }
1083
1084 // init the buttons that are specific to the debriefing screen
1085 void debrief_buttons_init()
1086 {
1087         ui_button_info *b;
1088         int i;
1089
1090         for ( i=0; i<NUM_BUTTONS; i++ ) {
1091                 b = &Buttons[gr_screen.res][i];
1092                 b->button.create( &Debrief_ui_window, "", b->x, b->y, 60, 30, 0 /*b->flags & REPEAT*/, 1 );
1093                 // set up callback for when a mouse first goes over a button
1094                 b->button.set_highlight_action( common_play_highlight_sound );
1095                 b->button.set_bmaps(b->filename);
1096                 b->button.link_hotspot(b->hotspot);
1097         }
1098
1099         // add all xstrs
1100         for(i=0; i<NUM_DEBRIEF_TEXT; i++){
1101                 // multiplayer specific text
1102                 if((i == MP_TEXT_INDEX_1) || (i == MP_TEXT_INDEX_2) || (i == MP_TEXT_INDEX_3)){
1103                         // only add if in multiplayer mode
1104                         if(Game_mode & GM_MULTIPLAYER){
1105                                 Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1106                         }
1107                 } 
1108                 // all other text
1109                 else {
1110                         Debrief_ui_window.add_XSTR(&Debrief_strings[gr_screen.res][i]);
1111                 }
1112         }
1113         
1114         // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
1115         Buttons[gr_screen.res][NEXT_STAGE].button.set_hotkey(KEY_RIGHT);
1116         Buttons[gr_screen.res][PREV_STAGE].button.set_hotkey(KEY_LEFT);
1117         Buttons[gr_screen.res][LAST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_RIGHT);
1118         Buttons[gr_screen.res][FIRST_STAGE].button.set_hotkey(KEY_SHIFTED | KEY_LEFT);
1119         Buttons[gr_screen.res][TEXT_SCROLL_UP].button.set_hotkey(KEY_UP);
1120         Buttons[gr_screen.res][TEXT_SCROLL_DOWN].button.set_hotkey(KEY_DOWN);
1121         Buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_CTRLED+KEY_ENTER);
1122
1123         // if in multiplayer, disable the button for all players except the host
1124         // also disable for squad war matches
1125         if(Game_mode & GM_MULTIPLAYER){
1126                 if((Netgame.type_flags & NG_TYPE_SW) || !(Net_player->flags & NETINFO_FLAG_GAME_HOST)){
1127                         Buttons[gr_screen.res][REPLAY_MISSION].button.disable();
1128                 }
1129         }
1130 }
1131
1132 // --------------------------------------------------------------------------------------
1133 //      debrief_ui_init()
1134 //
1135 void debrief_ui_init()
1136 {
1137         // init ship selection masks and buttons
1138         common_set_interface_palette("DebriefPalette");         // set the interface palette
1139         Debrief_ui_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
1140         Debrief_ui_window.set_mask_bmap(Debrief_mask_name[gr_screen.res]);
1141         Debrief_ui_window.tooltip_handler = debrief_tooltip_handler;
1142         debrief_buttons_init();
1143
1144         // load in help overlay bitmap  
1145         help_overlay_load(DEBRIEFING_OVERLAY);
1146         help_overlay_set_state(DEBRIEFING_OVERLAY,0);
1147
1148         if ( Game_mode & GM_MULTIPLAYER ) {
1149                 // close down any old instances of the chatbox
1150                 chatbox_close();
1151
1152                 // create the new one
1153                 chatbox_create();
1154                 Background_bitmap = bm_load(Debrief_multi_name[gr_screen.res]);
1155                 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);
1156                 List_region.hide();
1157         } else {
1158                 Background_bitmap = bm_load(Debrief_single_name[gr_screen.res]);
1159         }
1160
1161         if ( Background_bitmap < 0 ) {
1162                 Warning(LOCATION, "Could not load the background bitmap for debrief screen");
1163         }
1164
1165         Award_bg_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_BG]);
1166         Debrief_multi_loading_bitmap = bm_load(Debrief_loading_bitmap_fname[gr_screen.res]);
1167 }
1168
1169 // sets Promotion_stage.voice
1170 // defaults to number 9 (Petrarch) for non-volition missions
1171 // this is an ugly, nasty way of doing this, but it saves us changing the missions at this point
1172 void debrief_choose_promotion_voice()
1173 {
1174         int i, j;
1175
1176         if(Campaign.current_mission < 0){
1177                 sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1178                 return;
1179         }
1180
1181         // search thru all official campaigns for our current campaign
1182         if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1183                 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1184                         if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {  
1185                                 // now search thru the mission filenames, 
1186                                 for (j=0; j<Volition_campaigns[i].num_missions; j++) {
1187                                         if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1188                                                 // found it!  set the persona and bail
1189                                                 sprintf(Promotion_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Ranks[Promoted].promotion_voice_base);
1190                                                 return;
1191                                         }
1192                                 }
1193                         }
1194                 }
1195         }
1196
1197         // default to petrarch
1198         sprintf(Promotion_stage.voice, NOX("9_%s"), Ranks[Promoted].promotion_voice_base);
1199 }
1200
1201 // sets Promotion_stage.voice
1202 // defaults to number 9 (Petrarch) for non-volition missions
1203 // this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point
1204 void debrief_choose_badge_voice()
1205 {
1206         int i, j;
1207
1208         if(Campaign.current_mission < 0){
1209                 // default to petrarch
1210                 sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1211         }
1212
1213         if ((Campaign.missions[Campaign.current_mission].name) && (Campaign.filename)) {
1214                 // search thru all official campaigns for our current campaign
1215                 for (i=0; i<NUM_VOLITION_CAMPAIGNS; i++) {
1216                         if ((Campaign.filename != NULL) && !stricmp(Campaign.filename, Volition_campaigns[i].campaign_name)) {  
1217                                 // now search thru the mission filenames, 
1218                                 for (j=0; j<Campaign.num_missions; j++) {
1219                                         if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, Debrief_promotion_voice_mapping[i][j].mission_file)) {
1220                                                 // found it!  set the persona and bail
1221                                                 sprintf(Badge_stage.voice, NOX("%d_%s"), Debrief_promotion_voice_mapping[i][j].persona_index, Badge_info[Player->stats.m_badge_earned].voice_base);
1222                                                 return;
1223                                         }
1224                                 }
1225                         }
1226                 }
1227         }
1228
1229         // default to petrarch
1230         sprintf(Badge_stage.voice, NOX("9_%s"), Badge_info[Player->stats.m_badge_earned].voice_base);
1231 }
1232
1233
1234 void debrief_award_init()
1235 {
1236         char buf[80];
1237         int i;
1238
1239         Rank_bitmap = -1; 
1240         Medal_bitmap = -1;
1241         Badge_bitmap = -1;
1242         Wings_bitmap = -1;
1243         Crest_bitmap = -1;
1244         Promoted = -1;
1245
1246         // be sure there are no old award texts floating around
1247         debrief_award_text_clear();
1248
1249         // handle medal earned
1250         if (Player->stats.m_medal_earned != -1) {
1251                 if (Player->stats.m_medal_earned == 13) {  // special hack for the wings..
1252                         int ver;
1253                         if ( Player->stats.medals[13] > 1 ) {
1254                                 ver = 1;
1255                         } else {
1256                                 ver = 0;
1257                         }
1258                         sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_WINGS], ver);                
1259                         Wings_bitmap = bm_load(buf);
1260
1261                 } else if (Player->stats.m_medal_earned == 17) {  // special hack for the soc crest
1262                         Crest_bitmap = bm_load(Debrief_award_filename[gr_screen.res][DB_AWARD_SOC]);
1263                 } else {
1264                         sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_MEDAL], Player->stats.m_medal_earned);
1265                         Medal_bitmap = bm_load(buf);
1266                 }
1267
1268                 debrief_add_award_text(Medals[Player->stats.m_medal_earned].name);
1269         }
1270         
1271         // handle promotions
1272         if ( Player->stats.m_promotion_earned != -1 ) {
1273                 Promoted = Player->stats.m_promotion_earned;
1274                 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_RANK], Promoted + 1);
1275                 Rank_bitmap = bm_load(buf);
1276
1277                 Promotion_stage.new_text = Ranks[Promoted].promotion_text;
1278                 Promotion_stage.new_recommendation_text = NULL;
1279
1280                 // choose appropriate promotion voice for this mission
1281                 debrief_choose_promotion_voice();
1282
1283                 debrief_add_award_text(Ranks[Promoted].name);
1284         }
1285
1286         // handle badge earned
1287         // only grant badge if earned and allowed.  (no_promotion really means no promotion and no badges)
1288         if ( Player->stats.m_badge_earned != -1 ) {
1289                 i = Player->stats.m_badge_earned;
1290                 sprintf(buf, NOX("%s%.2d"), Debrief_award_filename[gr_screen.res][DB_AWARD_BADGE], i + 1);
1291                 Badge_bitmap = bm_load(buf);
1292
1293                 Badge_stage.new_text = Badge_info[i].promotion_text;
1294                 Badge_stage.new_recommendation_text = NULL;
1295
1296                 // choose appropriate voice
1297                 debrief_choose_badge_voice();
1298
1299                 debrief_add_award_text(Medals[Badge_index[i]].name);
1300         }
1301
1302         if ((Rank_bitmap >= 0) || (Medal_bitmap >= 0) || (Badge_bitmap >= 0) || (Wings_bitmap >= 0) || (Crest_bitmap >= 0)) {
1303                 Award_active = 1;
1304         } else {
1305                 Award_active = 0;
1306         }
1307 }
1308
1309 // debrief_traitor_init() initializes local data which could be used if the player leaves the 
1310 // mission a traitor.  The same debriefing always gets played
1311 void debrief_traitor_init()
1312 {
1313         static int inited = 0;
1314
1315         if ( !inited ) {
1316                 debriefing              *debrief;
1317                 debrief_stage   *stagep;
1318                 int rval;
1319                 int stage_num;
1320
1321                 if ((rval = setjmp(parse_abort)) != 0) {
1322                         Error(LOCATION, "Unable to parse traitor.tbl!  Code = %i.\n", rval);
1323                 }
1324                 else {
1325                         read_file_text("traitor.tbl");
1326                         reset_parse();          
1327                 }
1328
1329                 // open localization
1330                 lcl_ext_open();
1331
1332                 // simplied form of the debriefing stuff.
1333                 debrief = &Traitor_debriefing;
1334                 required_string("#Debriefing_info");
1335
1336                 required_string("$Num stages:");
1337                 stuff_int(&debrief->num_stages);
1338                 Assert(debrief->num_stages == 1);
1339
1340                 stage_num = 0;
1341                 stagep = &debrief->stages[stage_num++];
1342                 required_string("$Formula:");
1343                 stagep->formula = get_sexp_main();
1344                 required_string("$multi text");
1345                 if ( Fred_running )     {
1346                         stuff_string( stagep->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1347                 } else {
1348                         stagep->new_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1349                 }
1350                 required_string("$Voice:");
1351                 char traitor_voice_file[NAME_LENGTH];
1352                 stuff_string(traitor_voice_file, F_FILESPEC, NULL);
1353
1354 // DKA 9/13/99  Only 1 traitor msg for FS2
1355 //              if ( Player->on_bastion ) {
1356 //                      strcpy(stagep->voice, NOX("3_"));
1357 //              } else {
1358 //                      strcpy(stagep->voice, NOX("1_"));
1359 //              }
1360
1361                 strcat(stagep->voice, traitor_voice_file);
1362
1363                 required_string("$Recommendation text:");
1364                 if ( Fred_running )     {
1365                         stuff_string( stagep->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1366                 } else {
1367                         stagep->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1368                 }
1369                 inited = 1;
1370
1371                 // close localization
1372                 lcl_ext_close();
1373         }
1374
1375         // disable the accept button if in single player and I am a traitor
1376         Debrief_accepted = 0;
1377         Turned_traitor = Must_replay_mission = 0;
1378         if (!(Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_CAMPAIGN_MODE)) {
1379                 if (Player_ship->team == TEAM_TRAITOR){
1380                         Turned_traitor = 1;
1381                 }
1382
1383                 if (Campaign.next_mission == Campaign.current_mission){
1384                         Must_replay_mission = 1;
1385                 }
1386         }
1387
1388         if (Turned_traitor || Must_replay_mission) {
1389                 Buttons[gr_screen.res][ACCEPT_BUTTON].button.hide();
1390
1391                 // kill off any stats
1392                 Player->flags &= ~PLAYER_FLAGS_PROMOTED;
1393                 scoring_level_init( &Player->stats );
1394         }
1395 }
1396
1397 // initialization for listing of players in game
1398 void debrief_multi_list_init()
1399 {
1400         Multi_list_size = 0;  // number of net players to choose from
1401         Multi_list_offset = 0;
1402
1403         Multi_list_select = -1;
1404
1405         if ( !(Game_mode & GM_MULTIPLAYER) ) 
1406                 return;
1407
1408         debrief_rebuild_player_list();
1409
1410         // switch stats display to this newly selected player
1411         set_player_stats(Multi_list[0].net_player_index);
1412         strcpy(Debrief_current_callsign, Multi_list[0].callsign);       
1413         Debrief_player = Player;
1414 }
1415
1416 void debrief_multi_list_scroll_up()
1417 {
1418         // if we're at the beginning of the list, don't do anything
1419         if(Multi_list_offset == 0){
1420                 gamesnd_play_iface(SND_GENERAL_FAIL);
1421                 return;
1422         }
1423
1424         // otherwise scroll up
1425         Multi_list_offset--;
1426         gamesnd_play_iface(SND_USER_SELECT);
1427 }
1428
1429 void debrief_multi_list_scroll_down()
1430 {               
1431         // if we can scroll down no further
1432         if(Multi_list_size < Debrief_multi_list_team_max_display[gr_screen.res]){
1433                 gamesnd_play_iface(SND_GENERAL_FAIL);
1434                 return;
1435         }
1436         if((Multi_list_offset + Debrief_multi_list_team_max_display[gr_screen.res]) >= Multi_list_size){
1437                 gamesnd_play_iface(SND_GENERAL_FAIL);
1438                 return;
1439         }
1440
1441         // otherwise scroll down
1442         Multi_list_offset++;
1443         gamesnd_play_iface(SND_USER_SELECT);
1444 }
1445
1446 // draw the connected net players
1447 void debrief_multi_list_draw()
1448 {
1449         int y, z, font_height,idx;
1450         char str[CALLSIGN_LEN+5];
1451         net_player *np;
1452         
1453         font_height = gr_get_font_height();     
1454
1455         // if we currently have no item picked, pick a reasonable one
1456         if((Multi_list_size >= 0) && (Multi_list_select == -1)){
1457                 // select the entry which corresponds to the local player
1458                 Multi_list_select = 0;                          
1459                 for(idx=0;idx<Multi_list_size;idx++){
1460                         if(Multi_list[idx].net_player_index == MY_NET_PLAYER_NUM){
1461                                 Multi_list_select = idx;
1462
1463                                 // switch stats display to this newly selected player
1464                                 set_player_stats(Multi_list[idx].net_player_index);
1465                                 strcpy(Debrief_current_callsign, Multi_list[idx].callsign);     
1466                                 Debrief_player = Net_players[Multi_list[idx].net_player_index].player;                          
1467                                 break;
1468                         }
1469                 }
1470         }
1471
1472         // draw the list itself
1473         y = 0;
1474         z = Multi_list_offset;
1475         while (y + font_height <= Debrief_list_coords[gr_screen.res][3]){
1476                 np = &Net_players[Multi_list[z].net_player_index];
1477
1478                 if (z >= Multi_list_size){
1479                         break;
1480                 }
1481                 // set the proper text color for the highlight
1482                 if(np->flags & NETINFO_FLAG_GAME_HOST){
1483                         if(Multi_list_select == z){
1484                                 gr_set_color_fast(&Color_text_active_hi);
1485                         } else {
1486                                 gr_set_color_fast(&Color_bright);
1487                         }
1488                 } else {
1489                         if(Multi_list_select == z){
1490                                 gr_set_color_fast(&Color_text_active);
1491                         } else {
1492                                 gr_set_color_fast(&Color_text_normal);
1493                         }
1494                 }
1495
1496                 // blit the proper indicator - skipping observers
1497                 if(!((np->flags & NETINFO_FLAG_OBSERVER) && !(np->flags & NETINFO_FLAG_OBS_PLAYER))){
1498                         if(Netgame.type_flags & NG_TYPE_TEAM){
1499                                 // team 0
1500                                 if(np->p_info.team == 0){
1501                                         // draw his "selected" icon
1502                                         if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1503                                                 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1504                                                 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1505                                         } 
1506                                         // draw his "normal" icon
1507                                         else if(Multi_common_icons[MICON_TEAM0] != -1){
1508                                                 gr_set_bitmap(Multi_common_icons[MICON_TEAM0]);
1509                                                 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1510                                         }                                       
1511                                 } else if(np->p_info.team == 1){
1512                                         // draw his "selected" icon
1513                                         if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM1_SELECT] != -1)){                                         
1514                                                 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]);
1515                                                 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1516                                         } 
1517                                         // draw his "normal" icon
1518                                         else if(Multi_common_icons[MICON_TEAM1] != -1){
1519                                                 gr_set_bitmap(Multi_common_icons[MICON_TEAM1]);
1520                                                 gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1521                                         }                                       
1522                                 }
1523                         } else {
1524                                 // draw the team 0 selected icon
1525                                 if(((np->state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (np->state == NETPLAYER_STATE_DEBRIEF_REPLAY)) && (Multi_common_icons[MICON_TEAM0_SELECT] != -1)){
1526                                         gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]);
1527                                         gr_bitmap(Debrief_list_coords[gr_screen.res][0], Debrief_list_coords[gr_screen.res][1] + y - 2);
1528                                 }
1529                         }
1530                 }
1531
1532                 strcpy(str,Multi_list[z].callsign);
1533                 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)){
1534                         strcat(str,XSTR( "(O)", 438));
1535                 }               
1536
1537                 // bli
1538                 gr_string(Debrief_list_coords[gr_screen.res][0] + MULTI_LIST_TEAM_OFFSET, Debrief_list_coords[gr_screen.res][1] + y, str);
1539
1540                 y += font_height;
1541                 z++;
1542         }
1543 }
1544
1545 void debrief_kick_selected_player()
1546 {
1547         if(Multi_list_select >= 0){
1548                 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
1549                 multi_kick_player(Multi_list[Multi_list_select].net_player_index);
1550         }
1551 }
1552
1553 // get optional mission popup text 
1554 void debrief_assemble_optional_mission_popup_text(char *buffer, char *mission_loop_desc)
1555 {
1556         Assert(buffer != NULL);
1557         // base message
1558
1559         if (mission_loop_desc == NULL) {
1560                 strcpy(buffer, XSTR("<No Mission Loop Description Available>", 1490));
1561                 mprintf(("No mission loop description avail"));
1562         } else {
1563                 strcpy(buffer, mission_loop_desc);
1564         }
1565
1566         strcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491));
1567 }
1568
1569 // what to do when the accept button is hit
1570 void debrief_accept(int ok_to_post_start_game_event)
1571 {
1572         int go_loop = 0;
1573
1574         if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) {
1575                 char *str;
1576                 int z;
1577
1578                 if (Game_mode & GM_MULTIPLAYER) {
1579                         return;
1580                 }
1581
1582                 if (Player_ship->team == TEAM_TRAITOR){
1583                         str = XSTR( "Your career is over, Traitor!  You can't accept new missions!", 439);
1584                 }/* else if (Cheats_enabled) {
1585                         str = XSTR( "You are a cheater.  You cannot accept this mission!", 440);
1586                 }*/ else {
1587                         str = XSTR( "You have failed this mission and cannot accept.  What do you you wish to do instead?", 441);
1588                 }
1589
1590                 z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str);
1591                 if (z == 2){
1592                         gameseq_post_event(GS_EVENT_START_BRIEFING);  // cycle back to briefing
1593                 } else if ( z == 1 ) {
1594                         gameseq_post_event(GS_EVENT_END_GAME);  // return to main hall, tossing stats
1595                 }
1596
1597                 return;
1598         }
1599
1600         Debrief_accepted = 1;
1601         // save mission stats
1602         if (Game_mode & GM_MULTIPLAYER) {
1603                 // note that multi_debrief_accept_hit() will handle all mission_campaign_* calls on its own
1604                 // as well as doing stats transfers, etc.
1605                 multi_debrief_accept_hit();
1606
1607         } else {
1608
1609                 int play_commit_sound = 1;
1610                 // only write the player's stats if he's accepted
1611
1612                 // if we are just playing a single mission, then don't do many of the things
1613                 // that need to be done.  Nothing much should happen when just playing a single
1614                 // mission that isn't in a campaign.
1615                 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1616
1617                         // check for possible mission loop
1618                         // check for (1) mission loop available, (2) dont have to repeat last mission
1619                         if(!(Game_mode & GM_MULTIPLAYER)){
1620                                 int cur = Campaign.current_mission;
1621                                 bool require_repeat_mission = (Campaign.current_mission == Campaign.next_mission);
1622                                 if (Campaign.missions[cur].has_mission_loop) {
1623                                         Assert(Campaign.loop_mission != CAMPAIGN_LOOP_MISSION_UNINITIALIZED);
1624                                 }
1625
1626                                 if ( (Campaign.missions[cur].has_mission_loop && (Campaign.loop_mission != -1)) && !require_repeat_mission ) {
1627                                         /*
1628                                         char buffer[512];
1629                                         debrief_assemble_optional_mission_popup_text(buffer, Campaign.missions[cur].mission_loop_desc);
1630
1631                                         int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer);
1632                                         if (choice == 1) {
1633                                                 Campaign.loop_enabled = 1;
1634                                                 Campaign.next_mission = Campaign.loop_mission;
1635                                         }
1636                                         */
1637                                         go_loop = 1;
1638                                 }
1639                         }                       
1640
1641                         // loopy loopy time
1642                         if (go_loop) {
1643                                 if(ok_to_post_start_game_event){
1644                                         gameseq_post_event(GS_EVENT_LOOP_BRIEF);
1645                                 } else {
1646                                         play_commit_sound = 0;
1647                                 }
1648                         }
1649                         // continue as normal
1650                         else {
1651                                 // end the mission
1652                                 mission_campaign_mission_over();
1653
1654                                 // check to see if we are out of the loop now
1655                                 if ( Campaign.next_mission == Campaign.loop_reentry ) {
1656                                         Campaign.loop_enabled = 0;
1657                                 }
1658
1659                                 // check if campaign is over
1660                                 if ( Campaign.next_mission == -1 ) {
1661         #if defined(FS2_DEMO) || defined(OEM_BUILD)
1662                                         gameseq_post_event(GS_EVENT_END_DEMO);
1663         #else
1664                                         gameseq_post_event(GS_EVENT_MAIN_MENU);
1665         #endif
1666                                 } else {
1667                                         if ( ok_to_post_start_game_event ) {
1668                                                 // CD CHECK
1669                                                 if(game_do_cd_mission_check(Game_current_mission_filename)){
1670                                                         gameseq_post_event(GS_EVENT_START_GAME);
1671                                                 } else {
1672                                                         gameseq_post_event(GS_EVENT_MAIN_MENU);
1673                                                 }
1674                                         } else {
1675                                                 play_commit_sound = 0;
1676                                         }
1677                                 }
1678                         }
1679                 } else {
1680                         gameseq_post_event(GS_EVENT_MAIN_MENU);
1681                 }
1682
1683                 if ( play_commit_sound ) {
1684                         gamesnd_play_iface(SND_COMMIT_PRESSED);
1685                 }
1686
1687                 game_flush();
1688         }
1689 }
1690
1691 void debrief_next_tab()
1692 {
1693         New_mode = Current_mode + 1;
1694         if (New_mode >= NUM_TABS)
1695                 New_mode = 0;
1696 }
1697
1698 void debrief_prev_tab()
1699 {
1700         New_mode = Current_mode - 1;
1701         if (New_mode < 0)
1702                 New_mode = NUM_TABS - 1;
1703 }
1704
1705 // --------------------------------------------------------------------------------------
1706 //      debrief_next_stage()
1707 //
1708 void debrief_next_stage()
1709 {
1710         if (Current_stage < Num_stages - 1) {
1711                 New_stage = Current_stage + 1;
1712                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1713
1714         } else
1715                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1716 }
1717
1718 // --------------------------------------------------------------------------------------
1719 //      debrief_prev_stage()
1720 //
1721 void debrief_prev_stage()
1722 {
1723         if (Current_stage) {
1724                 New_stage = Current_stage - 1;
1725                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1726
1727         } else
1728                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1729 }
1730
1731 // --------------------------------------------------------------------------------------
1732 //      debrief_first_stage()
1733 void debrief_first_stage()
1734 {
1735         if (Current_stage) {
1736                 New_stage = 0;
1737                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1738
1739         } else
1740                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1741 }
1742
1743 // --------------------------------------------------------------------------------------
1744 //      debrief_last_stage()
1745 void debrief_last_stage()
1746 {
1747         if (Current_stage != Num_stages - 1) {
1748                 New_stage = Num_stages - 1;
1749                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG);
1750
1751         } else
1752                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
1753 }
1754
1755 // draw what stage number the debriefing is on
1756 void debrief_render_stagenum()
1757 {
1758         int w;
1759         char buf[64];
1760         
1761         if (Num_stages < 2)
1762                 return;
1763                 
1764         sprintf(buf, XSTR( "%d of %d", 445), Current_stage + 1, Num_stages);
1765         gr_get_string_size(&w, NULL, buf);
1766         gr_set_color_fast(&Color_bright_blue);
1767         gr_string(Debrief_stage_info_coords[gr_screen.res][0] - w, Debrief_stage_info_coords[gr_screen.res][1], buf);
1768         gr_set_color_fast(&Color_white);
1769 }
1770
1771 // render the mission time at the specified y location
1772 void debrief_render_mission_time(int y_loc)
1773 {
1774         char time_str[30];
1775         
1776         game_format_time(Missiontime, time_str);
1777         gr_string(0, y_loc, XSTR( "Mission Time", 446));
1778         gr_string(Debrief_text_x2[gr_screen.res], y_loc, time_str);     
1779 }
1780
1781 // render out the debriefing text to the scroll window
1782 void debrief_render()
1783 {
1784         int y, z, font_height;
1785
1786         if ( Num_stages <= 0 )
1787                 return;
1788
1789         font_height = gr_get_font_height();
1790
1791         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]);
1792         y = 0;
1793         z = Text_offset;
1794         while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1795                 if (z >= Num_text_lines)
1796                         break;
1797
1798                 if (Text_type[z] == TEXT_TYPE_NORMAL)
1799                         gr_set_color_fast(&Color_white);
1800                 else
1801                         gr_set_color_fast(&Color_bright_red);
1802
1803                 if (Text[z])
1804                         gr_string(0, y, Text[z]);
1805
1806                 y += font_height;
1807                 z++;
1808         }
1809
1810         gr_reset_clip();
1811 }
1812
1813 // render out the stats info to the scroll window
1814 //
1815 void debrief_stats_render()
1816 {       
1817         int i, y, font_height;  
1818
1819         gr_set_color_fast(&Color_blue);
1820         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]);
1821         gr_string(0, 0, Debrief_current_callsign);
1822         font_height = gr_get_font_height();
1823         y = 30;
1824         
1825         switch ( Current_stage ) {
1826                 case DEBRIEF_MISSION_STATS:
1827                         i = Current_stage - 1;
1828                         if ( i < 0 )
1829                                 i = 0;
1830
1831                         gr_set_color_fast(&Color_white);
1832
1833                         // display mission completion time
1834                         debrief_render_mission_time(y);
1835
1836                         y += 20;
1837                         show_stats_label(i, 0, y, font_height);
1838                         show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1839                         break;
1840                 case DEBRIEF_ALLTIME_STATS:
1841                         i = Current_stage - 1;
1842                         if ( i < 0 )
1843                                 i = 0;
1844
1845                         gr_set_color_fast(&Color_white);
1846                         show_stats_label(i, 0, y, font_height);
1847                         show_stats_numbers(i, Debrief_text_x2[gr_screen.res], y, font_height);
1848                         break;
1849
1850                 case DEBRIEF_ALLTIME_KILLS:
1851                 case DEBRIEF_MISSION_KILLS:
1852                         gr_set_color_fast(&Color_white);
1853                         i = Text_offset;
1854                         while (y + font_height <= Debrief_text_wnd_coords[gr_screen.res][3]) {
1855                                 if (i >= Num_text_lines)
1856                                         break;
1857
1858                                 if (!i) {
1859                                         if ( Current_stage == DEBRIEF_MISSION_KILLS )
1860                                                 gr_printf(0, y, XSTR( "Mission Kills by Ship Type", 447));
1861                                         else
1862                                                 gr_printf(0, y, XSTR( "All-time Kills by Ship Type", 448));
1863
1864                                 } else if (i > 1) {
1865                                         gr_printf(0, y, "%s", Debrief_stats_kills[i - 2].text);
1866                                         gr_printf(Debrief_text_x2[gr_screen.res], y, "%d", Debrief_stats_kills[i - 2].num);
1867                                 }
1868
1869                                 y += font_height;
1870                                 i++;
1871                         }
1872
1873                         if (Num_text_lines == 2) {
1874                                 if ( Current_stage == DEBRIEF_MISSION_KILLS )
1875                                         gr_printf(0, y, XSTR( "(No ship kills this mission)", 449));
1876                                 else
1877                                         gr_printf(0, y, XSTR( "(No ship kills)", 450));
1878                         }
1879
1880                         break;
1881
1882                 default:
1883                         Int3();
1884                         break;
1885         } 
1886
1887         gr_reset_clip();
1888 }
1889
1890 // do action for when the replay button is pressed
1891 void debrief_replay_pressed()
1892 {       
1893         if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
1894                 int choice;
1895                 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));
1896
1897                 if (choice != 1){
1898                         return;
1899                 }
1900         }
1901
1902         gameseq_post_event(GS_EVENT_START_BRIEFING);            // take us to the briefing
1903         gamesnd_play_iface(SND_COMMIT_PRESSED);
1904 }
1905
1906 // -------------------------------------------------------------------
1907 // debrief_redraw_pressed_buttons()
1908 //
1909 // Redraw any debriefing buttons that are pressed down.  This function is needed
1910 // since we sometimes need to draw pressed buttons last to ensure the entire
1911 // button gets drawn (and not overlapped by other buttons)
1912 //
1913 void debrief_redraw_pressed_buttons()
1914 {
1915         int i;
1916         UI_BUTTON *b;
1917         
1918         for ( i=0; i<NUM_BUTTONS; i++ ) {
1919                 b = &Buttons[gr_screen.res][i].button;
1920                 // don't draw the recommendations button if we're in stats mode
1921                 if ( b->button_down() ) {
1922                         b->draw_forced(2);
1923                 }
1924         }
1925 }
1926
1927 // debrief specific button with hotspot 'i' has been pressed, so perform the associated action
1928 //
1929 void debrief_button_pressed(int num)
1930 {
1931         switch (num) {
1932                 case DEBRIEF_TAB:
1933                         Buttons[gr_screen.res][RECOMMENDATIONS].button.enable();                        
1934                         // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 0;
1935                         if (num != Current_mode){
1936                                 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1937                         }
1938                         New_mode = num;
1939                         break;
1940                 case STATS_TAB:
1941                         // Debrief_ui_window.use_hack_to_get_around_stupid_problem_flag = 1;                    // allows failure sound to be played
1942                         Buttons[gr_screen.res][RECOMMENDATIONS].button.disable();                       
1943                         if (num != Current_mode){
1944                                 gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
1945                         }
1946                         New_mode = num;
1947                         break;
1948
1949                 case TEXT_SCROLL_UP:
1950                         if (Text_offset) {
1951                                 Text_offset--;
1952                                 gamesnd_play_iface(SND_SCROLL);
1953                         } else {
1954                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1955                         }
1956                         break;
1957
1958                 case TEXT_SCROLL_DOWN:
1959                         if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
1960                                 Text_offset++;
1961                                 gamesnd_play_iface(SND_SCROLL);
1962                         } else {
1963                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1964                         }
1965                         break;
1966
1967                 case REPLAY_MISSION:
1968                         if(Game_mode & GM_MULTIPLAYER){
1969                                 multi_debrief_replay_hit();
1970                         } else {                        
1971                                 debrief_replay_pressed();       
1972                         }
1973                         break;
1974
1975                 case RECOMMENDATIONS:
1976                         gamesnd_play_iface(SND_USER_SELECT);
1977                         Recommend_active = !Recommend_active;
1978                         debrief_text_init();
1979                         break;
1980
1981                 case FIRST_STAGE:
1982                         debrief_first_stage();
1983                         break;
1984
1985                 case PREV_STAGE:
1986                         debrief_prev_stage();
1987                         break;
1988
1989                 case NEXT_STAGE:
1990                         debrief_next_stage();
1991                         break;
1992
1993                 case LAST_STAGE:
1994                         debrief_last_stage();
1995                         break;
1996
1997                 case HELP_BUTTON:
1998                         gamesnd_play_iface(SND_HELP_PRESSED);
1999                         launch_context_help();
2000                         break;
2001
2002                 case OPTIONS_BUTTON:
2003                         gamesnd_play_iface(SND_SWITCH_SCREENS);
2004                         gameseq_post_event( GS_EVENT_OPTIONS_MENU );
2005                         break;
2006
2007                 case ACCEPT_BUTTON:
2008                         debrief_accept();
2009                         break;
2010
2011                 case MEDALS_BUTTON:
2012                         gamesnd_play_iface(SND_SWITCH_SCREENS);
2013                         gameseq_post_event(GS_EVENT_VIEW_MEDALS);
2014                         break;
2015
2016                 case PLAYER_SCROLL_UP:
2017                         debrief_multi_list_scroll_up();
2018                         break;
2019
2020                 case PLAYER_SCROLL_DOWN:
2021                         debrief_multi_list_scroll_down();
2022                         break;
2023
2024                 case MULTI_PINFO_POPUP:
2025                         Debrief_should_show_popup = 1;
2026                         break;
2027
2028                 case MULTI_KICK:
2029                         debrief_kick_selected_player();
2030                         break;
2031         } // end swtich
2032 }
2033
2034 void debrief_setup_ship_kill_stats(int stage_num)
2035 {
2036         int i;
2037         ushort *kill_arr;
2038         debrief_stats_kill_info *kill_info;
2039
2040         Assert(Current_stage < DEBRIEF_NUM_STATS_PAGES);
2041         if ( Current_stage == DEBRIEF_MISSION_STATS || Current_stage == DEBRIEF_ALLTIME_STATS )
2042                 return;
2043
2044         Assert(Debrief_player != NULL);
2045
2046         // kill_ar points to an array of MAX_SHIP_TYPE ints
2047         if ( Current_stage == DEBRIEF_MISSION_KILLS ) {
2048                 kill_arr = Debrief_player->stats.m_okKills;
2049         } else {                
2050                 kill_arr = Debrief_player->stats.kills;
2051         }
2052
2053         Num_text_lines = 0;
2054         for ( i=0; i<MAX_SHIP_TYPES; i++ ) {
2055
2056                 // code used to add in mission kills, but the new system assumes that the player will accept, so
2057                 // all time stats already have mission stats added in.
2058                 if ( kill_arr[i] <= 0 ){
2059                         continue;
2060                 }
2061
2062
2063                 kill_info = &Debrief_stats_kills[Num_text_lines++];
2064
2065                 kill_info->num = kill_arr[i];
2066
2067                 strcpy(kill_info->text, Ship_info[i].name);
2068                 strcat(kill_info->text, NOX(":"));
2069         }
2070
2071         Num_text_lines += 2;
2072 }
2073
2074 // Iterate through the debriefing buttons, checking if they are pressed
2075 void debrief_check_buttons()
2076 {
2077         int i, y, z;
2078
2079         for ( i=0; i<NUM_BUTTONS; i++ ) {
2080                 if ( Buttons[gr_screen.res][i].button.pressed() ) {
2081                         debrief_button_pressed(i);
2082                 }
2083         }
2084
2085         if ( !(Game_mode & GM_MULTIPLAYER) ) 
2086                 return;
2087
2088         if (List_region.pressed()) {
2089                 List_region.get_mouse_pos(NULL, &y);
2090                 z = Multi_list_offset + y / gr_get_font_height();
2091                 if ((z >= 0) && (z < Multi_list_size)) {
2092                         // switch stats display to this newly selected player
2093                         set_player_stats(Multi_list[z].net_player_index);
2094                         strcpy(Debrief_current_callsign, Multi_list[z].callsign);
2095                         Debrief_player = Net_players[Multi_list[z].net_player_index].player;
2096                         Multi_list_select = z;
2097                         debrief_setup_ship_kill_stats(Current_stage);
2098                         gamesnd_play_iface(SND_USER_SELECT);                    
2099                 }
2100         }       
2101
2102         // if the player was double clicked on - we should popup a player info popup
2103         /*
2104         if (List_region.double_clicked()) {
2105                 Debrief_should_show_popup = 1;
2106         }
2107         */
2108 }
2109
2110 void debrief_text_stage_init(char *src, int type)
2111 {
2112         int i, n_lines, n_chars[MAX_DEBRIEF_LINES];
2113         char line[MAX_DEBRIEF_LINE_LEN];
2114         char *p_str[MAX_DEBRIEF_LINES];
2115
2116         n_lines = split_str(src, Debrief_text_wnd_coords[gr_screen.res][2], n_chars, p_str, MAX_DEBRIEF_LINES);
2117         Assert(n_lines >= 0);
2118
2119         // if you hit this, you proba   
2120         if(n_lines >= MAX_DEBRIEF_LINES){
2121                 Warning(LOCATION, "You have come close to the limit of debriefing lines, try adding more stages");      
2122         }
2123
2124         for ( i=0; i<n_lines; i++ ) {
2125                 Assert(n_chars[i] < MAX_DEBRIEF_LINE_LEN);
2126                 Assert(Num_text_lines < MAX_TOTAL_DEBRIEF_LINES);
2127                 strncpy(line, p_str[i], n_chars[i]);
2128                 line[n_chars[i]] = 0;
2129                 drop_white_space(line);
2130                 Text_type[Num_text_lines] = type;
2131                 Text[Num_text_lines++] = strdup(line);
2132         }
2133
2134         return;
2135 }
2136
2137 void debrief_free_text()
2138 {
2139         int i;
2140
2141         for (i=0; i<Num_debrief_lines; i++)
2142                 if (Text[i])
2143                         free(Text[i]);
2144
2145         Num_debrief_lines = 0;
2146 }
2147
2148 // setup the debriefing text lines for rendering
2149 void debrief_text_init()
2150 {
2151         int i, r_count = 0;
2152         char *src;
2153
2154         // release old text lines first
2155         debrief_free_text();
2156         Num_text_lines = Text_offset = 0;
2157
2158         if (Current_mode == DEBRIEF_TAB) {
2159                 for (i=0; i<Num_debrief_stages; i++) {
2160                         if (i)
2161                                 Text[Num_text_lines++] = NULL;  // add a blank line between stages
2162
2163                         src = Debrief_stages[i]->new_text;
2164                         if (src)
2165                                 debrief_text_stage_init(src, TEXT_TYPE_NORMAL);
2166
2167                         if (Recommend_active) {
2168                                 src = Debrief_stages[i]->new_recommendation_text;
2169                                 if (!src && (i == Num_debrief_stages - 1) && !r_count)
2170                                         src = XSTR( "We have no recommendations for you.", 1054);
2171
2172                                 if (src) {
2173                                         Text[Num_text_lines++] = NULL;
2174                                         debrief_text_stage_init(src, TEXT_TYPE_RECOMMENDATION);
2175                                         r_count++;
2176                                 }
2177                         }
2178                 }
2179
2180                 Num_debrief_lines = Num_text_lines;
2181                 return;
2182         }
2183
2184         // not in debriefing mode, must be in stats mode
2185         Num_text_lines = 0;
2186         debrief_setup_ship_kill_stats(Current_stage);
2187 }
2188
2189
2190 // --------------------------------------------------------------------------------------
2191 //
2192 void debrief_init()
2193 {
2194         Assert(!Debrief_inited);
2195 //      Campaign.loop_enabled = 0;
2196         Campaign.loop_mission = CAMPAIGN_LOOP_MISSION_UNINITIALIZED;
2197
2198         // set up the right briefing for this guy
2199         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
2200                 Debriefing = &Debriefings[Net_player->p_info.team];
2201         } else {
2202                 Debriefing = &Debriefings[0];                   
2203         }
2204
2205         // no longer is mission
2206         Game_mode &= ~(GM_IN_MISSION);  
2207
2208         game_flush();
2209         Current_mode = -1;
2210         New_mode = DEBRIEF_TAB;
2211         Recommend_active = Award_active = 0;
2212         Current_stage = 0;
2213
2214         Current_stage = -1;
2215         New_stage = 0;
2216         Debrief_cue_voice = 0;
2217         Num_text_lines = Num_debrief_lines = 0;
2218         Debrief_first_voice_flag = 1;
2219
2220         Debrief_multi_voice_loaded = 0;
2221
2222         if ( (Game_mode & GM_CAMPAIGN_MODE) && ( !MULTIPLAYER_CLIENT )  ) {
2223                 // MUST store goals and events first - may be used to evaluate next mission
2224                 // store goals and events
2225                 mission_campaign_store_goals_and_events();
2226
2227                 // evaluate next mission
2228                 mission_campaign_eval_next_mission();
2229         }
2230
2231         // call traitor init before calling scoring_level_close.  traitor init will essentially nullify
2232         // any stats
2233         if ( !(Game_mode & GM_MULTIPLAYER) ) {  // only do for single player
2234                 debrief_traitor_init();                                 // initialize data needed if player becomes traitor.
2235         }
2236
2237         // call scoring level close for my stats.  Needed for award_init.  The stats will
2238         // be backed out if used chooses to replace them.
2239         scoring_level_close();
2240
2241         debrief_ui_init();  // init UI items
2242         debrief_award_init();
2243         show_stats_init();
2244         debrief_voice_init();
2245         debrief_multi_list_init();
2246 //      rank_bitmaps_clear();
2247 //      rank_bitmaps_load();
2248
2249         strcpy(Debrief_current_callsign, Player->callsign);
2250         Debrief_player = Player;
2251 //      Debrief_current_net_player_index = debrief_multi_list[0].net_player_index;
2252
2253         // set up the Debrief_stages[] and Recommendations[] arrays.  Only do the following stuff
2254         // for non-clients (i.e. single and game server).  Multiplayer clients will get their debriefing
2255         // info directly from the server.
2256         if ( !MULTIPLAYER_CLIENT ) {
2257                 debrief_set_stages_and_multi_stuff();
2258
2259                 if ( Num_debrief_stages <= 0 ) {
2260                         Num_debrief_stages = 0;
2261                 } else {
2262                         debrief_voice_load_all();
2263                 }
2264         } else {
2265                 // multiplayer client may have already received their debriefing info.  If they have not,
2266                 // then set the num debrief stages to 0
2267                 if ( !Debrief_multi_stages_loaded ) {
2268                         Num_debrief_stages = 0;
2269                 }
2270         }
2271
2272         /*
2273         if (mission_evaluate_primary_goals() == PRIMARY_GOALS_COMPLETE) {
2274                 common_music_init(SCORE_DEBRIEF_SUCCESS);
2275         } else {
2276                 common_music_init(SCORE_DEBRIEF_FAIL);
2277         }
2278         */
2279
2280         // start up the appropriate music
2281         if (Campaign.next_mission == Campaign.current_mission) {
2282                 // you failed the mission because you suck, so you get the suck music
2283                 common_music_init(SCORE_DEBRIEF_FAIL);
2284         } else if (mission_goals_met()) {
2285                 // you completed all primaries and secondaries, thus you are a stud boy and you get stud boy music
2286                 common_music_init(SCORE_DEBRIEF_SUCCESS);
2287         } else {
2288                 // you somehow passed the mission, so you get a little something for your efforts.
2289                 common_music_init(SCORE_DEBRIEF_AVERAGE);
2290         }
2291
2292         if (Campaign.next_mission == Campaign.current_mission) {
2293                 // better luck next time, increase his retries
2294                 Player->failures_this_session++;
2295         } else { 
2296                 // clear his retries info regardless of whether or not he accepts
2297                 Player->failures_this_session = 0;
2298         }
2299
2300         if (Game_mode & GM_MULTIPLAYER) {
2301                 multi_debrief_init();
2302
2303                 // if i'm not the host of the game, disable the multi kick button
2304                 if (!(Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
2305                         Buttons[gr_screen.res][MULTI_KICK].button.disable();
2306                 }
2307         } else {
2308                 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.disable();
2309                 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.disable();
2310                 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.disable();
2311                 Buttons[gr_screen.res][MULTI_KICK].button.disable();
2312                 Buttons[gr_screen.res][PLAYER_SCROLL_UP].button.hide();
2313                 Buttons[gr_screen.res][PLAYER_SCROLL_DOWN].button.hide();
2314                 Buttons[gr_screen.res][MULTI_PINFO_POPUP].button.hide();                
2315                 Buttons[gr_screen.res][MULTI_KICK].button.hide();
2316         }
2317
2318         if (!Award_active) {
2319                 Buttons[gr_screen.res][MEDALS_BUTTON].button.disable();
2320                 Buttons[gr_screen.res][MEDALS_BUTTON].button.hide();
2321         }
2322
2323         Debrief_skip_popup_already_shown = 0;
2324
2325         Debrief_inited = 1;
2326 }
2327
2328 // --------------------------------------------------------------------------------------
2329 //      debrief_close()
2330 void debrief_close()
2331 {
2332         int i, idx;
2333
2334         Assert(Debrief_inited);
2335
2336         // if the mission wasn't accepted, clear out my stats
2337         // we need to evaluate a little differently for multiplayer since the conditions for "accepting" 
2338         // are a little bit different
2339         if (Game_mode & GM_MULTIPLAYER) {
2340                 // if stats weren't accepted, backout my own stats
2341                 if (multi_debrief_stats_accept_code() != 1) {
2342                         if(MULTIPLAYER_MASTER){
2343                                 for(idx=0; idx<MAX_PLAYERS; idx++){
2344                                         if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
2345                                                 scoring_backout_accept(&Net_players[idx].player->stats);
2346                                         }
2347                                 }
2348                         } else {
2349                                 scoring_backout_accept( &Player->stats );
2350                         }
2351                 }
2352         } else {
2353                 // single player
2354                 if( !Debrief_accepted || !(Game_mode & GM_CAMPAIGN_MODE) ){
2355                         scoring_backout_accept( &Player->stats );
2356                 }
2357         }
2358
2359         // if dude passed the misson and accepted, reset his show skip popup flag
2360         if (Debrief_accepted) {
2361                 Player->show_skip_popup = 1;
2362         }
2363
2364         if (Num_debrief_lines) {
2365                 for (i=0; i<Num_debrief_lines; i++){
2366                         if (Text[i]){
2367                                 free(Text[i]);
2368                         }
2369                 }
2370         }
2371
2372         // unload the overlay bitmap
2373 //      help_overlay_unload(DEBRIEFING_OVERLAY);
2374
2375         // clear out award text 
2376         Debrief_award_text_num_lines = 0;
2377
2378         debrief_voice_unload_all();
2379         common_music_close();
2380         chatbox_close();
2381
2382 //      rank_bitmaps_release();
2383
2384         // unload bitmaps
2385         if (Background_bitmap >= 0){
2386                 bm_unload(Background_bitmap);
2387         }
2388
2389         if (Award_bg_bitmap >= 0){
2390                 bm_unload(Award_bg_bitmap);
2391         }
2392
2393         if (Rank_bitmap >= 0){
2394                 bm_unload(Rank_bitmap);
2395         }
2396
2397         if (Medal_bitmap >= 0){
2398                 bm_unload(Medal_bitmap);
2399         }
2400
2401         if (Badge_bitmap >= 0){
2402                 bm_unload(Badge_bitmap);
2403         }
2404
2405         if (Wings_bitmap >= 0) {
2406                 bm_unload(Wings_bitmap);
2407         }
2408         
2409         if (Crest_bitmap >= 0) {
2410                 bm_unload(Crest_bitmap);
2411         }
2412
2413         Debrief_ui_window.destroy();
2414         common_free_interface_palette();                // restore game palette
2415         show_stats_close();
2416
2417         if (Game_mode & GM_MULTIPLAYER){
2418                 multi_debrief_close();
2419         }
2420
2421         game_flush();
2422
2423         Debrief_inited = 0;
2424 }
2425
2426 // handle keypresses in debriefing
2427 void debrief_do_keys(int new_k)
2428 {
2429         switch (new_k) {
2430                 case KEY_TAB:
2431                         debrief_next_tab();
2432                         break;
2433
2434                 case KEY_SHIFTED | KEY_TAB:
2435                         debrief_prev_tab();
2436                         break;
2437
2438                 case KEY_ESC: {
2439                         int pf_flags;
2440                         int choice;
2441
2442                         // multiplayer accept popup is a little bit different
2443                         if (Game_mode & GM_MULTIPLAYER) {               
2444                                 multi_debrief_esc_hit();
2445
2446                         // display the normal debrief popup
2447                         } else {
2448                                 if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2449                                         pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
2450                                         choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456));
2451                                         if (choice == 1) {  // accept and continue on
2452                                                 debrief_accept(0);
2453                                                 gameseq_post_event(GS_EVENT_MAIN_MENU);
2454                                         }
2455
2456                                         if (choice < 1)
2457                                                 break;
2458
2459                                 } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) {
2460                                         // need to popup saying that mission was a failure and must be replayed
2461                                         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));
2462                                         if (choice <= 0)
2463                                                 break;
2464                                 }
2465
2466                                 // Return to Main Hall
2467                                 gameseq_post_event(GS_EVENT_END_GAME);
2468                         }
2469                 }
2470
2471                 default:
2472                         break;
2473         }       // end switch
2474 }
2475
2476 // uuuuuugly
2477 void debrief_draw_award_text()
2478 {
2479         int start_y, curr_y, i, x, sw;
2480         int fh = gr_get_font_height();
2481         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];
2482
2483         // vertically centered within field
2484         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);
2485         curr_y = start_y;
2486
2487         // draw the strings
2488         for (i=0; i<Debrief_award_text_num_lines; i++) {
2489                 gr_get_string_size(&sw, NULL, Debrief_award_text[i]);
2490                 x = (Medal_bitmap < 0) ? (Debrief_award_text_coords[gr_screen.res][0] + (field_width - sw) / 2) : Debrief_award_text_coords[gr_screen.res][0];
2491                 if (i==AWARD_TEXT_MAX_LINES-1) x += 7;                          // hack because of the shape of the box
2492                 gr_set_color_fast(&Color_white);
2493                 gr_string(x, curr_y, Debrief_award_text[i]);
2494
2495                 // adjust y pos, including a little extra between the "pairs"
2496                 curr_y += fh;
2497                 if ((i == 1) || (i == 3)) { 
2498                         curr_y += ((gr_screen.res == GR_640) ? 2 : 6);
2499                 }
2500         }
2501 }
2502
2503 // clears out text array so we dont have old award text showing up on new awards.
2504 void debrief_award_text_clear() {
2505         int i;
2506         
2507         Debrief_award_text_num_lines = 0;
2508         for (i=0; i<AWARD_TEXT_MAX_LINES; i++) {
2509                 //Debrief_award_text[i][0] = 0;
2510                 memset(Debrief_award_text[i], 0, sizeof(char)*AWARD_TEXT_MAX_LINE_LENGTH);
2511         }
2512 }
2513
2514 // this is the nastiest code I have ever written.  if you are modifying this, i feel bad for you.
2515 void debrief_add_award_text(char *str)
2516 {
2517         Assert(Debrief_award_text_num_lines <= AWARD_TEXT_MAX_LINES);
2518         if (Debrief_award_text_num_lines > AWARD_TEXT_MAX_LINES) {
2519                 return;
2520         }
2521
2522         char *line2;
2523         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];
2524
2525         // copy in the line
2526         strcpy(Debrief_award_text[Debrief_award_text_num_lines], str);  
2527
2528         // maybe translate for displaying
2529         if (Lcl_gr) {
2530                 medals_translate_name(Debrief_award_text[Debrief_award_text_num_lines], AWARD_TEXT_MAX_LINE_LENGTH);
2531         }
2532
2533         Debrief_award_text_num_lines++;
2534
2535         // if its too long, split once ONLY
2536         // assumes text isnt > 2 lines, but this is a safe assumption due to the char limits of the ranks/badges/etc
2537         if (Debrief_award_text_num_lines < AWARD_TEXT_MAX_LINES) {
2538                 line2 = split_str_once(Debrief_award_text[Debrief_award_text_num_lines-1], field_width);
2539                 if (line2 != NULL) {
2540                         sprintf(Debrief_award_text[Debrief_award_text_num_lines], " %s", line2);  // indent a space
2541                 }
2542                 Debrief_award_text_num_lines++;         // leave blank line even if it all fits into 1
2543         }
2544 }
2545
2546 //      called once per frame to drive all the input reading and rendering
2547 void debrief_do_frame(float frametime)
2548 {
2549         int k=0, new_k=0;
2550         char *please_wait_str = XSTR("Please Wait", 1242);
2551         int str_w, str_h;
2552         char buf[256];
2553
2554         Assert(Debrief_inited); 
2555
2556         // first thing is to load the files
2557         if ( MULTIPLAYER_CLIENT && !Debrief_multi_stages_loaded ) {
2558                 // draw the background, etc
2559                 GR_MAYBE_CLEAR_RES(Background_bitmap);
2560                 if (Background_bitmap >= 0) {
2561                         gr_set_bitmap(Background_bitmap);
2562                         gr_bitmap(0, 0);
2563                 }
2564
2565                 Debrief_ui_window.draw();
2566                 chatbox_render();
2567                 if ( Debrief_multi_loading_bitmap > -1 ){
2568                         gr_set_bitmap(Debrief_multi_loading_bitmap);            
2569                         gr_bitmap( Please_wait_coords[gr_screen.res][0], Please_wait_coords[gr_screen.res][1] );
2570                 }
2571
2572                 // draw "Please Wait"           
2573                 gr_set_color_fast(&Color_normal);
2574                 gr_set_font(FONT2);
2575                 gr_get_string_size(&str_w, &str_h, please_wait_str);
2576                 gr_string((gr_screen.max_w - str_w) / 2, (gr_screen.max_h - str_h) / 2, please_wait_str);
2577                 gr_set_font(FONT1);
2578
2579                 gr_flip();
2580
2581                 // make sure we run the debrief do frame
2582                 if (Game_mode & GM_MULTIPLAYER) {
2583                         multi_debrief_do_frame();
2584                 }
2585
2586                 // esc pressed?         
2587                 os_poll();      
2588                 int keypress = game_check_key();        
2589                 if(keypress == KEY_ESC){
2590                         // popup to leave
2591                         multi_quit_game(PROMPT_CLIENT);
2592                 }
2593
2594                 return;
2595         }
2596
2597         // if multiplayer client, and not loaded voice, then load it
2598         if ( MULTIPLAYER_CLIENT && !Debrief_multi_voice_loaded ) {
2599                 debrief_multi_fixup_stages();
2600                 debrief_voice_load_all();
2601                 Debrief_multi_voice_loaded = 1;
2602         }
2603
2604         if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2605                 Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
2606                 Debrief_ui_window.set_ignore_gadgets(1);
2607         }
2608
2609         k = chatbox_process();
2610         if ( Game_mode & GM_NORMAL ) {
2611                 new_k = Debrief_ui_window.process(k);
2612         } else {
2613                 new_k = Debrief_ui_window.process(k, 0);
2614         }
2615
2616         if ( (k > 0) || (new_k > 0) || B1_JUST_RELEASED ) {
2617                 if ( help_overlay_active(DEBRIEFING_OVERLAY) ) {
2618                         help_overlay_set_state(DEBRIEFING_OVERLAY, 0);
2619                         Debrief_ui_window.set_ignore_gadgets(0);
2620                         k = 0;
2621                         new_k = 0;
2622                 }
2623         }
2624
2625         if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2626                 Debrief_ui_window.set_ignore_gadgets(0);
2627         }
2628
2629         // don't show pilot info popup by default
2630         Debrief_should_show_popup = 0;
2631
2632         // see if the mode has changed and handle it if so.
2633         if ( Current_mode != New_mode ) {
2634                 debrief_voice_stop();
2635                 Current_mode = New_mode;
2636                 Current_stage = -1;
2637                 New_stage = 0;
2638                 if (New_mode == DEBRIEF_TAB) {
2639                         Num_stages = 1;
2640                         Debrief_cue_voice = 0;
2641                         Stage_voice = -1;
2642                         if (Debrief_first_voice_flag) {
2643                                 Debrief_cue_voice = timestamp(DEBRIEF_VOICE_DELAY * 3);
2644                                 Debrief_first_voice_flag = 0;
2645                         }
2646                 } else {
2647                         Num_stages = DEBRIEF_NUM_STATS_PAGES;
2648                 }
2649         }
2650
2651         if ((Num_stages > 0) &&  (New_stage != Current_stage)) {
2652                 Current_stage = New_stage;
2653                 debrief_text_init();
2654         }
2655
2656         debrief_voice_play();
2657         common_music_do();
2658
2659         if (Game_mode & GM_MULTIPLAYER) {
2660                 multi_debrief_do_frame();
2661         }
2662
2663         // Now do all the rendering for the frame
2664         GR_MAYBE_CLEAR_RES(Background_bitmap);
2665         if (Background_bitmap >= 0) {
2666                 gr_set_bitmap(Background_bitmap);
2667                 gr_bitmap(0, 0);
2668         } 
2669
2670         // draw the damn awarded stuff, G
2671         if ( Award_active && (Award_bg_bitmap >= 0) ) {
2672                 gr_set_bitmap(Award_bg_bitmap);
2673                 gr_bitmap(Debrief_award_wnd_coords[gr_screen.res][0], Debrief_award_wnd_coords[gr_screen.res][1]);
2674                 if (Rank_bitmap >= 0) {
2675                         gr_set_bitmap(Rank_bitmap);
2676                         gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2677                 }
2678
2679                 if (Medal_bitmap >= 0) {
2680                         gr_set_bitmap(Medal_bitmap);
2681                         gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2682                 }
2683
2684                 if (Badge_bitmap >= 0) {
2685                         gr_set_bitmap(Badge_bitmap);
2686                         gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2687                 }
2688
2689                 if (Wings_bitmap >= 0) {
2690                         gr_set_bitmap(Wings_bitmap);
2691                         gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2692                 }
2693
2694                 if (Crest_bitmap >= 0) {
2695                         gr_set_bitmap(Crest_bitmap);
2696                         gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2697                 }
2698
2699                 //  draw medal/badge/rank labels
2700                 debrief_draw_award_text();
2701
2702 /*              if (Rank_text_bitmap >= 0) {
2703                         gr_set_bitmap(Rank_text_bitmap);
2704                         gr_bitmap(Debrief_award_coords[gr_screen.res][0], Debrief_award_coords[gr_screen.res][1]);
2705                 }
2706
2707         
2708                 if (Medal_text_bitmap >= 0) {
2709                         gr_set_bitmap(Medal_text_bitmap);
2710                         gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2711                 }
2712
2713                 if (Badge_text_bitmap >= 0) {
2714                         gr_set_bitmap(Badge_text_bitmap);
2715                         gr_bitmap(Debrief_award_text_coords[gr_screen.res][0], Debrief_award_text_coords[gr_screen.res][1]);
2716                 }
2717 */
2718         }
2719         
2720         Debrief_ui_window.draw();
2721         debrief_redraw_pressed_buttons();
2722         Buttons[gr_screen.res][Current_mode].button.draw_forced(2);
2723         if (Recommend_active && (Current_mode != STATS_TAB)) {
2724                 Buttons[gr_screen.res][RECOMMENDATIONS].button.draw_forced(2);
2725         }
2726
2727         // draw the title of the mission
2728         gr_set_color_fast(&Color_bright_white);
2729         strcpy(buf, The_mission.name);
2730         gr_force_fit_string(buf, 255, Debrief_title_coords[gr_screen.res][2]);
2731         gr_string(Debrief_title_coords[gr_screen.res][0], Debrief_title_coords[gr_screen.res][1], buf); 
2732
2733 #if !defined(NDEBUG) || defined(INTERPLAYQA)
2734         gr_set_color_fast(&Color_normal);
2735         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);
2736 #endif
2737
2738         // draw the screen-specific text
2739         switch (Current_mode) {
2740                 case DEBRIEF_TAB:
2741                         if ( Num_debrief_stages <= 0 ) {
2742                                 gr_set_color_fast(&Color_white);
2743                                 Assert( Game_current_mission_filename != NULL );
2744                                 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);
2745
2746                         } else {
2747                                 debrief_render();
2748                         }
2749
2750                         break;
2751
2752                 case STATS_TAB:
2753                         debrief_stats_render();
2754                         break;
2755         } // end switch
2756
2757         if (Text_offset + Debrief_text_wnd_coords[gr_screen.res][3] / gr_get_font_height() < Num_text_lines) {
2758                 int w;
2759
2760                 gr_set_color_fast(&Color_red);
2761                 gr_get_string_size(&w, NULL, XSTR( "More", 459));
2762                 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));
2763         }
2764
2765         debrief_render_stagenum();
2766         debrief_multi_list_draw();
2767
2768         // render some extra stuff in multiplayer
2769         if (Game_mode & GM_MULTIPLAYER) {
2770                 // render the chatbox last
2771                 chatbox_render();
2772
2773                 // draw tooltips
2774                 Debrief_ui_window.draw_tooltip();
2775
2776                 // render the status indicator for the voice system
2777                 multi_common_voice_display_status();
2778         }
2779
2780         // AL 3-6-98: Needed to move key reading here, since popups are launched from this code, and we don't
2781         //                                want to include the mouse pointer which is drawn in the flip
2782
2783         if ( !help_overlay_active(DEBRIEFING_OVERLAY) ) {
2784                 debrief_check_buttons();
2785                 debrief_do_keys(new_k); 
2786         }
2787
2788         // blit help overlay if active
2789         help_overlay_maybe_blit(DEBRIEFING_OVERLAY);
2790
2791         gr_flip();
2792
2793         // dont let dude skip 3-09.  hack.      
2794         if(Game_mode & GM_CAMPAIGN_MODE){
2795                 if((Campaign.current_mission >= 0) && (Campaign.current_mission < MAX_CAMPAIGN_MISSIONS)){
2796                         if ((Campaign.missions[Campaign.current_mission].name != NULL) && !stricmp(Campaign.missions[Campaign.current_mission].name, "sm3-09.fs2")) {
2797                                 Debrief_skip_popup_already_shown = 1;
2798                         }
2799                 }
2800         }       
2801
2802         // maybe show skip mission popup
2803         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)) {
2804                 int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473),
2805                                                                                                  XSTR("Advance To The Next Mission", 1474),
2806                                                                                                  XSTR("Don't Show Me This Again", 1475),
2807                                                                                                  XSTR("You have failed this mission five times.  If you like, you may advance to the next mission.", 1472) );
2808                 switch (popup_choice) {
2809                 case 0:
2810                         // stay on this mission, so proceed to normal debrief
2811                         // in other words, do nothing.
2812                         break;
2813                 case 1:
2814                         // skip this mission
2815                         mission_campaign_skip_to_next();
2816                         gameseq_post_event(GS_EVENT_START_GAME);
2817                         break;
2818                 case 2:
2819                         // dont show this again
2820                         Player->show_skip_popup = 0;
2821                         break;
2822                 }
2823
2824                 Debrief_skip_popup_already_shown = 1;
2825         }
2826
2827         // check to see if we should be showing a pilot info popup in multiplayer (if a guy was double clicked)
2828         if ((Game_mode & GM_MULTIPLAYER) && Debrief_should_show_popup) {
2829                 Assert((Multi_list_select >= 0) && (Multi_list_select < Multi_list_size));
2830                 multi_pinfo_popup(&Net_players[Multi_list[Multi_list_select].net_player_index]);
2831
2832                 Debrief_should_show_popup = 0;
2833         }
2834 }
2835
2836 void debrief_rebuild_player_list()
2837 {
2838         int i;
2839         net_player *np;
2840         debrief_multi_list_info *list;
2841
2842         Multi_list_size = 0;  // number of net players to choose from
2843
2844         for ( i=0; i<MAX_PLAYERS; i++ ) {
2845                 np = &Net_players[i];
2846                 // remember not to include the standalone.
2847                 if ( MULTI_CONNECTED((*np)) && !MULTI_STANDALONE((*np))){
2848                         list = &Multi_list[Multi_list_size++];
2849                         list->net_player_index = i;
2850                         strcpy(list->callsign, np->player->callsign);
2851                         
2852                         // make sure to leave some room to blit the team indicator
2853                         gr_force_fit_string(list->callsign, CALLSIGN_LEN - 1, Debrief_list_coords[gr_screen.res][2] - MULTI_LIST_TEAM_OFFSET);
2854                 }
2855         } // end for
2856 }
2857
2858 void debrief_handle_player_drop()
2859 {
2860         debrief_rebuild_player_list();
2861 }
2862
2863 void debrief_disable_accept()
2864 {
2865 }
2866