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