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