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