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