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