]> icculus.org git repositories - taylor/freespace2.git/blob - src/mission/missionbriefcommon.cpp
GCC 3.4 fixes.
[taylor/freespace2.git] / src / mission / missionbriefcommon.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/Mission/MissionBriefCommon.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module for briefing code common to FreeSpace and FRED
16  *
17  * $Log$
18  * Revision 1.11  2004/09/20 01:31:44  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.10  2004/07/04 11:39:06  taylor
22  * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
23  *
24  * Revision 1.9  2003/06/11 18:30:32  taylor
25  * plug memory leaks
26  *
27  * Revision 1.8  2003/06/03 04:00:40  taylor
28  * Polish language support (Janusz Dziemidowicz)
29  *
30  * Revision 1.7  2003/05/25 02:30:42  taylor
31  * Freespace 1 support
32  *
33  * Revision 1.6  2002/06/17 06:33:09  relnev
34  * ryan's struct patch for gcc 2.95
35  *
36  * Revision 1.5  2002/06/09 04:41:22  relnev
37  * added copyright header
38  *
39  * Revision 1.4  2002/06/02 04:26:34  relnev
40  * warning cleanup
41  *
42  * Revision 1.3  2002/06/01 07:12:33  relnev
43  * a few NDEBUG updates.
44  *
45  * removed a few warnings.
46  *
47  * Revision 1.2  2002/05/07 03:16:46  theoddone33
48  * The Great Newline Fix
49  *
50  * Revision 1.1.1.1  2002/05/03 03:28:10  root
51  * Initial import.
52  *
53  * 
54  * 19    11/02/99 3:23p Jefff
55  * translate briefing icon names
56  * 
57  * 18    9/09/99 9:44a Jefff
58  * doh, fixed reversed brief text color thingy.  i am stoopid.
59  * 
60  * 17    9/08/99 11:14a Jefff
61  * toned down hostile/friendly colors in briefing text
62  * 
63  * 16    9/07/99 12:20p Mikeb
64  * return pos of briefing icon even it does not fit on screen.
65  * 
66  * 15    9/03/99 1:32a Dave
67  * CD checking by act. Added support to play 2 cutscenes in a row
68  * seamlessly. Fixed super low level cfile bug related to files in the
69  * root directory of a CD. Added cheat code to set campaign mission # in
70  * main hall.
71  * 
72  * 14    8/10/99 7:28p Jefff
73  * shuffled some text around
74  * 
75  * 13    7/30/99 3:05p Jefff
76  * Fixed briefing icon fades -- in and out were reversed.
77  * 
78  * 12    7/26/99 1:52p Mikeb
79  * Fixed strange briefing bug where a NULL wasn't being checked for when
80  * copying briefing stage text. Odd.
81  * 
82  * 11    7/24/99 6:15p Jefff
83  * moved "stage x of y" text in multiplayer mode so its not covered by the
84  * chatbox
85  * 
86  * 10    7/20/99 7:09p Jefff
87  * briefing text occupies full window in 1024x768
88  * 
89  * 9     7/09/99 5:54p Dave
90  * Seperated cruiser types into individual types. Added tons of new
91  * briefing icons. Campaign screen.
92  * 
93  * 8     6/29/99 7:39p Dave
94  * Lots of small bug fixes.
95  * 
96  * 7     2/05/99 7:19p Neilk
97  * Removed black part from mission screen, fixed info text coords
98  * 
99  * 6     1/29/99 4:17p Dave
100  * New interface screens.
101  * 
102  * 5     12/18/98 1:13a Dave
103  * Rough 1024x768 support for Direct3D. Proper detection and usage through
104  * the launcher.
105  * 
106  * 4     10/23/98 3:51p Dave
107  * Full support for tstrings.tbl and foreign languages. All that remains
108  * is to make it active in Fred.
109  * 
110  * 3     10/13/98 9:28a Dave
111  * Started neatening up freespace.h. Many variables renamed and
112  * reorganized. Added AlphaColors.[h,cpp]
113  * 
114  * 2     10/07/98 10:53a Dave
115  * Initial checkin.
116  * 
117  * 1     10/07/98 10:49a Dave
118  * 
119  * 122   6/09/98 10:31a Hoffoss
120  * Created index numbers for all xstr() references.  Any new xstr() stuff
121  * added from here on out should be added to the end if the list.  The
122  * current list count can be found in FreeSpace.cpp (search for
123  * XSTR_SIZE).
124  * 
125  * 121   6/05/98 9:54a Lawrance
126  * OEM changes
127  * 
128  * 120   6/01/98 11:43a John
129  * JAS & MK:  Classified all strings for localization.
130  * 
131  * 119   5/23/98 10:38p Lawrance
132  * Avoid doing a cfile refresh when running debug
133  * 
134  * 118   5/23/98 6:49p Lawrance
135  * Fix problems with refreshing the file list when a CD is inserted
136  * 
137  * 117   5/21/98 6:57p Lawrance
138  * Don't prompt for the CD if voice not found
139  * 
140  * 116   5/21/98 12:35a Lawrance
141  * Tweak how CD is checked for
142  * 
143  * 115   5/12/98 11:46a John
144  * Changed the way the "glowing movement" type text draw.   Use Hoffoss's
145  * gr_get_string_size optional length parameter to determine length of
146  * string which accounts for kerning on the last character and then I only
147  * draw each character only once.
148  * 
149  * 114   5/08/98 5:32p Lawrance
150  * prompt for CD if can't load animations or voice
151  * 
152  * 113   5/06/98 5:30p John
153  * Removed unused cfilearchiver.  Removed/replaced some unused/little used
154  * graphics functions, namely gradient_h and _v and pixel_sp.   Put in new
155  * DirectX header files and libs that fixed the Direct3D alpha blending
156  * problems.
157  * 
158  * 112   4/27/98 9:08p Allender
159  * fix the debriefing stage problems when clients get to screen long after
160  * server
161  * 
162  * 111   4/25/98 3:49p Lawrance
163  * Save briefing auto-advance pref
164  * 
165  * 110   4/20/98 3:53p Lawrance
166  * Fix various bugs with auto-advancing through briefings.
167  * 
168  * $NoKeywords: $
169  */
170
171 #include "freespace.h"
172 #include "ship.h"
173 #include "key.h"
174 #include "2d.h"
175 #include "3d.h"
176 #include "line.h"
177 #include "timer.h"
178 #include "math.h"
179 #include "linklist.h"
180 #include "mouse.h"
181 #include "hud.h"
182 #include "osapi.h"
183 #include "object.h"
184 #include "multi.h"
185 #include "bmpman.h"
186 #include "missionbrief.h"
187 #include "missiongrid.h"
188 #include "missionbriefcommon.h"
189 #include "animplay.h"
190 #include "fvi.h"
191 #include "float.h"
192 #include "gamesnd.h"
193 #include "cmdline.h"
194 #include "parselo.h"
195 #include "audiostr.h"
196 #include "missioncmdbrief.h"
197 #include "missiondebrief.h"
198 #include "alphacolors.h"
199 #include "localize.h"
200 #include "vecmat.h"
201
202 // --------------------------------------------------------------------------------------
203 // briefing icons
204 // --------------------------------------------------------------------------------------
205 hud_frames      Icon_bitmaps[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
206 hud_anim                Icon_highlight_anims[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
207 hud_anim                Icon_fade_anims[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
208
209
210 // --------------------------------------------------------------------------------------
211 // briefing screen
212 // --------------------------------------------------------------------------------------
213
214 brief_screen bscreen;
215
216 // briefing screen sections
217 #define BRIEF_CUP_X1                    400
218 #define BRIEF_CUP_Y1                    70
219 #define BRIEF_CUP_X2                    639
220 #define BRIEF_CUP_Y2                    245
221 #define BRIEF_CUPINFO_X1        445
222 #define BRIEF_CUPINFO_Y1        247
223 #define BRIEF_CUPINFO_X2        639
224 #define BRIEF_CUPINFO_Y2        438
225
226 char *Brief_static_name[GR_NUM_RESOLUTIONS] = {
227         "BriefMap",
228         "2_BriefMap"
229 };
230
231 int Brief_static_coords[GR_NUM_RESOLUTIONS][2] = {
232         { // GR_640
233 #ifdef MAKE_FS1
234                 42, 122
235 #else
236                 10, 130
237 #endif
238         },
239         { // GR_1024
240                 15, 208
241         }
242 };
243
244 int Brief_bmap_coords[GR_NUM_RESOLUTIONS][2] = {
245         { // GR_640
246 #ifdef MAKE_FS1
247                 42, 122
248 #else
249                 0, 115
250 #endif
251         },
252         { // GR_1024
253                 0, 184
254         }
255 };
256
257 int Brief_grid_coords[GR_NUM_RESOLUTIONS][4] = {
258         { // GR_640
259 #ifdef MAKE_FS1
260                 54, 133, 530, 239
261 #else
262                 19, 147, 555, 232
263 #endif
264         },
265         { // GR_1024
266                 30, 235, 888, 371
267         }
268 };
269
270 int Brief_text_coords[GR_NUM_RESOLUTIONS][4] = {
271         { // GR_640
272 #ifdef MAKE_FS1
273                 49, 415, 374, 56
274 #else
275                 28, 399, 395, 74
276 #endif
277         },
278         { // GR_1024
279                 46, 637, 630, 120
280         }
281 };
282
283 int Brief_stage_text_coords[GR_NUM_RESOLUTIONS][2] = {
284         { // GR_640
285 #ifdef MAKE_FS1
286                 61, 387
287 #else
288                 138, 117
289 #endif
290         },
291         { // GR_1024
292                 227, 194
293         }
294 };
295
296 int Brief_stage_text_coords_multi[GR_NUM_RESOLUTIONS][2] = {
297         { // GR_640
298 #ifdef MAKE_FS1
299                 61, 387
300 #else
301                 479, 385
302 #endif
303         },
304         { // GR_1024
305                 821, 616
306         }
307 };
308
309 int Brief_text_max_lines[GR_NUM_RESOLUTIONS] = {
310         6, 6
311 };
312
313 #define LOOKAT_DIST     500.0f
314
315 // --------------------------------------------------------------------------------------
316 // Game-wide global data
317 // --------------------------------------------------------------------------------------
318 briefing                Briefings[MAX_TEAMS];                   // there is exactly one briefing per mission
319 debriefing      Debriefings[MAX_TEAMS];                 // there can be multiple debriefings per mission
320 briefing                *Briefing;                                                      // pointer used in code -- points to correct briefing
321 debriefing      *Debriefing;                                            // pointer to correct debriefing
322
323 int                     Briefing_voice_enabled=1;               // flag which turn on/off voice playback of briefings/debriefings
324
325 // --------------------------------------------------------------------------------------
326 // Module global data
327 // --------------------------------------------------------------------------------------
328
329 static int Last_new_stage;
330 int     Cur_brief_id;
331
332 const char BRIEF_META_CHAR = '$';
333
334 // static int Brief_voice_ask_for_cd;
335
336 // camera related
337 static vector   Current_cam_pos;                // current camera position
338 static vector   Target_cam_pos;         // desired camera position
339 static matrix   Current_cam_orient;     // current camera orientation
340 static matrix   Target_cam_orient;      // desired camera orientation
341 static matrix   Start_cam_orient;               // start camera orientation
342 static vector   Start_cam_pos;                  // position of camera at the start of a translation
343 static vector   Cam_vel;                                        //      camera velocity
344 static vector   Current_lookat_pos;     // lookat point
345 static vector   Target_lookat_pos;      // lookat point
346 static vector   Start_lookat_pos;
347 static vector   Lookat_vel;                             //      lookat point velocity
348
349 static float    Start_cam_move;         // time at which camera started moving (seconds)
350 static float    Total_move_time;                // time in which camera should move from current pos to target pos (seconds)
351 static float    Elapsed_time;
352
353 static float    Start_dist;
354 static float    End_dist;
355 static float    Dist_change_rate;
356
357 static vector   Acc_limit;
358 static vector   Vel_limit;
359
360 static float    Total_dist;
361 static float    Peak_speed;
362 static float    Cam_accel;
363 static float    Last_dist;
364 static vector   W_init;
365
366 // flag to indicate that the sound for a spinning highlight animation has played
367 static int Brief_stage_highlight_sound_handle = -1;
368
369 // used for scrolling briefing text ( if necessary )
370 int             Num_brief_text_lines[MAX_TEXT_STREAMS];
371 int             Top_brief_text_line;
372 static char             Brief_text[MAX_BRIEF_LINES][MAX_BRIEF_LINE_LEN];
373
374 // Used to support drawing colored text for the briefing.  Gets complicates since we
375 // need to be able to draw one character at a time as well when the briefing text
376 // first appears.
377 typedef struct colored_char
378 {
379         char    letter;
380         ubyte   color;          // index into Brief_text_colors[]
381 } colored_char;
382
383 static colored_char Colored_text[MAX_TEXT_STREAMS][MAX_BRIEF_LINES][MAX_BRIEF_LINE_LEN];
384 static int Colored_text_len[MAX_TEXT_STREAMS][MAX_BRIEF_LINES];
385
386 #define MAX_BRIEF_TEXT_COLORS                   9
387 #define BRIEF_TEXT_WHITE                                0
388 #define BRIEF_TEXT_BRIGHT_WHITE         1
389 #define BRIEF_TEXT_RED                                  2
390 #define BRIEF_TEXT_GREEN                                3
391 #define BRIEF_TEXT_YELLOW                               4
392 #define BRIEF_TEXT_BLUE                                 5
393 #define BRIEF_IFF_FRIENDLY                              6
394 #define BRIEF_IFF_HOSTILE                               7
395 #define BRIEF_IFF_NEUTRAL                               8
396
397 color Brief_color_red, Brief_color_green;
398
399 color *Brief_text_colors[MAX_BRIEF_TEXT_COLORS] = 
400 {
401         &Color_white,
402         &Color_bright_white,
403         &Color_red,
404         &Color_green,
405         &Color_yellow,
406         &Color_blue,
407         &Brief_color_green,
408         &Brief_color_red,
409         &IFF_colors[IFF_COLOR_NEUTRAL][0],
410 };
411
412 #define BRIGHTEN_LEAD   2
413
414 float Brief_text_wipe_time_elapsed;
415 static int Max_briefing_line_len;
416
417 static int Brief_voice_ended;
418 static int Brief_textdraw_finished;
419 static int Brief_voice_started;
420 static int Brief_stage_time;
421
422 const float             BRIEF_TEXT_WIPE_TIME    = 1.5f;         // time in seconds for wipe to occur
423 static int              Brief_text_wipe_snd;                                    // sound handle of sound effect for text wipe
424 static int              Play_brief_voice;
425
426 // animation stuff
427 static int              Play_highlight_flag;
428 static int              Cam_target_reached;
429 static int              Cam_movement_done;
430
431 // moving icons
432 typedef struct icon_move_info
433 {
434         icon_move_info  *next, *prev;
435         int                             used;
436         int                             id;
437         vector                  start;
438         vector                  finish;
439         vector                  current;
440
441         // used to move icons smoothly
442         vector                  direction;
443         float                           total_dist;
444         float                           accel;
445         float                           total_move_time;
446         float                           peak_speed;
447         int                             reached_dest;
448         float                           last_dist;
449 } icon_move_info;
450
451 #define MAX_MOVE_ICONS  10
452 icon_move_info  Icon_movers[MAX_MOVE_ICONS];
453 icon_move_info  Icon_move_list; // head of linked list
454
455 // fading out icons
456 typedef struct fade_icon
457 {
458         hud_anim        fade_anim;              // anim info
459         vector  pos;
460         int             team;
461 } fade_icon;
462
463 #define         MAX_FADE_ICONS  30
464 fade_icon       Fading_icons[MAX_FADE_ICONS];
465 int                     Num_fade_icons;
466
467 // voice id's for briefing text
468 int Brief_voices[MAX_BRIEF_STAGES];
469
470 cmd_brief *Cur_cmd_brief;
471 cmd_brief Cmd_briefs[MAX_TEAMS];
472
473 // --------------------------------------------------------------------------------------
474 // forward declarations
475 // --------------------------------------------------------------------------------------
476 void    brief_render_elements(vector *pos, grid *gridp);
477 void    brief_render_icons(int stage_num, float frametime);
478 void    brief_parse_icon_tbl();
479 void    brief_grid_read_camera_controls( control_info * ci, float frametime );
480 void    brief_maybe_create_new_grid(grid *gridp, vector *pos, matrix *orient, int force = 0);
481 grid    *brief_create_grid(grid *gridp, vector *forward, vector *right, vector *center, int nrows, int ncols, float square_size);
482 grid    *brief_create_default_grid(void);
483 void    brief_render_grid(grid *gridp);
484 void    brief_modify_grid(grid *gridp);
485 void    brief_rpd_line(vector *v0, vector *v1);
486 void    brief_set_text_color(int color_index);
487 extern void get_camera_limits(matrix *start_camera, matrix *end_camera, float time, vector *acc_max, vector *w_max);
488 int brief_text_wipe_finished();
489
490 void brief_set_icon_color(int team)
491 {
492         switch (team) { 
493         case TEAM_FRIENDLY:     SET_COLOR_FRIENDLY;     break;
494         case TEAM_HOSTILE:      SET_COLOR_HOSTILE;      break;
495         case TEAM_NEUTRAL:      SET_COLOR_NEUTRAL;      break;
496         case TEAM_TRAITOR:      SET_COLOR_HOSTILE;      break;
497         default:
498                 SET_COLOR_HOSTILE;      break;
499         } // end switch
500 }
501
502 // --------------------------------------------------------------------------------------
503 //      brief_move_icon_reset()
504 //
505 //
506 void brief_move_icon_reset()
507 {
508         int i;
509
510         list_init(&Icon_move_list);
511         for ( i = 0; i < MAX_MOVE_ICONS; i++ )
512                 Icon_movers[i].used = 0;
513 }
514
515
516 // --------------------------------------------------------------------------------------
517 // Does one time initialization of the briefing and debriefing structures.
518 // Namely setting all malloc'ble pointers to NULL.  Called once at game startup.
519 void mission_brief_common_init()
520 {
521         int i,j;
522
523         // setup brief text colors
524         gr_init_alphacolor( &Brief_color_green, 50, 100, 50, 255, AC_TYPE_HUD);
525         gr_init_alphacolor( &Brief_color_red, 140, 20, 20, 255, AC_TYPE_HUD);
526
527         // extra catch to reset anything that's already loaded (ie. mission restart)
528         mission_brief_common_reset();
529         mission_debrief_common_reset();
530
531         if ( Fred_running )     {
532                 // If Fred is running malloc out max space
533                 for (i=0; i<MAX_TEAMS; i++ )    {
534                         for (j=0; j<MAX_BRIEF_STAGES; j++ )     {
535                                 Briefings[i].stages[j].new_text = (char *)malloc(MAX_BRIEF_LEN);
536                                 Assert(Briefings[i].stages[j].new_text!=NULL);
537                                 Briefings[i].stages[j].icons = (brief_icon *)malloc(sizeof(brief_icon)*MAX_STAGE_ICONS);
538                                 Assert(Briefings[i].stages[j].icons!=NULL);
539                                 Briefings[i].stages[j].lines = (brief_line *)malloc(sizeof(brief_line)*MAX_BRIEF_STAGE_LINES);
540                                 Assert(Briefings[i].stages[j].lines!=NULL);
541                                 Briefings[i].stages[j].num_icons = 0;
542                                 Briefings[i].stages[j].num_lines = 0;
543                         }
544                 }
545
546                 for (i=0; i<MAX_TEAMS; i++ )    {
547                         for (j=0; j<MAX_DEBRIEF_STAGES; j++ )   {
548                                 Debriefings[i].stages[j].new_text = (char *)malloc(MAX_DEBRIEF_LEN);
549                                 Assert(Debriefings[i].stages[j].new_text!=NULL);
550                                 Debriefings[i].stages[j].new_recommendation_text = (char *)malloc(MAX_RECOMMENDATION_LEN);
551                                 Assert(Debriefings[i].stages[j].new_recommendation_text!=NULL);
552                         }
553                 }
554
555         } else {
556                 // If game is running don't malloc anything
557                 for (i=0; i<MAX_TEAMS; i++ )    {
558                         for (j=0; j<MAX_BRIEF_STAGES; j++ )     {
559                                 Briefings[i].stages[j].new_text = NULL;
560                                 Briefings[i].stages[j].num_icons = 0;
561                                 Briefings[i].stages[j].icons = NULL;
562                                 Briefings[i].stages[j].num_lines = 0;
563                                 Briefings[i].stages[j].lines = NULL;
564                         }
565                 }
566
567                 for (i=0; i<MAX_TEAMS; i++ )    {
568                         for (j=0; j<MAX_DEBRIEF_STAGES; j++ )   {
569                                 Debriefings[i].stages[j].new_text = NULL;
570                                 Debriefings[i].stages[j].new_recommendation_text = NULL;
571                         }
572                 }
573
574         }
575
576                 
577 }
578
579 //--------------------------------------------------------------------------------------
580 // Frees all the memory allocated in the briefing and debriefing structures
581 // and sets all pointers to NULL.
582 void mission_brief_common_reset()
583 {
584         int i,j;
585
586         if ( Fred_running )     {
587                 return;                                         // Don't free these under Fred.
588         }
589
590         for (i=0; i<MAX_TEAMS; i++ )    {
591                 for (j=0; j<MAX_BRIEF_STAGES; j++ )     {
592                         if ( Briefings[i].stages[j].new_text )  {
593                                 free(Briefings[i].stages[j].new_text);
594                                 Briefings[i].stages[j].new_text = NULL;                 
595                         }
596         
597                         if ( Briefings[i].stages[j].icons )     {
598                                 free(Briefings[i].stages[j].icons);
599                                 Briefings[i].stages[j].icons = NULL;
600                         }
601
602                         if ( Briefings[i].stages[j].lines )     {
603                                 free(Briefings[i].stages[j].lines);
604                                 Briefings[i].stages[j].lines = NULL;
605                         }
606                 }
607         }
608 }
609
610 // split from above since we need to clear them separately
611 void mission_debrief_common_reset()
612 {
613         int i, j;
614
615         if ( Fred_running ) {
616                 return;                                         // Don't free these under Fred.
617         }
618
619         for (i=0; i<MAX_TEAMS; i++ )    {
620                 for (j=0; j<MAX_DEBRIEF_STAGES; j++ )   {
621                         if ( Debriefings[i].stages[j].new_text )        {
622                                 free(Debriefings[i].stages[j].new_text);
623                                 Debriefings[i].stages[j].new_text = NULL;
624                         }
625
626                         if ( Debriefings[i].stages[j].new_recommendation_text ) {
627                                 free(Debriefings[i].stages[j].new_recommendation_text);
628                                 Debriefings[i].stages[j].new_recommendation_text = NULL;
629                         }
630                 }
631         }               
632 }
633
634
635
636
637 // --------------------------------------------------------------------------------------
638 //      brief_reset()
639 //
640 //
641 void brief_reset()
642 {
643         int i;
644
645         Briefing = NULL;
646         for ( i = 0; i < MAX_TEAMS; i++ ) 
647                 Briefings[i].num_stages = 0;
648         Cur_brief_id = 1;
649 }
650
651 // --------------------------------------------------------------------------------------
652 //      debrief_reset()
653 //
654 //
655 void debrief_reset()
656 {
657         int i,j;
658
659         Debriefing = NULL;
660         for ( i = 0; i < MAX_TEAMS; i++ ) {
661                 Debriefings[i].num_stages = 0;
662                 for (j=0; j<MAX_DEBRIEF_STAGES; j++ )   {
663                         if ( Debriefings[i].stages[j].new_recommendation_text ) {
664                                 Debriefings[i].stages[j].new_recommendation_text[0] = 0;
665                         }
666                 }
667         }
668
669         // MWA 4/27/98 -- must initialize this variable here since we cannot do it as debrief
670         // init time because race conditions between all players in the game make that type of
671         // initialization unsafe.
672         Debrief_multi_stages_loaded = 0;
673 }
674
675 // --------------------------------------------------------------------------------------
676 //      brief_init_screen()
677 //
678 //      Set up the screen regions.  A mulitplayer briefing will look different than a single player
679 // briefing.
680 //
681 void brief_init_screen(int multiplayer_flag)
682 {
683         bscreen.map_x1                  = Brief_grid_coords[gr_screen.res][0];
684         bscreen.map_x2                  = Brief_grid_coords[gr_screen.res][0] + Brief_grid_coords[gr_screen.res][2];
685         bscreen.map_y1                  = Brief_grid_coords[gr_screen.res][1];
686         bscreen.map_y2                  = Brief_grid_coords[gr_screen.res][1] + Brief_grid_coords[gr_screen.res][3];
687         /*
688         bscreen.map_x1                  = BRIEF_GRID3_X1;
689         bscreen.map_x2                  = BRIEF_GRID0_X2;
690         bscreen.map_y1                  = BRIEF_GRID3_Y1;
691         bscreen.map_y2                  = BRIEF_GRID0_Y2+4;
692         bscreen.btext_x1                = BRIEF_TEXT_X1;
693         bscreen.btext_x2                = BRIEF_TEXT_X2;
694         bscreen.btext_y1                = BRIEF_TEXT_Y1;
695         bscreen.btext_y2                = BRIEF_TEXT_Y2;
696         bscreen.cup_x1                  = BRIEF_CUP_X1;
697         bscreen.cup_y1                  = BRIEF_CUP_Y1;
698         bscreen.cup_x2                  = BRIEF_CUP_X2;
699         bscreen.cup_y2                  = BRIEF_CUP_Y2;
700         bscreen.cupinfo_x1      = BRIEF_CUPINFO_X1;
701         bscreen.cupinfo_y1      = BRIEF_CUPINFO_Y1;
702         bscreen.cupinfo_x2      = BRIEF_CUPINFO_X2;
703         bscreen.cupinfo_y2      = BRIEF_CUPINFO_Y2;
704         */
705 }
706
707 // --------------------------------------------------------------------------------------
708 //      brief_init_icons()
709 //
710 //
711 void brief_init_icons()
712 {
713         if ( Fred_running ) {
714                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_HOSTILE][0],  0xff, 0x00, 0x00, 15*16, AC_TYPE_HUD);
715                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_FRIENDLY][0], 0x00, 0xff, 0x00, 15*16, AC_TYPE_HUD);
716         }
717
718         // Load in the bitmaps for the icons from icons.tbl
719         brief_parse_icon_tbl();
720 }
721
722 // Reset the highlight and fade anims... call before brief_parse_icon_tbl();
723 void brief_init_anims()
724 {
725 #ifndef MAKE_FS1
726         int idx;
727 #endif
728         int i;
729
730         for (i=0; i<MAX_BRIEF_ICONS; i++) {
731 #ifndef MAKE_FS1
732                 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
733                         Icon_highlight_anims[i][idx].num_frames=0;
734                         Icon_fade_anims[i][idx].num_frames=0;
735                 }
736 #else
737                 // one set of icons for all species in FS1
738                 Icon_highlight_anims[i][1].num_frames=0;
739                 Icon_fade_anims[i][1].num_frames=0;
740 #endif
741         }
742 }
743
744 // ------------------------------------------------------------------------
745 //      brief_unload_icons() 
746 //
747 //
748 void brief_unload_icons()
749 {
750         hud_frames              *ib;
751         int                             i, j, idx;
752
753         for ( i = 0; i < MAX_BRIEF_ICONS; i++ ) {
754                 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
755                         ib = &Icon_bitmaps[i][idx];
756
757                         for ( j=0; j<ib->num_frames; j++ ) {
758                                 bm_unload(ib->first_frame+j);
759                         }
760                 }
761         }
762 }
763
764 // determine if icon type is used in the current briefing
765 int brief_icon_used_in_briefing(int icon_type)
766 {
767         int num_icons, num_stages, i, j;
768
769         num_stages = Briefing->num_stages;
770
771         for ( i = 0; i < num_stages; i++ ) {
772                 num_icons = Briefing->stages[i].num_icons;
773                 for ( j = 0; j < num_icons; j++ ) {
774                         if ( Briefing->stages[i].icons[j].type == icon_type ) {
775                                 return 1;
776                         }
777                 }
778         }
779
780         return 0;
781 }
782
783 // --------------------------------------------------------------------------------------
784 //      brief_parse_icon_tbl()
785 //
786 //
787 void brief_parse_icon_tbl()
788 {
789         int                     num_icons, rval;
790         char                    name[NAME_LENGTH];
791         hud_frames      *hf;
792         hud_anim                *ha;
793         int idx;
794
795         // open localization
796         lcl_ext_open();
797
798         if ((rval = setjmp(parse_abort)) != 0) {
799                 Error(LOCATION, "Unable to parse icons.tbl!  Code = %i.\n", rval);
800         }
801         else {
802                 read_file_text("icons.tbl");
803                 reset_parse();          
804         }
805
806         num_icons = 0;
807         required_string("#Start");
808
809
810         int load_this_icon = 0;
811
812         while (required_string_either("#End","$Name:")) {
813                 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
814                         Assert( num_icons < MAX_BRIEF_ICONS);
815                         hf = &Icon_bitmaps[num_icons][idx];
816
817                         // load in regular frames
818                         required_string("$Name:");
819                         stuff_string(name, F_NAME, NULL);
820
821                         if ( Fred_running ) {
822                                 load_this_icon = 1;
823                         } else {
824                                 load_this_icon = brief_icon_used_in_briefing(num_icons);
825                         }
826
827                         if ( load_this_icon ) {
828                                 hf->first_frame = bm_load_animation(name, &hf->num_frames);
829                                 if ( hf->first_frame == -1 ) {
830                                         Int3(); // missing briefing icon
831                                 }
832                         }
833
834                         // load in fade frames
835                         required_string("$Name:");
836                         stuff_string(name, F_NAME, NULL);
837                         ha = &Icon_fade_anims[num_icons][idx];
838                         hud_anim_init(ha, 0, 0, name);
839
840                         // load in highlighting frames
841                         required_string("$Name:");
842                         stuff_string(name, F_NAME, NULL);
843                         ha = &Icon_highlight_anims[num_icons][idx];
844                         hud_anim_init(ha, 0, 0, name);
845                 }
846
847                 // next icon _type_
848                 num_icons++;
849         }
850         required_string("#End");
851
852         // close localization
853         lcl_ext_close();
854 }
855
856 // --------------------------------------------------------------------------------------
857 //      brief_close_map()
858 //
859 //
860 void brief_close_map()
861 {
862         brief_unload_icons();
863 }
864
865 void brief_preload_highlight_anim(brief_icon *bi)
866 {
867         hud_anim *ha;
868         int species = ship_get_species_by_type(bi->ship_class);
869
870         if(species < 0){
871                 return;
872         }
873
874         ha = &Icon_highlight_anims[bi->type][species];
875         if ( !stricmp(NOX("none"), ha->name) ) {
876                 return;
877         }
878
879         // force read of data from disk, so we don't glitch on initial playback
880         if ( ha->first_frame == -1 ) {
881                 hud_anim_load(ha);
882                 Assert(ha->first_frame >= 0);
883         }
884
885         bi->highlight_anim = *ha;
886
887         gr_set_bitmap(ha->first_frame, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
888         gr_aabitmap(0, 0);
889 }
890
891 void brief_preload_fade_anim(brief_icon *bi)
892 {
893         hud_anim *ha;
894         int species = ship_get_species_by_type(bi->ship_class);
895
896         if(species < 0){
897                 return;
898         }
899
900         ha = &Icon_fade_anims[bi->type][species];
901         if ( !stricmp(NOX("none"), ha->name) ) {
902                 return;
903         }
904
905         // force read of data from disk, so we don't glitch on initial playback
906         if ( ha->first_frame == -1 ) {
907                 hud_anim_load(ha);
908                 Assert(ha->first_frame >= 0);
909         }
910
911         gr_set_bitmap(ha->first_frame, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
912         gr_aabitmap(0, 0);
913 }
914
915 // preload highlight, fadein and fadeout animations that are used in this stage
916 void brief_preload_anims()
917 {
918         int                     num_icons, num_stages, i, j;
919         brief_icon      *bi;
920
921         num_stages = Briefing->num_stages;
922
923         for ( i = 0; i < num_stages; i++ ) {
924                 num_icons = Briefing->stages[i].num_icons;
925                 for ( j = 0; j < num_icons; j++ ) {
926                         bi = &Briefing->stages[i].icons[j];
927                         if ( bi->flags & BI_HIGHLIGHT ) {
928                                 brief_preload_highlight_anim(bi);
929                         }
930                         brief_preload_fade_anim(bi);
931                 }
932         }
933 }
934
935 // --------------------------------------------------------------------------------------
936 //      brief_init_map()
937 //
938 //
939 void brief_init_map()
940 {
941         vector *pos;
942         matrix *orient;
943
944         Assert( Briefing != NULL );
945
946         pos = &Briefing->stages[0].camera_pos;
947         orient = &Briefing->stages[0].camera_orient;
948         vm_vec_zero(&Current_lookat_pos);
949         vm_vec_zero(&Target_lookat_pos);
950         Elapsed_time = 0.0f;
951         Total_move_time = 0.0f;
952
953         The_grid = brief_create_default_grid();
954         brief_maybe_create_new_grid(The_grid, pos, orient, 1);
955
956         brief_init_anims();
957         brief_init_icons();
958         brief_move_icon_reset();
959         brief_preload_anims();
960
961         Brief_text_wipe_snd = -1;
962         Last_new_stage = -1;
963         Num_fade_icons=0;
964 }
965
966 #ifndef PLAT_UNIX
967 #pragma optimize("", off)
968 #endif
969
970 // render fade-out anim frame
971
972 void brief_render_fade_outs(float frametime)
973 {
974         int                     i,bx,by,w,h;
975         float                   bxf,byf;
976         vertex          tv;                     // temp vertex used to find screen position for text
977         fade_icon       *fi;
978         
979
980         for (i=0; i<Num_fade_icons; i++) {
981                 fi = &Fading_icons[i];
982
983                 g3_rotate_vertex(&tv, &fi->pos);
984
985                 if (!(tv.flags & PF_PROJECTED))
986                         g3_project_vertex(&tv);
987
988                 if (!(tv.flags & PF_OVERFLOW) ) {  // make sure point projected before drawing text
989
990                         brief_set_icon_color(fi->team);
991
992                         if ( fi->fade_anim.first_frame < 0 ) {
993                                 continue;
994                         }
995
996                         bm_get_info( fi->fade_anim.first_frame, &w, &h, NULL);
997                         
998                         bxf = tv.sx - w / 2.0f + 0.5f;
999                         byf = tv.sy - h / 2.0f + 0.5f;
1000                         bx = fl2i(bxf);
1001                         by = fl2i(byf);
1002
1003                         if ( fi->fade_anim.first_frame >= 0 ) {
1004                                 fi->fade_anim.sx = bx;
1005                                 fi->fade_anim.sy = by;
1006 #ifdef MAKE_FS1
1007                                 // FS1 has the anis reversed from FS2 so play them backwards
1008                                 hud_anim_render(&fi->fade_anim, frametime, 1, 0, 0, 1);
1009 #else                   
1010                                 hud_anim_render(&fi->fade_anim, frametime, 1, 0, 0, 0);
1011 #endif
1012                         }
1013                 }
1014         }
1015 }
1016
1017 // figure out how far an icon should move based on the elapsed time
1018 float brief_icon_get_dist_moved(icon_move_info *mi, float elapsed_time)
1019 {
1020         float time, dist_moved=0.0f;
1021         
1022         // first half of movement
1023         if ( elapsed_time < mi->total_move_time/2.0f ) {
1024                 dist_moved=0.5f*mi->accel*elapsed_time*elapsed_time;    // d = 1/2at^2
1025                 return dist_moved;
1026         }
1027
1028         // second half of movement
1029         time=elapsed_time - mi->total_move_time/2.0f;
1030         dist_moved=(mi->total_dist/2.0f)+(mi->peak_speed*time) - 0.5f*mi->accel*time*time;
1031         return dist_moved;
1032 }
1033
1034 // Draw a line between two icons on the briefing screen
1035 void brief_render_icon_line(int stage_num, int line_num)
1036 {
1037         brief_line      *bl;
1038         brief_icon      *icon[2];
1039         vertex          icon_vertex[2];
1040         int                     icon_status[2] = {0,0};
1041         int                     icon_w, icon_h, i;
1042         float                   icon_x[2], icon_y[2];
1043
1044         bl = &Briefing->stages[stage_num].lines[line_num];
1045         icon[0] = &Briefing->stages[stage_num].icons[bl->start_icon];
1046         icon[1] = &Briefing->stages[stage_num].icons[bl->end_icon];
1047
1048         // project icons
1049         for (i=0; i<2; i++) {
1050                 g3_rotate_vertex(&icon_vertex[i],&icon[i]->pos);
1051                 if (!(icon_vertex[i].flags&PF_PROJECTED))
1052                         g3_project_vertex(&icon_vertex[i]);
1053
1054                 if (!(icon_vertex[i].flags & PF_OVERFLOW) ) {  // make sure point projected before drawing text
1055                         icon_status[i]=1;
1056                 }
1057         }
1058
1059         if ( !icon_status[0] || !icon_status[1] ) {
1060                 return;
1061         }
1062
1063         // get screen (x,y) for icons
1064         for (i=0; i<2; i++) {
1065                 brief_common_get_icon_dimensions(&icon_w, &icon_h, icon[i]->type, icon[i]->ship_class);
1066                 icon_x[i] = icon_vertex[i].sx;
1067                 icon_y[i] = icon_vertex[i].sy;
1068         }
1069
1070         brief_set_icon_color(icon[0]->team);
1071
1072         gr_line(fl2i(icon_x[0]), fl2i(icon_y[0]), fl2i(icon_x[1]), fl2i(icon_y[1]));
1073 }
1074
1075 // -------------------------------------------------------------------------------------
1076 // Draw a briefing icon
1077 //
1078 // parameters:          stage_num               =>              briefing stage number (start at 0)
1079 //                                              icon_num                        =>              icon number in stage
1080 //                                              frametime               =>              time elapsed in seconds
1081 //                                              selected                        =>              FRED only (will be 0 or non-zero)
1082 //                                              w_scale_factor  =>              scale icon in width by this amount (default 1.0f)
1083 //                                              h_scale_factor  =>              scale icon in height by this amount (default 1.0f)
1084 void brief_render_icon(int stage_num, int icon_num, float frametime, int selected, float w_scale_factor, float h_scale_factor)
1085 {
1086         brief_icon      *bi, *closeup_icon;
1087         hud_frames      *ib;
1088         vertex          tv;     // temp vertex used to find screen position for text
1089         vector          *pos = NULL;
1090         int                     bx,by,bc,w,h,icon_w,icon_h,icon_bitmap=-1;
1091         float                   bxf, byf, dist=0.0f;
1092
1093         Assert( Briefing != NULL );
1094         
1095         bi = &Briefing->stages[stage_num].icons[icon_num];
1096
1097         icon_move_info *mi, *next;
1098         int interp_pos_found = 0;
1099         
1100         mi = GET_FIRST(&Icon_move_list);
1101         if (mi)
1102                 while ( mi != &Icon_move_list ) {
1103                         next = mi->next;
1104                         if ( ( mi->id != 0 ) && ( mi->id == bi->id ) ) {
1105
1106                                 if ( !mi->reached_dest ) {
1107                                         dist = brief_icon_get_dist_moved(mi, Elapsed_time);
1108                                         if ( dist < mi->last_dist ) {
1109                                                 mi->reached_dest=1;
1110                                                 mi->last_dist=0.0f;
1111                                         }
1112                                         mi->last_dist=dist;
1113                                 }
1114
1115                                 if ( !mi->reached_dest ) {
1116                                         vector dist_moved;
1117                                         vm_vec_copy_scale(&dist_moved, &mi->direction, dist);
1118                                         vm_vec_add(&mi->current, &mi->start, &dist_moved);
1119                                 } else {
1120                                         mi->current = mi->finish;
1121                                 }
1122
1123                                 pos = &mi->current;
1124                                 interp_pos_found = 1;
1125                                 break;
1126                         }
1127                         mi = next;
1128                 }
1129         
1130         if ( !interp_pos_found )
1131                 pos = &bi->pos;
1132                 
1133         brief_render_elements(pos, The_grid);
1134         g3_rotate_vertex(&tv,pos);
1135
1136         if (!(tv.flags&PF_PROJECTED))
1137                 g3_project_vertex(&tv);
1138
1139         if (!(tv.flags & PF_OVERFLOW) ) {  // make sure point projected before drawing text
1140
1141                 brief_set_icon_color(bi->team);
1142
1143                 int species = ship_get_species_by_type(bi->ship_class);
1144
1145                 if(species < 0){
1146                         return;
1147                 }
1148
1149                 ib = &Icon_bitmaps[bi->type][species];
1150                 if ( ib->first_frame < 0 ) {
1151                         Int3();
1152                         return;
1153                 }
1154
1155                 brief_common_get_icon_dimensions(&icon_w, &icon_h, bi->type, bi->ship_class);
1156
1157                 closeup_icon = brief_get_closeup_icon();
1158
1159                 if ( bi == closeup_icon || selected ) {
1160                         icon_bitmap=ib->first_frame+1;
1161 //                      gr_set_bitmap(ib->first_frame+1);
1162                 }
1163                 else {
1164                         icon_bitmap=ib->first_frame;
1165 //                      gr_set_bitmap(ib->first_frame);
1166                 }
1167         
1168                 // draw icon centered at draw position
1169 //              bx = fl2i(tv.sx - ib->icon_w/2.0f);
1170 //              by = fl2i(tv.sy - ib->icon_h/2.0f);
1171 //              bc = bx + fl2i(ib->icon_w/2.0f);
1172                 //gr_aabitmap(bx, by);
1173
1174                 float scaled_w, scaled_h;
1175                 
1176                 scaled_w = icon_w * w_scale_factor;
1177                 scaled_h = icon_h * h_scale_factor;
1178                 bxf = tv.sx - scaled_w / 2.0f + 0.5f;
1179                 byf = tv.sy - scaled_h / 2.0f + 0.5f;
1180                 bx = fl2i(bxf);
1181                 by = fl2i(byf);
1182                 bc = fl2i(tv.sx);
1183
1184                 if ( (bx < 0) || (bx > gr_screen.max_w) || (by < 0) || (by > gr_screen.max_h) && !Fred_running ) {
1185                         bi->x = bx;
1186                         bi->y = by;
1187                         return;
1188                 }
1189
1190                 vertex va, vb;
1191                 va.sx = bxf;
1192                 va.sy = byf;
1193                 va.u = 0.0f;
1194                 va.v = 0.0f;
1195
1196                 vb.sx = bxf+scaled_w-1;
1197                 vb.sy = byf+scaled_h-1;
1198                 vb.u = 1.0f;
1199                 vb.v = 1.0f;
1200
1201                 // render highlight anim frame
1202                 if ( (bi->flags&BI_SHOWHIGHLIGHT) && (bi->flags&BI_HIGHLIGHT) ) {
1203                         hud_anim *ha = &bi->highlight_anim;
1204                         if ( ha->first_frame >= 0 ) {
1205                                 ha->sx = bi->hold_x;
1206                                 if ( strlen(bi->label) > 0 ) {
1207                                         ha->sy = bi->hold_y - fl2i(gr_get_font_height()/2.0f +0.5) - 2;
1208                                 } else {
1209                                         ha->sy = bi->hold_y;
1210                                 }
1211
1212                                 //hud_set_iff_color(bi->team);
1213                                 brief_set_icon_color(bi->team);
1214
1215                                 hud_anim_render(ha, frametime, 1, 0, 1);
1216
1217                                 if ( Brief_stage_highlight_sound_handle < 0 ) {
1218                                         if ( !Fred_running) {
1219                                                 Brief_stage_highlight_sound_handle = snd_play(&Snds_iface[SND_ICON_HIGHLIGHT]);                                 
1220                                         }
1221                                 }
1222                         }
1223                 }
1224
1225                 // render fade-in anim frame
1226                 if ( bi->flags & BI_FADEIN ) {
1227                         hud_anim *ha = &bi->fadein_anim;
1228                         if ( ha->first_frame >= 0 ) {
1229                                 ha->sx = bx;
1230                                 ha->sy = by;
1231 //                              hud_set_iff_color(bi->team);
1232                                 brief_set_icon_color(bi->team);
1233
1234 #ifdef MAKE_FS1
1235                                 // FS1 has the anims backwards from FS2 so play in reverse
1236                                 if ( hud_anim_render(ha, frametime, 1, 0, 0, 0) == 0 ) {
1237 #else
1238                                 if ( hud_anim_render(ha, frametime, 1, 0, 0, 1) == 0 ) {
1239 #endif
1240                                         bi->flags &= ~BI_FADEIN;
1241                                 }
1242                         } else {
1243                                 bi->flags &= ~BI_FADEIN;
1244                         }
1245                 }               
1246
1247                 if ( !(bi->flags & BI_FADEIN) ) {
1248                         gr_set_bitmap(icon_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1249
1250                         if ( Fred_running )     {
1251                                 gr_aascaler(&va, &vb);
1252                         } else {
1253                                 // Don't bother scaling for the game
1254                                 gr_aabitmap(bx, by);
1255                         }
1256
1257                         // draw text centered over the icon (make text darker)
1258                         if ( bi->type == ICON_FIGHTER_PLAYER || bi->type == ICON_BOMBER_PLAYER ) {
1259                                 gr_get_string_size(&w,&h,Players[Player_num].callsign);
1260                                 gr_printf(bc - fl2i(w/2.0f), by - h, Players[Player_num].callsign);
1261                         }
1262                         else {
1263                                 if (Lcl_gr) {
1264                                         char buf[128];
1265                                         strcpy(buf, bi->label);
1266                                         lcl_translate_brief_icon_name(buf);
1267                                         gr_get_string_size(&w, &h, buf);
1268                                         gr_printf(bc - fl2i(w/2.0f), by - h, buf);
1269                                 } else if(Lcl_pl) {
1270                                         char buf[128];
1271                                         strcpy(buf, bi->label);
1272                                         lcl_translate_brief_icon_name_pl(buf);
1273                                         gr_get_string_size(&w, &h, buf);
1274                                         gr_printf(bc - fl2i(w/2.0f), by - h, buf);
1275                                 } else {
1276                                         gr_get_string_size(&w,&h,bi->label);
1277                                         gr_printf(bc - fl2i(w/2.0f), by - h, bi->label);
1278                                 }
1279                         }
1280
1281                         // show icon as selected (FRED only)
1282                         if ( selected ) {
1283                                 gr_get_string_size(&w,&h,NOX("(S)"));
1284                                 gr_printf(bc - fl2i(w/2.0f), by - h*2, NOX("(S)"));
1285                         }
1286                 }
1287
1288                 // store screen x,y,w,h
1289                 bi->x = bx;
1290                 bi->y = by;
1291                 bi->w = fl2i(scaled_w);
1292                 bi->h = fl2i(scaled_h);
1293
1294         }  // end if vertex is projected
1295 }
1296
1297 #ifndef PLAT_UNIX
1298 #pragma optimize("", on)
1299 #endif
1300
1301 // -------------------------------------------------------------------------------------
1302 // brief_render_icons()
1303 //
1304 void brief_render_icons(int stage_num, float frametime)
1305 {
1306         int i, num_icons, num_lines;
1307
1308         Assert( Briefing != NULL );
1309         
1310         num_icons = Briefing->stages[stage_num].num_icons;
1311         num_lines = Briefing->stages[stage_num].num_lines;
1312
1313         if ( Cam_target_reached ) {
1314                 for ( i = 0; i < num_lines; i++ ) {
1315                         brief_render_icon_line(stage_num, i);
1316                 }
1317         }
1318
1319         for ( i = 0; i < num_icons; i++ ) {
1320                 brief_render_icon(stage_num, i, frametime, 0);
1321         }
1322 }
1323
1324 // ------------------------------------------------------------------------------------
1325 // brief_start_highlight_anims()
1326 //
1327 //      see if there are any highlight animations to play
1328 //
1329 void brief_start_highlight_anims(int stage_num)
1330 {
1331         brief_stage             *bs;
1332         brief_icon              *bi;
1333         int                             x,y,i,anim_w,anim_h;
1334
1335         Assert( Briefing != NULL );
1336         bs = &Briefing->stages[stage_num];
1337         
1338         for ( i = 0; i < bs->num_icons; i++ ) {
1339                 bi = &bs->icons[i];
1340                 if ( bi->flags & BI_HIGHLIGHT ) {
1341                         bi->flags &= ~BI_SHOWHIGHLIGHT;
1342                         if ( bi->highlight_anim.first_frame < 0 ) {
1343                                 continue;
1344                         }
1345
1346                         bi->highlight_anim.time_elapsed=0.0f;
1347
1348                         bm_get_info( bi->highlight_anim.first_frame, &anim_w, &anim_h, NULL);
1349                         x = fl2i( i2fl(bi->x) + bi->w/2.0f - anim_w/2.0f );
1350                         y = fl2i( i2fl(bi->y) + bi->h/2.0f - anim_h/2.0f );
1351                         bi->hold_x = x;
1352                         bi->hold_y = y;
1353                         bi->flags |= BI_SHOWHIGHLIGHT;
1354                         bi->highlight_anim.time_elapsed=0.0f;
1355                 }
1356         }
1357 }
1358
1359 // -------------------------------------------------------------------------------------
1360 // brief_render_map()
1361 //
1362 //
1363 void brief_render_map(int stage_num, float frametime)
1364 {
1365         brief_stage *bs;
1366
1367         gr_set_clip(bscreen.map_x1 + 1, bscreen.map_y1 + 1, bscreen.map_x2 - bscreen.map_x1 - 1, bscreen.map_y2 - bscreen.map_y1 - 2);
1368         
1369         // REMOVED by neilk: removed gr_clear for FS2 because interface no longer calls for black background on grid
1370 #ifdef MAKE_FS1
1371         gr_clear();
1372 #endif
1373
1374   if (stage_num >= Briefing->num_stages) {
1375                 gr_reset_clip();
1376                 return;
1377         }
1378
1379         Assert(Briefing);
1380         bs = &Briefing->stages[stage_num];
1381
1382         g3_start_frame(0);
1383         g3_set_view_matrix(&Current_cam_pos, &Current_cam_orient, 0.5f);
1384
1385         brief_maybe_create_new_grid(The_grid, &Current_cam_pos, &Current_cam_orient);
1386         brief_render_grid(The_grid);
1387
1388         brief_render_fade_outs(frametime);
1389
1390         // go ahead and render everything that is in the active objects list
1391         brief_render_icons(stage_num, frametime);
1392
1393         if ( Cam_target_reached && brief_text_wipe_finished() ) {
1394
1395                 if ( Brief_textdraw_finished == 0 ) {
1396                         Brief_textdraw_finished = 1;
1397                         Brief_stage_time = 0;
1398                 }
1399
1400                 if ( Play_highlight_flag ) {
1401                         brief_start_highlight_anims(stage_num);
1402                         Play_highlight_flag = 0;
1403                 }
1404         }
1405
1406         anim_render_all(ON_BRIEFING_SELECT, frametime);
1407
1408         gr_reset_clip();
1409         g3_end_frame();
1410 }
1411
1412
1413 // -------------------------------------------------------------------------------------
1414 // brief_text_set_color()
1415 //
1416 void brief_text_set_color(char c) {
1417         switch ( c ) {
1418                 case 'f':
1419                         SET_COLOR_FRIENDLY;
1420                         break;
1421                 case 'h':
1422                         SET_COLOR_HOSTILE;
1423                         break;
1424                 case 'n':
1425                         SET_COLOR_NEUTRAL;
1426                         break;
1427                 case 'r':
1428                         gr_set_color_fast(&Color_red);
1429                         break;
1430                 case 'g':
1431                         gr_set_color_fast(&Color_green);
1432                         break;
1433                 case 'b':
1434                         gr_set_color_fast(&Color_blue);
1435                         break;
1436                 default:        
1437                         Int3(); // unsupported meta-code
1438                         break;
1439         } // end switch
1440 }
1441
1442 // Display what stage of the briefing is active
1443 void brief_blit_stage_num(int stage_num, int stage_max)
1444 {
1445         char buf[64];
1446         // int w;
1447
1448         Assert( Briefing != NULL );
1449 #ifdef MAKE_FS1
1450         gr_set_color_fast(&Color_bright_blue);
1451 #else
1452         gr_set_color_fast(&Color_text_heading);
1453 #endif
1454         sprintf(buf, XSTR( "Stage %d of %d", 394), stage_num + 1, stage_max);
1455         if (Game_mode & GM_MULTIPLAYER) {
1456                 gr_printf(Brief_stage_text_coords_multi[gr_screen.res][0], Brief_stage_text_coords_multi[gr_screen.res][1], buf);
1457         } else {
1458                 gr_printf(Brief_stage_text_coords[gr_screen.res][0], Brief_stage_text_coords[gr_screen.res][1], buf);
1459         }
1460
1461         // draw the title of the mission        
1462         // if this goes above briefing text, it will need to be raised 10 pixels in multiplayer to make
1463         // room for stage num, which makes toom for chat box
1464         /*
1465         if (Game_mode & GM_MULTIPLAYER) {
1466                 gr_get_string_size(&w,NULL,The_mission.name);
1467                 gr_string(bscreen.map_x2 - w, bscreen.map_y2 + 5, The_mission.name);            
1468         } else {
1469                 gr_get_string_size(&w,NULL,The_mission.name);
1470                 gr_string(bscreen.map_x2 - w, bscreen.map_y2 + 5, The_mission.name);            
1471         }
1472         */
1473 }
1474
1475 // Render a line of text for the briefings.  Lines are drawn in as a wipe, with leading bright
1476 // white characters.  Have to jump through some hoops since we support colored words.  This means
1477 // that we need to process the line one character at a time.
1478 void brief_render_line(int line_num, int x, int y, int instance)
1479 {
1480         int len, count, next, truncate_len, last_color, offset, w, h, bright_len, i;
1481         colored_char *src;
1482         char line[MAX_BRIEF_LINE_LEN];
1483
1484         src = &Colored_text[instance][line_num][0];
1485         len = Colored_text_len[instance][line_num];
1486
1487         if (len <= 0){
1488                 return;
1489         }
1490
1491         truncate_len = fl2i(Brief_text_wipe_time_elapsed / BRIEF_TEXT_WIPE_TIME * Max_briefing_line_len);
1492         if (truncate_len > len){
1493                 truncate_len = len;
1494         }
1495
1496         bright_len = 0;
1497         if (truncate_len < len) {
1498                 if (truncate_len <= BRIGHTEN_LEAD) {
1499                         bright_len = truncate_len;
1500                         truncate_len = 0;
1501
1502                 } else {
1503                         bright_len = BRIGHTEN_LEAD;
1504                         truncate_len -= BRIGHTEN_LEAD; 
1505                 }
1506         }
1507
1508         offset = 0;
1509         count  = 0;
1510         next     = 0;
1511
1512         gr_set_color_fast(&Color_white);
1513         last_color = BRIEF_TEXT_WHITE;
1514         for (i=0; i<truncate_len; i++) {
1515                 if (count >= truncate_len){
1516                         break;
1517                 }
1518
1519                 line[next] = src[count].letter;
1520
1521                 if (is_white_space(line[next])) {
1522                         // end of word reached, blit it
1523                         line[next + 1] = 0;
1524                         gr_string(x + offset, y, line);
1525                         gr_get_string_size(&w, &h, line);
1526                         offset += w;
1527                         next = 0;
1528
1529                         // reset color
1530                         if (last_color != BRIEF_TEXT_WHITE) {
1531                                 brief_set_text_color(BRIEF_TEXT_WHITE);
1532                                 last_color = BRIEF_TEXT_WHITE;
1533                         }
1534
1535                         count++;
1536                         continue;
1537                 }
1538
1539                 if (src[count].color != last_color) {
1540                         brief_set_text_color(src[count].color);
1541                         last_color = src[count].color;
1542                 }
1543
1544                 count++;
1545                 next++;
1546         }       // end for
1547
1548         line[next] = 0;
1549         gr_string(x + offset, y, line);
1550
1551
1552         // draw leading portion of the line bright white
1553         if (bright_len) {
1554
1555                 gr_set_color_fast(&Color_bright_white);
1556                 for (i=0; i<truncate_len+bright_len; i++) {
1557                         line[i] = src[i].letter;
1558                 }
1559
1560                 line[i] = 0;
1561
1562
1563                 if ( truncate_len > 0 ) {
1564                         int width_dim, height_dim;
1565                         gr_get_string_size(&width_dim, &height_dim, line, truncate_len );
1566                         gr_string(x+width_dim, y, &line[truncate_len]);
1567                 } else {
1568                         gr_string(x, y, line);
1569                 }
1570
1571                 // JAS: Not needed?
1572                 //              // now erase the part we don't want to be bright white
1573                 //              gr_set_color_fast(&Color_black);
1574                 //              if (i > BRIGHTEN_LEAD) {
1575                 //                      line[i - BRIGHTEN_LEAD] = 0;
1576                 //                      gr_get_string_size(&w, &h, line);
1577                 //                      gr_set_clip(x, y, w, gr_get_font_height());
1578                 //                      gr_clear();
1579                 //                      gr_reset_clip();
1580                 //              }
1581         }
1582 }
1583
1584 int brief_text_wipe_finished()
1585 {
1586         if ( Brief_text_wipe_time_elapsed > (BRIEF_TEXT_WIPE_TIME+0.5f) ) {
1587                 return 1;
1588         }
1589
1590         return 0;
1591 }
1592
1593 // -------------------------------------------------------------------------------------
1594 // brief_render_text()
1595 //
1596 // input:       frametime       =>      Time in seconds of previous frame
1597 //                              instance                =>      Optional parameter.  Used to indicate which text stream is used.
1598 //                                                                      This value is 0 unless multiple text streams are required
1599 int brief_render_text(int line_offset, int x, int y, int h, float frametime, int instance, int line_spacing)
1600 {
1601         int fh, line, yy;
1602
1603         fh = gr_get_font_height();
1604         if (Brief_text_wipe_time_elapsed == 0) {
1605                 if (snd_is_playing(Brief_text_wipe_snd)) {
1606                         snd_stop(Brief_text_wipe_snd);
1607                 }
1608                 gamesnd_play_iface(SND_BRIEF_TEXT_WIPE);
1609                 Play_brief_voice = 1;
1610         }
1611
1612         Brief_text_wipe_time_elapsed += frametime;
1613
1614         line = line_offset;
1615         yy = 0;
1616         while (yy + fh <= h) {
1617                 if (line >= Num_brief_text_lines[instance])
1618                         break;
1619
1620                 brief_render_line(line, x, y + yy, instance);
1621
1622                 line++;
1623                 yy += fh + line_spacing;
1624         }
1625
1626         if ( brief_text_wipe_finished() && (Play_brief_voice) ) {
1627                 Play_brief_voice = 0;
1628                 return 1;
1629         }
1630
1631         return 0;
1632 }
1633
1634 // ------------------------------------------------------------------------------------
1635 // brief_render_elements()
1636 //
1637 // Draw the lines that show objects positions on the grid
1638 //
1639 void brief_render_elements(vector *pos, grid* gridp)
1640 {
1641         vector  gpos;   //      Location of point on grid.
1642 //      vector  tpos;
1643         float           dxz;
1644         plane           tplane;
1645         vector  *gv;
1646         
1647         if ( pos->xyz.y < 1 && pos->xyz.y > -1 )
1648                 return;
1649
1650         tplane.A = gridp->gmatrix.v.uvec.xyz.x;
1651         tplane.B = gridp->gmatrix.v.uvec.xyz.y;
1652         tplane.C = gridp->gmatrix.v.uvec.xyz.z;
1653         tplane.D = gridp->planeD;
1654
1655         compute_point_on_plane(&gpos, &tplane, pos);
1656
1657         dxz = vm_vec_dist(pos, &gpos)/8.0f;
1658
1659         gv = &gridp->gmatrix.v.uvec;
1660         if (gv->xyz.x * pos->xyz.x + gv->xyz.y * pos->xyz.y + gv->xyz.z * pos->xyz.z < -gridp->planeD)
1661                 gr_set_color(127, 127, 127);
1662         else
1663                 gr_set_color(255, 255, 255);   // white
1664
1665 // AL 11-20-97: don't draw elevation lines.. they are confusing
1666 /*
1667         brief_rpd_line(&gpos, pos);     //      Line from grid to object center.
1668
1669         tpos = gpos;
1670
1671         vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.rvec, -dxz/2);
1672         vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.fvec, -dxz/2);
1673         
1674         vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.rvec, dxz/2);
1675         vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.fvec, dxz/2);
1676         
1677         brief_rpd_line(&gpos, &tpos);
1678
1679         vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.rvec, dxz);
1680         vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.rvec, -dxz);
1681
1682         brief_rpd_line(&gpos, &tpos);
1683 */
1684 }
1685
1686
1687 // ------------------------------------------------------------------------------------
1688 // brief_reset_icons()
1689 //
1690 void brief_reset_icons(int stage_num)
1691 {
1692         brief_stage             *bs;
1693         brief_icon              *bi;
1694         int                             i;
1695
1696         Assert( Briefing != NULL );
1697         bs = &Briefing->stages[stage_num];
1698
1699         for ( i = 0; i < bs->num_icons; i++ ) {
1700                 bi = &bs->icons[i];
1701                 bi->flags &= ~BI_SHOWHIGHLIGHT;
1702         }
1703 }
1704
1705 // ------------------------------------------------------------------------------------
1706 // brief_set_camera_target()
1707 //
1708 //      input:  pos             =>              target position for the camera
1709 //                              orient  =>              target orientation for the camera
1710 //                              time            =>              time in ms to reach target
1711 //
1712 void brief_set_camera_target(vector *pos, matrix *orient, int time)
1713 {
1714         float time_in_seconds;
1715         
1716         time_in_seconds = time / 1000.0f;
1717
1718         if ( time == 0 ) {
1719                 Current_cam_pos = *pos;
1720                 Current_cam_orient = *orient;
1721         }
1722
1723         Target_cam_pos = *pos;
1724         Target_cam_orient = *orient;
1725         Start_cam_orient = Current_cam_orient;
1726         Start_cam_pos = Current_cam_pos;                                                                // we need this when checking if camera movement complete
1727         Start_cam_move = timer_get_milliseconds()*1000.0f;              // start time, convert to seconds
1728         Total_move_time = time_in_seconds;
1729         Elapsed_time = 0.0f;
1730
1731         vm_vec_scale_add(&Start_lookat_pos, &Start_cam_pos, &Start_cam_orient.v.fvec, LOOKAT_DIST);
1732         vm_vec_scale_add(&Target_lookat_pos, &Target_cam_pos, &Target_cam_orient.v.fvec, LOOKAT_DIST);
1733
1734         Play_highlight_flag = 1;                                                                // once target reached, play highlight anims
1735         Cam_target_reached = 0;
1736         Cam_movement_done=0;
1737         anim_release_all_instances(ON_BRIEFING_SELECT); // stop any briefing-specific anims
1738         
1739         // calculate camera velocity
1740         vm_vec_sub(&Cam_vel, pos, &Current_cam_pos);
1741 //      vm_vec_scale(&Cam_vel, 1.0f/time_in_seconds);
1742         if ( !IS_VEC_NULL(&Cam_vel) ) {
1743                 vm_vec_normalize(&Cam_vel);
1744         }
1745
1746         // calculate lookat point velocity
1747         vm_vec_sub(&Lookat_vel, &Target_lookat_pos, &Current_lookat_pos);
1748         vm_vec_scale(&Lookat_vel, 1.0f/time_in_seconds);
1749
1750         Start_dist = vm_vec_dist(&Start_cam_pos, &Start_lookat_pos);
1751         End_dist = vm_vec_dist(&Target_cam_pos, &Target_lookat_pos);
1752         Dist_change_rate = (End_dist - Start_dist) / time_in_seconds;
1753
1754         Total_dist=vm_vec_dist(&Start_cam_pos, &Target_cam_pos);
1755
1756 //      Peak_speed=Total_dist/Total_move_time*1.5f;
1757 //      Cam_accel = Peak_speed/Total_move_time*3.0f;
1758
1759         Peak_speed=Total_dist/Total_move_time*2.0f;
1760         Cam_accel = 4*Total_dist/(Total_move_time*Total_move_time);
1761         Last_dist=0.0f;
1762
1763         vm_vec_zero(&W_init);
1764
1765         get_camera_limits(&Start_cam_orient, &Target_cam_orient, Total_move_time, &Acc_limit, &Vel_limit);
1766 }
1767
1768
1769 ubyte brief_return_color_index(char c)
1770 {
1771         switch (c) {
1772                 case 'f':
1773                         return BRIEF_IFF_FRIENDLY;
1774
1775                 case 'h':
1776                         return BRIEF_IFF_HOSTILE;
1777
1778                 case 'n':
1779                         return BRIEF_IFF_NEUTRAL;
1780
1781                 case 'r':
1782                         return BRIEF_TEXT_RED;
1783
1784                 case 'g':
1785                         return BRIEF_TEXT_GREEN;
1786
1787                 case 'b':
1788                         return BRIEF_TEXT_BLUE;
1789
1790                 default:        
1791                         Int3(); // unsupported meta-code
1792                         break;
1793         } // end switch
1794
1795         return BRIEF_TEXT_WHITE;
1796 }
1797
1798 void brief_set_text_color(int color_index)
1799 {
1800         Assert(color_index < MAX_BRIEF_TEXT_COLORS);
1801         gr_set_color_fast(Brief_text_colors[color_index]);
1802 }
1803
1804 // Set up the Colored_text array.
1805 // input:               index           =>              Index into Brief_text[] for source text.
1806 //                                      instance        =>              Which instance of Colored_text[] to use.  
1807 //                                                                              Value is 0 unless multiple text streams are required.
1808 int brief_text_colorize(int index, int instance)
1809 {
1810         char *src;
1811         int len, i, skip_to_next_word, dest_len;
1812         colored_char *dest;
1813         ubyte active_color_index;
1814
1815         src = Brief_text[index];
1816         dest = &Colored_text[instance][index][0];
1817         len = strlen(src);
1818
1819         skip_to_next_word = 0;
1820         dest_len = 0;
1821         active_color_index = BRIEF_TEXT_WHITE;
1822         for (i=0; i<len; i++) {
1823                 if (skip_to_next_word) {
1824                         if (is_white_space(src[i])) {
1825                                 skip_to_next_word = 0;
1826                         }
1827
1828                         continue;
1829                 }
1830
1831                 if ( src[i] == BRIEF_META_CHAR && is_white_space(src[i + 2]) ) {
1832                         active_color_index = brief_return_color_index(src[i + 1]);
1833                         skip_to_next_word = 1;
1834                         continue;
1835                 }
1836
1837                 if (is_white_space(src[i])) {
1838                         active_color_index = BRIEF_TEXT_WHITE;
1839                 }
1840
1841                 dest[dest_len].letter = src[i];
1842                 dest[dest_len].color  = active_color_index;
1843                 dest_len++;
1844         } // end for
1845
1846         dest[dest_len].letter = 0;
1847         Colored_text_len[instance][index] = dest_len;
1848         return len;
1849 }
1850
1851 // ------------------------------------------------------------------------------------
1852 // brief_color_text_init()
1853 //
1854 //      input:  src             =>              paragraph of text to process
1855 //                              w                       =>              max width of line in pixels
1856 //                              instance        =>              optional parameter, used when multiple text streams are required
1857 //                                                                      (default value is 0)
1858 int brief_color_text_init(char *src, int w, int instance)
1859 {
1860         int i, n_lines, len;
1861         int n_chars[MAX_BRIEF_LINES];
1862         char *p_str[MAX_BRIEF_LINES];
1863         
1864         Assert(src);
1865         n_lines = split_str(src, w, n_chars, p_str, MAX_BRIEF_LINES, BRIEF_META_CHAR);
1866         Assert(n_lines >= 0);
1867
1868         Max_briefing_line_len = 1;
1869         for (i=0; i<n_lines; i++) {
1870                 Assert(n_chars[i] < MAX_BRIEF_LINE_LEN);
1871                 strncpy(Brief_text[i], p_str[i], n_chars[i]);
1872                 Brief_text[i][n_chars[i]] = 0;
1873                 drop_leading_white_space(Brief_text[i]);
1874                 len = brief_text_colorize(i, instance);
1875                 if (len > Max_briefing_line_len)
1876                         Max_briefing_line_len = len;
1877         }
1878
1879         Brief_text_wipe_time_elapsed = 0.0f;
1880         Play_brief_voice = 0;
1881
1882         Num_brief_text_lines[instance] = n_lines;
1883         return n_lines;
1884 }
1885
1886 // ------------------------------------------------------------------------------------
1887 // brief_get_free_move_icon()
1888 //
1889 //      returns:                failure =>              -1
1890 //                                      success =>              handle to a free move icon struct
1891 //
1892 int brief_get_free_move_icon()
1893 {
1894         int i;
1895
1896         for ( i = 0; i < MAX_MOVE_ICONS; i++ ) {
1897                 if ( Icon_movers[i].used == 0 )
1898                         break;
1899         }
1900         
1901         if ( i == MAX_MOVE_ICONS ) 
1902                 return -1;
1903
1904         Icon_movers[i].used = 1;
1905         return i;
1906 }
1907
1908
1909 // ------------------------------------------------------------------------------------
1910 // brief_set_move_list()
1911 //
1912 //      input:  new_stage               =>              new stage number that briefing is now moving to
1913 //                              current_stage   =>              current stage that the briefing is on
1914 //                              time                            =>              time in seconds
1915 //
1916 int brief_set_move_list(int new_stage, int current_stage, float time)
1917 {
1918         brief_stage             *newb, *cb;     
1919         icon_move_info  *imi;   
1920         int                             i,j,k,num_movers,is_gone=0;
1921         vector                  zero_v = ZERO_VECTOR;
1922
1923         Assert(new_stage != current_stage);
1924         
1925         Assert( Briefing != NULL );
1926         newb = &Briefing->stages[new_stage];
1927         cb = &Briefing->stages[current_stage];
1928         num_movers = 0;
1929         
1930         for ( i = 0; i < cb->num_icons; i++ ) {
1931                 is_gone=1;
1932                 for ( j = 0; j < newb->num_icons; j++ ) {
1933                         if ( ( cb->icons[i].id != 0 ) && ( cb->icons[i].id == newb->icons[j].id ) ) {
1934                                 is_gone=0;
1935                                 if ( vm_vec_cmp(&cb->icons[i].pos, &newb->icons[j].pos) ) {
1936                                         //nprintf(("Alan","We found a match in icon %s\n", cb->icons[i].label));
1937                                         k = brief_get_free_move_icon();                         
1938                                         if ( k == -1 ) {
1939                                                 Int3(); // should never happen, get Alan
1940                                                 return 0;
1941                                         }
1942                                         imi = &Icon_movers[k];
1943                                         imi->id = cb->icons[i].id;
1944                                         imi->start = cb->icons[i].pos;
1945                                         imi->finish = newb->icons[j].pos;
1946                                         imi->current = imi->start;
1947                                         list_append(&Icon_move_list, imi);
1948
1949                                         imi->total_dist = vm_vec_dist(&imi->start, &imi->finish);
1950                                         imi->total_move_time = time;
1951                                         imi->peak_speed = imi->total_dist/imi->total_move_time*2.0f;
1952                                         imi->accel = 4*imi->total_dist/(time*time);
1953                                         imi->last_dist=0.0f;
1954                                         imi->reached_dest=0;
1955                                         imi->direction = zero_v;
1956
1957                                         vm_vec_sub(&imi->direction, &imi->finish, &imi->start);
1958                                         if ( !IS_VEC_NULL(&imi->direction) ) {
1959                                                 vm_vec_normalize(&imi->direction);
1960                                         }
1961
1962                                         num_movers++;
1963                                 }
1964                         }
1965                 }
1966
1967                 // Set up fading icon (to fade out)
1968                 if (is_gone == 1) {
1969                         if ( Num_fade_icons >= MAX_FADE_ICONS ) {
1970                                 Int3();
1971                                 Num_fade_icons=0;
1972                         }
1973
1974                         int species = ship_get_species_by_type(cb->icons[i].ship_class);
1975                         if(species < 0) {
1976                                 return 0;
1977                         }
1978
1979                         Fading_icons[Num_fade_icons].fade_anim = Icon_fade_anims[cb->icons[i].type][species];
1980                         Fading_icons[Num_fade_icons].pos = cb->icons[i].pos;
1981                         Fading_icons[Num_fade_icons].team = cb->icons[i].team;
1982                         Num_fade_icons++;
1983                 }
1984         }
1985
1986         // flag new icons for fading in
1987         for ( i=0; i<newb->num_icons; i++ ) {
1988                 int is_new = 1;
1989                 newb->icons[i].flags &= ~BI_FADEIN;
1990                 for ( j=0; j<cb->num_icons; j++ ) {
1991                         if ( ( cb->icons[j].id != 0 ) && ( cb->icons[j].id == newb->icons[i].id ) ) {
1992                                 is_new=0;
1993                         }
1994                 }
1995                 if ( is_new ) {
1996                         int species = ship_get_species_by_type(newb->icons[i].ship_class);
1997                         if(species < 0) {
1998                                 return 0;
1999                         }
2000
2001                         newb->icons[i].flags |= BI_FADEIN;
2002                         newb->icons[i].fadein_anim = Icon_fade_anims[newb->icons[i].type][species];
2003                         newb->icons[i].fadein_anim.time_elapsed = 0.0f;
2004                 }
2005         }
2006
2007         return num_movers;
2008 }
2009
2010 void brief_clear_fade_out_icons()
2011 {
2012         Num_fade_icons = 0;
2013 }
2014
2015
2016 // ------------------------------------------------------------------------------------
2017 // brief_set_new_stage()
2018 //
2019 //      input:  pos                     =>              target position for the camera
2020 //                              orient          =>              target orientation for the camera
2021 //                              time                    =>              time in ms to reach target
2022 //                              stage_num       =>              stage number of briefing (start numbering at 0)
2023 //
2024
2025 void brief_set_new_stage(vector *pos, matrix *orient, int time, int stage_num)
2026 {
2027         char msg[MAX_BRIEF_LEN];
2028         int num_movers, new_time, not_objv = 1;
2029
2030         Assert( Briefing != NULL );
2031         new_time = time;
2032
2033         if (stage_num >= Briefing->num_stages) {
2034                 not_objv = 0;  // turns out this is an objectives stage
2035                 new_time = 0;
2036         }
2037
2038         if ( stage_num == Last_new_stage ) {
2039                 return;
2040         }
2041
2042         num_movers = 0;
2043         brief_move_icon_reset();
2044         brief_clear_fade_out_icons();
2045         if ( (Last_new_stage != -1) && not_objv ) {
2046                 num_movers = brief_set_move_list(stage_num, Last_new_stage, new_time / 1000.0f);
2047         }
2048
2049         if ( (Last_new_stage != -1) && (num_movers == 0) && not_objv ) {
2050                 if ( !vm_vec_cmp( &Briefing->stages[stage_num].camera_pos, &Briefing->stages[Last_new_stage].camera_pos) ) {
2051                         if ( !vm_vec_cmp( &Briefing->stages[stage_num].camera_orient.v.fvec, &Briefing->stages[Last_new_stage].camera_orient.v.fvec) ){
2052                                 new_time = 0;
2053                         }
2054                 }
2055         }
2056
2057         if (not_objv) {
2058                 if(Briefing->stages[stage_num].new_text == NULL){
2059                         strcpy(msg, "");
2060                 } else {
2061                         strcpy(msg, Briefing->stages[stage_num].new_text);
2062                 }
2063         } else {
2064                 strcpy(msg, XSTR( "Please review your objectives for this mission.", 395));
2065         }
2066
2067         if (gr_screen.res == GR_640) {
2068                 // GR_640
2069                 Num_brief_text_lines[0] = brief_color_text_init(msg, MAX_BRIEF_LINE_W_640);
2070         } else {
2071                 // GR_1024
2072                 Num_brief_text_lines[0] = brief_color_text_init(msg, MAX_BRIEF_LINE_W_1024);            
2073         }
2074         Top_brief_text_line = 0;
2075
2076         if (not_objv){
2077                 brief_set_camera_target(pos, orient, new_time);
2078         }
2079
2080         if ( snd_is_playing(Brief_stage_highlight_sound_handle) ) {
2081                 snd_stop(Brief_stage_highlight_sound_handle);
2082         }
2083
2084         Brief_voice_ended = 0;
2085         Brief_textdraw_finished = 0;
2086         Brief_voice_started = 0;
2087         Brief_stage_time = 0;
2088
2089
2090         Brief_stage_highlight_sound_handle = -1;
2091         Last_new_stage = stage_num;
2092 }
2093
2094 // ------------------------------------------------------------------------------------
2095 // camera_pos_past_target()
2096 //
2097 //
2098 int camera_pos_past_target(vector *start, vector *current, vector *dest)
2099 {
2100         vector num, den;
2101         float ratio;
2102
2103         vm_vec_sub(&num, current, start);
2104         vm_vec_sub(&den, start, dest);
2105
2106         ratio = vm_vec_mag_quick(&num) / vm_vec_mag_quick(&den);
2107         if (ratio >= 1.0f)
2108                 return TRUE;
2109         
2110         return FALSE;
2111 }
2112
2113 // ------------------------------------------------------------------------------------
2114 // Interpolate between matrices.
2115 // elapsed_time/total_time gives percentage of interpolation between cur
2116 // and goal.
2117 void interpolate_matrix(matrix *result, matrix *goal, matrix *start, float elapsed_time, float total_time)
2118 {
2119         vector fvec, rvec;
2120         float   time0, time1;
2121         
2122         if ( !vm_matrix_cmp( goal, start ) ) {
2123                 return;
2124         }       
2125
2126         time0 = elapsed_time / total_time;
2127         time1 = (total_time - elapsed_time) / total_time;
2128
2129         vm_vec_copy_scale(&fvec, &start->v.fvec, time1);
2130         vm_vec_scale_add2(&fvec, &goal->v.fvec, time0);
2131
2132         vm_vec_copy_scale(&rvec, &start->v.rvec, time1);
2133         vm_vec_scale_add2(&rvec, &goal->v.rvec, time0);
2134
2135         vm_vector_2_matrix(result, &fvec, NULL, &rvec);
2136  }
2137
2138 // calculate how far the camera should have moved
2139 float brief_camera_get_dist_moved(float elapsed_time)
2140 {
2141         float time, dist_moved=0.0f;
2142         
2143         // first half of movement
2144         if ( elapsed_time < Total_move_time/2.0f ) {
2145                 dist_moved=0.5f*Cam_accel*elapsed_time*elapsed_time;    // d = 1/2at^2
2146                 return dist_moved;
2147         }
2148
2149         // second half of movement
2150         time=elapsed_time - Total_move_time/2.0f;
2151         dist_moved=(Total_dist/2.0f)+(Peak_speed*time) - 0.5f*Cam_accel*time*time;
2152         return dist_moved;
2153
2154 }
2155
2156 // ------------------------------------------------------------------------------------
2157 // Update the camera position
2158 void brief_camera_move(float frametime, int stage_num)
2159 {
2160         vector  dist_moved;
2161         float           dist;
2162         vector  w_out;
2163         matrix  result;
2164
2165         Elapsed_time += frametime;
2166
2167         if ( Cam_target_reached ) { 
2168 //              Current_cam_pos = Target_cam_pos;
2169 //              Current_lookat_pos = Target_lookat_pos;
2170 //              Current_cam_orient = Target_cam_orient;
2171                 return;
2172         }
2173
2174         // Update orientation
2175         if ( (Elapsed_time < Total_move_time) ) {
2176 //              interpolate_matrix(&Current_cam_orient, &Target_cam_orient, &Start_cam_orient, Elapsed_time, Total_move_time );
2177                 vm_matrix_interpolate(&Target_cam_orient, &Current_cam_orient, &W_init, frametime, &result, &w_out, &Vel_limit, &Acc_limit);
2178                 Current_cam_orient = result;
2179                 W_init = w_out;
2180         }
2181
2182         /*
2183         // interpolate lookat position
2184         if ( vm_vec_cmp( &Current_lookat_pos, &Target_lookat_pos ) ) {
2185                 vm_vec_copy_scale(&dist_moved, &Lookat_vel, Elapsed_time);
2186                 vm_vec_add(&Current_lookat_pos, &Start_lookat_pos, &dist_moved);
2187
2188                 if ( camera_pos_past_target(&Start_lookat_pos, &Current_lookat_pos, &Target_lookat_pos) ) {
2189                         Current_lookat_pos = Target_lookat_pos;
2190                 }
2191         }
2192
2193         cur_dist = Start_dist + Dist_change_rate * Elapsed_time;
2194         vm_vec_copy_scale(&dist_moved, &Current_cam_orient.v.fvec, -cur_dist);
2195         vm_vec_add(&Current_cam_pos, &Current_lookat_pos, &dist_moved);
2196         */
2197
2198         // use absolute pos to update position
2199         if ( vm_vec_cmp( &Current_cam_pos, &Target_cam_pos ) ) {
2200                 dist = brief_camera_get_dist_moved(Elapsed_time);
2201                 if ( dist < Last_dist ) {
2202                         Cam_movement_done=1;
2203                         Last_dist=0.0f;
2204                 }
2205                 Last_dist=dist;
2206
2207                 if ( Cam_movement_done == 0 ) {
2208                         vm_vec_copy_scale(&dist_moved, &Cam_vel, dist);
2209                         vm_vec_add(&Current_cam_pos, &Start_cam_pos, &dist_moved);
2210                 } else {
2211                         Current_cam_pos=Target_cam_pos;
2212                 }
2213         }
2214         else {
2215                 Cam_movement_done=1;
2216                 Current_cam_pos=Target_cam_pos;
2217         }
2218
2219         if ( Cam_movement_done && (Elapsed_time >= Total_move_time) ) {
2220                 Cam_target_reached=1;
2221         }
2222 }
2223
2224 //      Project the viewer's position onto the grid plane.  If more than threshold distance
2225 //      from grid center, move grid center.
2226 void brief_maybe_create_new_grid(grid* gridp, vector *pos, matrix *orient, int force)
2227 {
2228         int roundoff;
2229         plane   tplane;
2230         vector  gpos, tmp, c;
2231         float   dist_to_plane;
2232         float   square_size, ux, uy, uz;
2233
2234         ux = tplane.A = gridp->gmatrix.v.uvec.xyz.x;
2235         uy = tplane.B = gridp->gmatrix.v.uvec.xyz.y;
2236         uz = tplane.C = gridp->gmatrix.v.uvec.xyz.z;
2237         tplane.D = gridp->planeD;
2238
2239         compute_point_on_plane(&c, &tplane, pos);
2240         dist_to_plane = fl_abs(vm_dist_to_plane(pos, &gridp->gmatrix.v.uvec, &c));
2241         square_size = 1.0f;
2242
2243         while (dist_to_plane >= 25.0f)
2244         {
2245                 square_size *= 10.0f;
2246                 dist_to_plane /= 10.0f;
2247         }
2248         
2249         if (fvi_ray_plane(&gpos, &gridp->center, &gridp->gmatrix.v.uvec, pos, &orient->v.fvec, 0.0f)<0.0f)      {
2250                 vector p;
2251                 vm_vec_scale_add(&p,pos,&orient->v.fvec, 100.0f );
2252                 compute_point_on_plane(&gpos, &tplane, &p );
2253         }
2254
2255         if (vm_vec_dist(&gpos, &c) > 50.0f * square_size)
2256         {
2257                 vm_vec_sub(&tmp, &gpos, &c);
2258                 vm_vec_normalize(&tmp);
2259                 vm_vec_scale_add(&gpos, &c, &tmp, 50.0f * square_size);
2260         }
2261
2262         roundoff = (int) square_size * 10;
2263         if (!ux)
2264                 gpos.xyz.x = fl_roundoff(gpos.xyz.x, roundoff);
2265         if (!uy)
2266                 gpos.xyz.y = fl_roundoff(gpos.xyz.y, roundoff);
2267         if (!uz)
2268                 gpos.xyz.z = fl_roundoff(gpos.xyz.z, roundoff);
2269
2270         if ((square_size != gridp->square_size) ||
2271                 (gpos.xyz.x != gridp->center.xyz.x) ||
2272                 (gpos.xyz.y != gridp->center.xyz.y) ||
2273                 (gpos.xyz.z != gridp->center.xyz.z) || force)
2274         {
2275                 gridp->square_size = square_size;
2276                 gridp->center = gpos;
2277                 brief_modify_grid(gridp);
2278         }
2279 }
2280
2281 //      Create a grid
2282 //      *forward is vector pointing forward
2283 //      *right is vector pointing right
2284 //      *center is center point of grid
2285 //      length is length of grid
2286 //      width is width of grid
2287 //      square_size is size of a grid square
2288 //      For example:
2289 //              *forward = (0.0, 0.0, 1.0)
2290 //              *right   = (1.0, 0.0, 0.0)
2291 //              *center = (0.0, 0.0, 0.0)
2292 //              nrows = 10
2293 //              ncols =  50.0
2294 //              square_size = 10.0
2295 //      will generate a grid of squares 10 long by 5 wide.
2296 //      Each grid square will be 10.0 x 10.0 units.
2297 //      The center of the grid will be at the global origin.
2298 //      The grid will be parallel to the xz plane (because the normal is 0,1,0).
2299 //      (In fact, it will be the xz plane because it is centered on the origin.)
2300 //
2301 //      Stuffs grid in *gridp.  If gridp == NULL, mallocs and returns a grid.
2302 grid *brief_create_grid(grid *gridp, vector *forward, vector *right, vector *center, int nrows, int ncols, float square_size)
2303 {
2304         int     i, ncols2, nrows2, d = 1;
2305         vector  dfvec, drvec, cur, cur2, tvec, uvec, save, save2;
2306
2307         Assert(square_size > 0.0);
2308         if (double_fine_gridlines)
2309                 d = 2;
2310
2311         if (gridp == NULL)
2312                 gridp = (grid *) malloc(sizeof(grid));
2313
2314         Assert(gridp);
2315
2316         gridp->center = *center;
2317         gridp->square_size = square_size;
2318
2319         //      Create the plane equation.
2320         Assert(!IS_VEC_NULL(forward));
2321         Assert(!IS_VEC_NULL(right));
2322
2323         vm_vec_copy_normalize(&dfvec, forward);
2324         vm_vec_copy_normalize(&drvec, right);
2325
2326         vm_vec_cross(&uvec, &dfvec, &drvec);
2327         
2328         Assert(!IS_VEC_NULL(&uvec));
2329
2330         gridp->gmatrix.v.uvec = uvec;
2331
2332         gridp->planeD = -(center->xyz.x * uvec.xyz.x + center->xyz.y * uvec.xyz.y + center->xyz.z * uvec.xyz.z);
2333         Assert(!_isnan(gridp->planeD));
2334
2335         gridp->gmatrix.v.fvec = dfvec;
2336         gridp->gmatrix.v.rvec = drvec;
2337
2338         vm_vec_scale(&dfvec, square_size);
2339         vm_vec_scale(&drvec, square_size);
2340
2341         vm_vec_scale_add(&cur, center, &dfvec, (float) -nrows * d / 2);
2342         vm_vec_scale_add2(&cur, &drvec, (float) -ncols * d / 2);
2343         vm_vec_scale_add(&cur2, center, &dfvec, (float) -nrows * 5 / 2);
2344         vm_vec_scale_add2(&cur2, &drvec, (float) -ncols * 5 / 2);
2345         save = cur;
2346         save2 = cur2;
2347
2348         gridp->ncols = ncols;
2349         gridp->nrows = nrows;
2350         ncols2 = ncols / 2;
2351         nrows2 = nrows / 2;
2352         Assert(ncols < MAX_GRIDLINE_POINTS && nrows < MAX_GRIDLINE_POINTS);
2353
2354         // Create the points along the edges of the grid, so we can just draw lines
2355         // between them to form the grid.  
2356         for (i=0; i<=ncols*d; i++) {
2357                 gridp->gpoints1[i] = cur;  // small, dark gridline points
2358                 vm_vec_scale_add(&tvec, &cur, &dfvec, (float) nrows * d);
2359                 gridp->gpoints2[i] = tvec;
2360                 vm_vec_add2(&cur, &drvec);
2361         }
2362
2363         for (i=0; i<=ncols2; i++) {
2364                 gridp->gpoints5[i] = cur2;  // large, brighter gridline points
2365                 vm_vec_scale_add(&tvec, &cur2, &dfvec, (float) nrows2 * 10);
2366                 gridp->gpoints6[i] = tvec;
2367                 vm_vec_scale_add2(&cur2, &drvec, 10.0f);
2368         }
2369
2370         cur = save;
2371         cur2 = save2;
2372         for (i=0; i<=nrows*d; i++) {
2373                 gridp->gpoints3[i] = cur;  // small, dark gridline points
2374                 vm_vec_scale_add(&tvec, &cur, &drvec, (float) ncols * d);
2375                 gridp->gpoints4[i] = tvec;
2376                 vm_vec_add2(&cur, &dfvec);
2377         }
2378
2379         for (i=0; i<=nrows2; i++) {
2380                 gridp->gpoints7[i] = cur2;  // large, brighter gridline points
2381                 vm_vec_scale_add(&tvec, &cur2, &drvec, (float) ncols2 * 10);
2382                 gridp->gpoints8[i] = tvec;
2383                 vm_vec_scale_add2(&cur2, &dfvec, 10.0f);
2384         }
2385
2386         return gridp;
2387 }
2388
2389 //      Create a nice grid -- centered at origin, 10x10, 10.0 size squares, in xz plane.
2390 grid *brief_create_default_grid(void)
2391 {
2392         grid    *rgrid;
2393         vector  fvec, rvec, cvec;
2394
2395         rgrid = brief_create_grid(&Global_grid, vm_vec_make(&fvec, 0.0f, 0.0f, 1.0f),
2396                 vm_vec_make(&rvec, 1.0f, 0.0f, 0.0f),
2397                 vm_vec_make(&cvec, 0.0f, -10.0f, 0.0f), 100, 100, 5.0f);
2398
2399         physics_init(&rgrid->physics);
2400         rgrid->physics.flags |= (PF_ACCELERATES | PF_SLIDE_ENABLED);
2401         return rgrid;
2402 }
2403
2404 //      Rotate and project points and draw a line.
2405 void brief_rpd_line(vector *v0, vector *v1)
2406 {
2407         vertex  tv0, tv1;
2408         g3_rotate_vertex(&tv0, v0);
2409         g3_rotate_vertex(&tv1, v1);
2410
2411 /*
2412         g3_project_vertex(&tv0);        
2413         g3_project_vertex(&tv1);
2414
2415         if ( (tv0.flags & PF_OVERFLOW) || (tv1.flags & PF_OVERFLOW) )
2416                 return;
2417 */
2418
2419         gr_set_color_fast(&Color_grey);
2420         g3_draw_line(&tv0, &tv1);
2421 }
2422
2423 //      Renders a grid defined in a grid struct
2424 void brief_render_grid(grid *gridp)
2425 {
2426         int     i, ncols, nrows;
2427
2428         ncols = gridp->ncols;
2429         nrows = gridp->nrows;
2430         if (double_fine_gridlines)
2431         {
2432                 ncols *= 2;
2433                 nrows *= 2;
2434         }
2435
2436         gr_set_color(30,30,30);
2437 //      SET_DARK;
2438
2439         //      Draw the column lines.
2440         for (i=0; i<=ncols; i++)
2441                 brief_rpd_line(&gridp->gpoints1[i], &gridp->gpoints2[i]);
2442
2443         //      Draw the row lines.
2444         for (i=0; i<=nrows; i++)
2445                 brief_rpd_line(&gridp->gpoints3[i], &gridp->gpoints4[i]);
2446
2447         ncols = gridp->ncols / 2;
2448         nrows = gridp->nrows / 2;
2449
2450         // now draw the larger, brighter gridlines that is x10 the scale of smaller one.
2451 //      SET_MEDIUM;
2452 /*
2453         for (i=0; i<=ncols; i++)
2454                 brief_rpd_line(&gridp->gpoints5[i], &gridp->gpoints6[i]);
2455
2456         for (i=0; i<=nrows; i++)
2457                 brief_rpd_line(&gridp->gpoints7[i], &gridp->gpoints8[i]);
2458 */
2459 }
2460
2461 void brief_modify_grid(grid *gridp)
2462 {
2463         brief_create_grid(gridp, &gridp->gmatrix.v.fvec, &gridp->gmatrix.v.rvec, &gridp->center,
2464                 gridp->nrows, gridp->ncols, gridp->square_size);
2465 }
2466
2467 void brief_unload_anims()
2468 {
2469 #ifndef MAKE_FS1
2470         int idx;
2471 #endif
2472         int i;
2473         
2474         for (i=0; i<MAX_BRIEF_ICONS; i++) {
2475 #ifndef MAKE_FS1
2476                 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
2477                         hud_anim_release(&Icon_highlight_anims[i][idx]);
2478                         hud_anim_release(&Icon_fade_anims[i][idx]);
2479                 }
2480 #else
2481                 // one set of icons in FS1
2482                 hud_anim_release(&Icon_highlight_anims[i][1]);
2483                 hud_anim_release(&Icon_fade_anims[i][1]);
2484 #endif
2485         }
2486 }
2487
2488 void brief_common_close()
2489 {
2490         brief_close_map();
2491         brief_unload_anims();
2492 }
2493
2494
2495 void brief_restart_text_wipe()
2496 {
2497         Brief_stage_time = 0;
2498         Brief_voice_ended = 0;
2499         Brief_voice_started = 0;
2500         Brief_text_wipe_time_elapsed = 0.0f;
2501 }
2502
2503 // initialize the array of handles to the different voice streams
2504 void brief_voice_init()
2505 {
2506         int i;
2507         for ( i = 0; i < MAX_BRIEF_STAGES; i++ ) {
2508                 Brief_voices[i] = -1;
2509         }
2510 }
2511
2512 void brief_load_voice_file(int voice_num, char *name)
2513 {
2514         int load_attempts = 0;
2515         while(1) {
2516
2517                 if ( load_attempts++ > 5 ) {
2518                         break;
2519                 }
2520
2521                 Brief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
2522                 if ( Brief_voices[voice_num] >= 0 ) {
2523                         break;
2524                 }
2525
2526                 // Don't bother to ask for the CD in multiplayer
2527                 if ( Game_mode & GM_MULTIPLAYER ) {
2528                         break;
2529                 }
2530
2531                 // couldn't load animation, ask user to insert CD (if necessary)
2532                 // if ( Brief_voice_ask_for_cd ) {
2533                         // if ( game_do_cd_check() == 0 ) {
2534                                 // Brief_voice_ask_for_cd = 0;
2535                                 // break;
2536                         // }
2537                 // }
2538         }
2539 }
2540
2541 // open and pre-load the stream buffers for the different voice streams
2542 void brief_voice_load_all()
2543 {
2544         int                     i;
2545         brief_stage     *bs;
2546
2547         // Brief_voice_ask_for_cd = 1;
2548
2549         Assert( Briefing != NULL );
2550         for ( i = 0; i < Briefing->num_stages; i++ ) {
2551                 bs = &Briefing->stages[i];
2552                 if ( strnicmp(bs->voice, NOX("none"), 4) ) {
2553                         brief_load_voice_file(i, bs->voice);
2554 //                      Brief_voices[i] = audiostream_open( bs->voice, ASF_VOICE );
2555                 }
2556         }
2557 }
2558
2559 // close all the briefing voice streams
2560 void brief_voice_unload_all()
2561 {
2562         int i;
2563
2564         for ( i = 0; i < MAX_BRIEF_STAGES; i++ ) {
2565                 if ( Brief_voices[i] != -1 ) {
2566                         audiostream_close_file(Brief_voices[i], 0);
2567                         Brief_voices[i] = -1;
2568                 }
2569         }
2570 }
2571
2572 // start playback of the voice for a particular briefing stage
2573 void brief_voice_play(int stage_num)
2574 {
2575         if ( Brief_voices[stage_num] == -1 )
2576                 return; // voice file doesn't exist
2577
2578         if ( !Briefing_voice_enabled ) {
2579                 return;
2580         }
2581
2582         if ( audiostream_is_playing( Brief_voices[stage_num]) )
2583                 return;
2584
2585         audiostream_play(Brief_voices[stage_num], Master_voice_volume, 0);
2586         Brief_voice_started = 1;
2587 }
2588
2589 // stop playback of the voice for a particular briefing stage
2590 void brief_voice_stop(int stage_num)
2591 {
2592         if ( Brief_voices[stage_num] == -1 )
2593                 return;
2594
2595         audiostream_stop(Brief_voices[stage_num]);      // stream is automatically rewound
2596 }
2597
2598 // pause playback of the voice for a particular briefing stage, to resume just
2599 // call brief_voice_unpause() again
2600 void brief_voice_pause(int stage_num)
2601 {
2602         if ( Brief_voices[stage_num] == -1 )
2603                 return;
2604
2605         audiostream_pause(Brief_voices[stage_num]);
2606 }
2607
2608 void brief_voice_unpause(int stage_num)
2609 {
2610         if ( Brief_voices[stage_num] == -1 )
2611                 return;
2612
2613         audiostream_unpause(Brief_voices[stage_num]);
2614 }
2615
2616 void brief_reset_last_new_stage()
2617 {
2618         Last_new_stage = -1;
2619 }
2620
2621 // get the dimensions for a briefing icon
2622 void brief_common_get_icon_dimensions(int *w, int *h, int type, int ship_class)
2623 {
2624         Assert(type >= 0 && type < MAX_BRIEF_ICONS);
2625
2626         // in case anything goes wrong
2627         *w=0;
2628         *h=0;
2629
2630         int species = ship_get_species_by_type(ship_class);
2631         if(species < 0){
2632                 return;
2633         }
2634
2635         if ( Icon_bitmaps[type][species].first_frame >= 0 ) {
2636                 bm_get_info( Icon_bitmaps[type][species].first_frame, w, h, NULL);
2637         } else {
2638                 *w=0;
2639                 *h=0;
2640         }
2641 }
2642
2643 void cmd_brief_reset()
2644 {
2645         int i, j;
2646         static int inited = 0;
2647
2648         if (inited) {
2649                 for (i=0; i<MAX_TEAMS; i++) {
2650                         for (j=0; j<Cmd_briefs[i].num_stages; j++) {
2651                                 if (Cmd_briefs[i].stage[j].text)
2652                                         free(Cmd_briefs[i].stage[j].text);
2653                         }
2654                 }
2655         }
2656
2657         inited = 1;
2658         for (i=0; i<MAX_TEAMS; i++)
2659                 Cmd_briefs[i].num_stages = 0;
2660 }
2661
2662 #define STAGE_ADVANCE_DELAY     1000            // time in ms to wait after voice stops before advancing stage
2663
2664 // should briefing advance to the next stage?
2665 int brief_time_to_advance(int stage_num, float frametime)
2666 {
2667         int voice_active, advance = 0;
2668         brief_icon *closeup_icon;
2669
2670         closeup_icon = brief_get_closeup_icon();
2671
2672         if ( closeup_icon ) {
2673                 return 0;
2674         }
2675
2676         if ( !Player->auto_advance ) {
2677                 return 0;
2678         }
2679
2680         Brief_stage_time += fl2i(frametime*1000 + 0.5f);
2681
2682         if ( (Brief_voices[stage_num] >= 0) && Briefing_voice_enabled ) {
2683                 voice_active = 1;
2684         } else {
2685                 voice_active = 0;
2686         }
2687
2688         if ( voice_active && (Brief_voice_ended == 0) && Brief_voice_started) {
2689                 if ( !audiostream_is_playing( Brief_voices[stage_num]) ) {
2690                         Brief_voice_ended = 1;
2691                         Brief_stage_time = 0;
2692                 }
2693         }
2694         
2695         if ( Brief_voice_ended ) {
2696                 if ( Brief_stage_time > STAGE_ADVANCE_DELAY ) {
2697                         advance = 1;
2698                 }
2699         }
2700
2701         if ( !voice_active && (Brief_textdraw_finished > 0) ) {
2702                 if ( Brief_stage_time > max(5000, Num_brief_text_lines[0] * 3500) ) {
2703                         advance = 1;
2704                 }
2705         }
2706
2707         return advance;
2708 }
2709