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