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