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