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