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