2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Mission/MissionBriefCommon.cpp $
15 * C module for briefing code common to FreeSpace and FRED
18 * Revision 1.12 2005/10/01 22:04:58 taylor
19 * fix FS1 (de)briefing voices, the directory names are different in FS1
20 * hard code the table values so that the fs1.vp file isn't needed
21 * hard code a mission fix for sm2-08a since a have no idea how to fix it otherwise
22 * generally cleanup some FS1 code
23 * fix volume sliders in the options screen that never went all the way up
25 * Revision 1.11 2004/09/20 01:31:44 theoddone33
28 * Revision 1.10 2004/07/04 11:39:06 taylor
29 * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
31 * Revision 1.9 2003/06/11 18:30:32 taylor
34 * Revision 1.8 2003/06/03 04:00:40 taylor
35 * Polish language support (Janusz Dziemidowicz)
37 * Revision 1.7 2003/05/25 02:30:42 taylor
40 * Revision 1.6 2002/06/17 06:33:09 relnev
41 * ryan's struct patch for gcc 2.95
43 * Revision 1.5 2002/06/09 04:41:22 relnev
44 * added copyright header
46 * Revision 1.4 2002/06/02 04:26:34 relnev
49 * Revision 1.3 2002/06/01 07:12:33 relnev
50 * a few NDEBUG updates.
52 * removed a few warnings.
54 * Revision 1.2 2002/05/07 03:16:46 theoddone33
55 * The Great Newline Fix
57 * Revision 1.1.1.1 2002/05/03 03:28:10 root
61 * 19 11/02/99 3:23p Jefff
62 * translate briefing icon names
64 * 18 9/09/99 9:44a Jefff
65 * doh, fixed reversed brief text color thingy. i am stoopid.
67 * 17 9/08/99 11:14a Jefff
68 * toned down hostile/friendly colors in briefing text
70 * 16 9/07/99 12:20p Mikeb
71 * return pos of briefing icon even it does not fit on screen.
73 * 15 9/03/99 1:32a Dave
74 * CD checking by act. Added support to play 2 cutscenes in a row
75 * seamlessly. Fixed super low level cfile bug related to files in the
76 * root directory of a CD. Added cheat code to set campaign mission # in
79 * 14 8/10/99 7:28p Jefff
80 * shuffled some text around
82 * 13 7/30/99 3:05p Jefff
83 * Fixed briefing icon fades -- in and out were reversed.
85 * 12 7/26/99 1:52p Mikeb
86 * Fixed strange briefing bug where a NULL wasn't being checked for when
87 * copying briefing stage text. Odd.
89 * 11 7/24/99 6:15p Jefff
90 * moved "stage x of y" text in multiplayer mode so its not covered by the
93 * 10 7/20/99 7:09p Jefff
94 * briefing text occupies full window in 1024x768
96 * 9 7/09/99 5:54p Dave
97 * Seperated cruiser types into individual types. Added tons of new
98 * briefing icons. Campaign screen.
100 * 8 6/29/99 7:39p Dave
101 * Lots of small bug fixes.
103 * 7 2/05/99 7:19p Neilk
104 * Removed black part from mission screen, fixed info text coords
106 * 6 1/29/99 4:17p Dave
107 * New interface screens.
109 * 5 12/18/98 1:13a Dave
110 * Rough 1024x768 support for Direct3D. Proper detection and usage through
113 * 4 10/23/98 3:51p Dave
114 * Full support for tstrings.tbl and foreign languages. All that remains
115 * is to make it active in Fred.
117 * 3 10/13/98 9:28a Dave
118 * Started neatening up freespace.h. Many variables renamed and
119 * reorganized. Added AlphaColors.[h,cpp]
121 * 2 10/07/98 10:53a Dave
124 * 1 10/07/98 10:49a Dave
126 * 122 6/09/98 10:31a Hoffoss
127 * Created index numbers for all xstr() references. Any new xstr() stuff
128 * added from here on out should be added to the end if the list. The
129 * current list count can be found in FreeSpace.cpp (search for
132 * 121 6/05/98 9:54a Lawrance
135 * 120 6/01/98 11:43a John
136 * JAS & MK: Classified all strings for localization.
138 * 119 5/23/98 10:38p Lawrance
139 * Avoid doing a cfile refresh when running debug
141 * 118 5/23/98 6:49p Lawrance
142 * Fix problems with refreshing the file list when a CD is inserted
144 * 117 5/21/98 6:57p Lawrance
145 * Don't prompt for the CD if voice not found
147 * 116 5/21/98 12:35a Lawrance
148 * Tweak how CD is checked for
150 * 115 5/12/98 11:46a John
151 * Changed the way the "glowing movement" type text draw. Use Hoffoss's
152 * gr_get_string_size optional length parameter to determine length of
153 * string which accounts for kerning on the last character and then I only
154 * draw each character only once.
156 * 114 5/08/98 5:32p Lawrance
157 * prompt for CD if can't load animations or voice
159 * 113 5/06/98 5:30p John
160 * Removed unused cfilearchiver. Removed/replaced some unused/little used
161 * graphics functions, namely gradient_h and _v and pixel_sp. Put in new
162 * DirectX header files and libs that fixed the Direct3D alpha blending
165 * 112 4/27/98 9:08p Allender
166 * fix the debriefing stage problems when clients get to screen long after
169 * 111 4/25/98 3:49p Lawrance
170 * Save briefing auto-advance pref
172 * 110 4/20/98 3:53p Lawrance
173 * Fix various bugs with auto-advancing through briefings.
178 #include "freespace.h"
186 #include "linklist.h"
193 #include "missionbrief.h"
194 #include "missiongrid.h"
195 #include "missionbriefcommon.h"
196 #include "animplay.h"
202 #include "audiostr.h"
203 #include "missioncmdbrief.h"
204 #include "missiondebrief.h"
205 #include "alphacolors.h"
206 #include "localize.h"
209 // --------------------------------------------------------------------------------------
211 // --------------------------------------------------------------------------------------
212 hud_frames Icon_bitmaps[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
213 hud_anim Icon_highlight_anims[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
214 hud_anim Icon_fade_anims[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
217 // --------------------------------------------------------------------------------------
219 // --------------------------------------------------------------------------------------
221 brief_screen bscreen;
223 // briefing screen sections
224 #define BRIEF_CUP_X1 400
225 #define BRIEF_CUP_Y1 70
226 #define BRIEF_CUP_X2 639
227 #define BRIEF_CUP_Y2 245
228 #define BRIEF_CUPINFO_X1 445
229 #define BRIEF_CUPINFO_Y1 247
230 #define BRIEF_CUPINFO_X2 639
231 #define BRIEF_CUPINFO_Y2 438
233 const char *Brief_static_name[GR_NUM_RESOLUTIONS] = {
238 int Brief_static_coords[GR_NUM_RESOLUTIONS][2] = {
251 int Brief_bmap_coords[GR_NUM_RESOLUTIONS][2] = {
264 int Brief_grid_coords[GR_NUM_RESOLUTIONS][4] = {
277 int Brief_text_coords[GR_NUM_RESOLUTIONS][4] = {
290 int Brief_stage_text_coords[GR_NUM_RESOLUTIONS][2] = {
303 int Brief_stage_text_coords_multi[GR_NUM_RESOLUTIONS][2] = {
316 int Brief_text_max_lines[GR_NUM_RESOLUTIONS] = {
320 #define LOOKAT_DIST 500.0f
322 // --------------------------------------------------------------------------------------
323 // Game-wide global data
324 // --------------------------------------------------------------------------------------
325 briefing Briefings[MAX_TEAMS]; // there is exactly one briefing per mission
326 debriefing Debriefings[MAX_TEAMS]; // there can be multiple debriefings per mission
327 briefing *Briefing; // pointer used in code -- points to correct briefing
328 debriefing *Debriefing; // pointer to correct debriefing
330 int Briefing_voice_enabled=1; // flag which turn on/off voice playback of briefings/debriefings
332 // --------------------------------------------------------------------------------------
333 // Module global data
334 // --------------------------------------------------------------------------------------
336 static int Last_new_stage;
339 const char BRIEF_META_CHAR = '$';
341 // static int Brief_voice_ask_for_cd;
344 static vector Current_cam_pos; // current camera position
345 static vector Target_cam_pos; // desired camera position
346 static matrix Current_cam_orient; // current camera orientation
347 static matrix Target_cam_orient; // desired camera orientation
348 static matrix Start_cam_orient; // start camera orientation
349 static vector Start_cam_pos; // position of camera at the start of a translation
350 static vector Cam_vel; // camera velocity
351 static vector Current_lookat_pos; // lookat point
352 static vector Target_lookat_pos; // lookat point
353 static vector Start_lookat_pos;
354 static vector Lookat_vel; // lookat point velocity
356 static float Start_cam_move; // time at which camera started moving (seconds)
357 static float Total_move_time; // time in which camera should move from current pos to target pos (seconds)
358 static float Elapsed_time;
360 static float Start_dist;
361 static float End_dist;
362 static float Dist_change_rate;
364 static vector Acc_limit;
365 static vector Vel_limit;
367 static float Total_dist;
368 static float Peak_speed;
369 static float Cam_accel;
370 static float Last_dist;
371 static vector W_init;
373 // flag to indicate that the sound for a spinning highlight animation has played
374 static int Brief_stage_highlight_sound_handle = -1;
376 // used for scrolling briefing text ( if necessary )
377 int Num_brief_text_lines[MAX_TEXT_STREAMS];
378 int Top_brief_text_line;
379 static char Brief_text[MAX_BRIEF_LINES][MAX_BRIEF_LINE_LEN];
381 // Used to support drawing colored text for the briefing. Gets complicates since we
382 // need to be able to draw one character at a time as well when the briefing text
384 typedef struct colored_char
387 ubyte color; // index into Brief_text_colors[]
390 static colored_char Colored_text[MAX_TEXT_STREAMS][MAX_BRIEF_LINES][MAX_BRIEF_LINE_LEN];
391 static int Colored_text_len[MAX_TEXT_STREAMS][MAX_BRIEF_LINES];
393 #define MAX_BRIEF_TEXT_COLORS 9
394 #define BRIEF_TEXT_WHITE 0
395 #define BRIEF_TEXT_BRIGHT_WHITE 1
396 #define BRIEF_TEXT_RED 2
397 #define BRIEF_TEXT_GREEN 3
398 #define BRIEF_TEXT_YELLOW 4
399 #define BRIEF_TEXT_BLUE 5
400 #define BRIEF_IFF_FRIENDLY 6
401 #define BRIEF_IFF_HOSTILE 7
402 #define BRIEF_IFF_NEUTRAL 8
404 color Brief_color_red, Brief_color_green;
406 color *Brief_text_colors[MAX_BRIEF_TEXT_COLORS] =
416 &IFF_colors[IFF_COLOR_NEUTRAL][0],
419 #define BRIGHTEN_LEAD 2
421 float Brief_text_wipe_time_elapsed;
422 static int Max_briefing_line_len;
424 static int Brief_voice_ended;
425 static int Brief_textdraw_finished;
426 static int Brief_voice_started;
427 static int Brief_stage_time;
429 const float BRIEF_TEXT_WIPE_TIME = 1.5f; // time in seconds for wipe to occur
430 static int Brief_text_wipe_snd; // sound handle of sound effect for text wipe
431 static int Play_brief_voice;
434 static int Play_highlight_flag;
435 static int Cam_target_reached;
436 static int Cam_movement_done;
439 typedef struct icon_move_info
441 icon_move_info *next, *prev;
448 // used to move icons smoothly
452 float total_move_time;
458 #define MAX_MOVE_ICONS 10
459 icon_move_info Icon_movers[MAX_MOVE_ICONS];
460 icon_move_info Icon_move_list; // head of linked list
463 typedef struct fade_icon
465 hud_anim fade_anim; // anim info
470 #define MAX_FADE_ICONS 30
471 fade_icon Fading_icons[MAX_FADE_ICONS];
474 // voice id's for briefing text
475 int Brief_voices[MAX_BRIEF_STAGES];
477 cmd_brief *Cur_cmd_brief;
478 cmd_brief Cmd_briefs[MAX_TEAMS];
481 static const char *fs1_icon_tbl[MAX_BRIEF_ICONS][3] = {
482 { "iconfighter", "FadeFighter", "iconhighlight04" },
483 { "iconfighterW", "FadeFighterW", "iconhighlight02" },
484 { "iconcargo", "FadeCargo", "iconhighlight04" },
485 { "iconcargoW", "FadeCargoW", "iconhighlight02" },
486 { "iconbigship", "FadeBigShip", "iconhighlight07" },
487 { "iconbigshipW", "FadeBigShipW", "iconhighlight05" },
488 { "iconcapital", "FadeCapital", "iconhighlight06" },
489 { "iconplanet", "FadePlanet", "iconhighlight03" },
490 { "iconasteroid", "FadeAsteroid", "iconhighlight03" },
491 { "iconwaypoint", "FadeWaypoint", "iconhighlight04" },
492 { "iconsupport", "FadeSupport", "iconhighlight04" },
493 { "iconfreighter", "FadeFreighter", "iconhighlight01" },
494 { "iconfreighterc", "FadeFreighterC", "iconhighlight01" },
495 { "iconfreighterwing", "FadeFreighterW", "iconhighlight05" },
496 { "iconfreightercwing", "FadeFreighterCW", "iconhighlight05" },
497 { "iconInstallation", "FadeInstallation", "iconhighlight03" },
498 { "iconbomber", "FadeBomber", "iconhighlight07" },
499 { "iconbomberW", "FadeBomberW", "iconhighlight05" },
500 { "iconcruiser", "FadeCruiser", "iconhighlight01" },
501 { "iconcruiserW", "FadeCruiserW", "iconhighlight05" },
502 { "iconunknown", "FadeUnknown", "iconhighlight04" },
503 { "iconunknownW", "FadeUnknownW", "iconhighlight01" },
504 { "iconfighterP", "FadeFighterP", "iconhighlight04" },
505 { "iconfighterWP", "FadeFighterWP", "iconhighlight02" },
506 { "iconbomberP", "FadeBomberP", "iconhighlight07" },
507 { "iconbomberWP", "FadeBomberWP", "iconhighlight05" },
508 { "iconwaypoint", "FadeWaypoint", "iconhighlight04" }
512 // --------------------------------------------------------------------------------------
513 // forward declarations
514 // --------------------------------------------------------------------------------------
515 void brief_render_elements(vector *pos, grid *gridp);
516 void brief_render_icons(int stage_num, float frametime);
517 void brief_parse_icon_tbl();
518 void brief_grid_read_camera_controls( control_info * ci, float frametime );
519 void brief_maybe_create_new_grid(grid *gridp, vector *pos, matrix *orient, int force = 0);
520 grid *brief_create_grid(grid *gridp, vector *forward, vector *right, vector *center, int nrows, int ncols, float square_size);
521 grid *brief_create_default_grid(void);
522 void brief_render_grid(grid *gridp);
523 void brief_modify_grid(grid *gridp);
524 void brief_rpd_line(vector *v0, vector *v1);
525 void brief_set_text_color(int color_index);
526 extern void get_camera_limits(matrix *start_camera, matrix *end_camera, float time, vector *acc_max, vector *w_max);
527 int brief_text_wipe_finished();
529 void brief_set_icon_color(int team)
532 case TEAM_FRIENDLY: SET_COLOR_FRIENDLY; break;
533 case TEAM_HOSTILE: SET_COLOR_HOSTILE; break;
534 case TEAM_NEUTRAL: SET_COLOR_NEUTRAL; break;
535 case TEAM_TRAITOR: SET_COLOR_HOSTILE; break;
537 SET_COLOR_HOSTILE; break;
541 // --------------------------------------------------------------------------------------
542 // brief_move_icon_reset()
545 void brief_move_icon_reset()
549 list_init(&Icon_move_list);
550 for ( i = 0; i < MAX_MOVE_ICONS; i++ )
551 Icon_movers[i].used = 0;
555 // --------------------------------------------------------------------------------------
556 // Does one time initialization of the briefing and debriefing structures.
557 // Namely setting all malloc'ble pointers to NULL. Called once at game startup.
558 void mission_brief_common_init()
562 // setup brief text colors
563 gr_init_alphacolor( &Brief_color_green, 50, 100, 50, 255, AC_TYPE_HUD);
564 gr_init_alphacolor( &Brief_color_red, 140, 20, 20, 255, AC_TYPE_HUD);
566 // extra catch to reset anything that's already loaded (ie. mission restart)
567 mission_brief_common_reset();
568 mission_debrief_common_reset();
570 if ( Fred_running ) {
571 // If Fred is running malloc out max space
572 for (i=0; i<MAX_TEAMS; i++ ) {
573 for (j=0; j<MAX_BRIEF_STAGES; j++ ) {
574 Briefings[i].stages[j].new_text = (char *)malloc(MAX_BRIEF_LEN);
575 SDL_assert(Briefings[i].stages[j].new_text!=NULL);
576 Briefings[i].stages[j].icons = (brief_icon *)malloc(sizeof(brief_icon)*MAX_STAGE_ICONS);
577 SDL_assert(Briefings[i].stages[j].icons!=NULL);
578 Briefings[i].stages[j].lines = (brief_line *)malloc(sizeof(brief_line)*MAX_BRIEF_STAGE_LINES);
579 SDL_assert(Briefings[i].stages[j].lines!=NULL);
580 Briefings[i].stages[j].num_icons = 0;
581 Briefings[i].stages[j].num_lines = 0;
585 for (i=0; i<MAX_TEAMS; i++ ) {
586 for (j=0; j<MAX_DEBRIEF_STAGES; j++ ) {
587 Debriefings[i].stages[j].new_text = (char *)malloc(MAX_DEBRIEF_LEN);
588 SDL_assert(Debriefings[i].stages[j].new_text!=NULL);
589 Debriefings[i].stages[j].new_recommendation_text = (char *)malloc(MAX_RECOMMENDATION_LEN);
590 SDL_assert(Debriefings[i].stages[j].new_recommendation_text!=NULL);
595 // If game is running don't malloc anything
596 for (i=0; i<MAX_TEAMS; i++ ) {
597 for (j=0; j<MAX_BRIEF_STAGES; j++ ) {
598 Briefings[i].stages[j].new_text = NULL;
599 Briefings[i].stages[j].num_icons = 0;
600 Briefings[i].stages[j].icons = NULL;
601 Briefings[i].stages[j].num_lines = 0;
602 Briefings[i].stages[j].lines = NULL;
606 for (i=0; i<MAX_TEAMS; i++ ) {
607 for (j=0; j<MAX_DEBRIEF_STAGES; j++ ) {
608 Debriefings[i].stages[j].new_text = NULL;
609 Debriefings[i].stages[j].new_recommendation_text = NULL;
618 //--------------------------------------------------------------------------------------
619 // Frees all the memory allocated in the briefing and debriefing structures
620 // and sets all pointers to NULL.
621 void mission_brief_common_reset()
625 if ( Fred_running ) {
626 return; // Don't free these under Fred.
629 for (i=0; i<MAX_TEAMS; i++ ) {
630 for (j=0; j<MAX_BRIEF_STAGES; j++ ) {
631 if ( Briefings[i].stages[j].new_text ) {
632 free(Briefings[i].stages[j].new_text);
633 Briefings[i].stages[j].new_text = NULL;
636 if ( Briefings[i].stages[j].icons ) {
637 free(Briefings[i].stages[j].icons);
638 Briefings[i].stages[j].icons = NULL;
641 if ( Briefings[i].stages[j].lines ) {
642 free(Briefings[i].stages[j].lines);
643 Briefings[i].stages[j].lines = NULL;
649 // split from above since we need to clear them separately
650 void mission_debrief_common_reset()
654 if ( Fred_running ) {
655 return; // Don't free these under Fred.
658 for (i=0; i<MAX_TEAMS; i++ ) {
659 for (j=0; j<MAX_DEBRIEF_STAGES; j++ ) {
660 if ( Debriefings[i].stages[j].new_text ) {
661 free(Debriefings[i].stages[j].new_text);
662 Debriefings[i].stages[j].new_text = NULL;
665 if ( Debriefings[i].stages[j].new_recommendation_text ) {
666 free(Debriefings[i].stages[j].new_recommendation_text);
667 Debriefings[i].stages[j].new_recommendation_text = NULL;
676 // --------------------------------------------------------------------------------------
685 for ( i = 0; i < MAX_TEAMS; i++ )
686 Briefings[i].num_stages = 0;
690 // --------------------------------------------------------------------------------------
699 for ( i = 0; i < MAX_TEAMS; i++ ) {
700 Debriefings[i].num_stages = 0;
701 for (j=0; j<MAX_DEBRIEF_STAGES; j++ ) {
702 if ( Debriefings[i].stages[j].new_recommendation_text ) {
703 Debriefings[i].stages[j].new_recommendation_text[0] = 0;
708 // MWA 4/27/98 -- must initialize this variable here since we cannot do it as debrief
709 // init time because race conditions between all players in the game make that type of
710 // initialization unsafe.
711 Debrief_multi_stages_loaded = 0;
714 // --------------------------------------------------------------------------------------
715 // brief_init_screen()
717 // Set up the screen regions. A mulitplayer briefing will look different than a single player
720 void brief_init_screen(int multiplayer_flag)
722 bscreen.map_x1 = Brief_grid_coords[gr_screen.res][0];
723 bscreen.map_x2 = Brief_grid_coords[gr_screen.res][0] + Brief_grid_coords[gr_screen.res][2];
724 bscreen.map_y1 = Brief_grid_coords[gr_screen.res][1];
725 bscreen.map_y2 = Brief_grid_coords[gr_screen.res][1] + Brief_grid_coords[gr_screen.res][3];
727 bscreen.map_x1 = BRIEF_GRID3_X1;
728 bscreen.map_x2 = BRIEF_GRID0_X2;
729 bscreen.map_y1 = BRIEF_GRID3_Y1;
730 bscreen.map_y2 = BRIEF_GRID0_Y2+4;
731 bscreen.btext_x1 = BRIEF_TEXT_X1;
732 bscreen.btext_x2 = BRIEF_TEXT_X2;
733 bscreen.btext_y1 = BRIEF_TEXT_Y1;
734 bscreen.btext_y2 = BRIEF_TEXT_Y2;
735 bscreen.cup_x1 = BRIEF_CUP_X1;
736 bscreen.cup_y1 = BRIEF_CUP_Y1;
737 bscreen.cup_x2 = BRIEF_CUP_X2;
738 bscreen.cup_y2 = BRIEF_CUP_Y2;
739 bscreen.cupinfo_x1 = BRIEF_CUPINFO_X1;
740 bscreen.cupinfo_y1 = BRIEF_CUPINFO_Y1;
741 bscreen.cupinfo_x2 = BRIEF_CUPINFO_X2;
742 bscreen.cupinfo_y2 = BRIEF_CUPINFO_Y2;
746 // --------------------------------------------------------------------------------------
747 // brief_init_icons()
750 void brief_init_icons()
752 if ( Fred_running ) {
753 gr_init_alphacolor( &IFF_colors[IFF_COLOR_HOSTILE][0], 0xff, 0x00, 0x00, 15*16, AC_TYPE_HUD);
754 gr_init_alphacolor( &IFF_colors[IFF_COLOR_FRIENDLY][0], 0x00, 0xff, 0x00, 15*16, AC_TYPE_HUD);
760 for (i=0; i<MAX_BRIEF_ICONS; i++) {
761 for (idx=0; idx<MAX_SPECIES_NAMES; idx++) {
762 Icon_bitmaps[i][idx].first_frame = -1;
763 Icon_bitmaps[i][idx].num_frames = 0;
767 // Load in the bitmaps for the icons from icons.tbl
768 brief_parse_icon_tbl();
771 // Reset the highlight and fade anims... call before brief_parse_icon_tbl();
772 void brief_init_anims()
777 for (i=0; i<MAX_BRIEF_ICONS; i++) {
778 for (idx=0; idx<MAX_SPECIES_NAMES; idx++) {
779 Icon_highlight_anims[i][idx].first_frame = -1;
780 Icon_highlight_anims[i][idx].num_frames = 0;
781 Icon_fade_anims[i][idx].first_frame = -1;
782 Icon_fade_anims[i][idx].num_frames = 0;
787 // ------------------------------------------------------------------------
788 // brief_unload_icons()
791 void brief_unload_icons()
796 for ( i = 0; i < MAX_BRIEF_ICONS; i++ ) {
797 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
798 ib = &Icon_bitmaps[i][idx];
800 if (ib->first_frame < 0)
803 for ( j=0; j<ib->num_frames; j++ ) {
804 bm_unload(ib->first_frame+j);
810 // determine if icon type is used in the current briefing
811 int brief_icon_used_in_briefing(int icon_type)
813 int num_icons, num_stages, i, j;
815 num_stages = Briefing->num_stages;
817 for ( i = 0; i < num_stages; i++ ) {
818 num_icons = Briefing->stages[i].num_icons;
819 for ( j = 0; j < num_icons; j++ ) {
820 if ( Briefing->stages[i].icons[j].type == icon_type ) {
829 // --------------------------------------------------------------------------------------
830 // brief_parse_icon_tbl()
833 void brief_parse_icon_tbl()
837 char name[NAME_LENGTH];
846 read_file_text("icons.tbl");
850 required_string("#Start");
853 int load_this_icon = 0;
855 while (required_string_either("#End","$Name:")) {
856 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
857 SDL_assert( num_icons < MAX_BRIEF_ICONS);
858 hf = &Icon_bitmaps[num_icons][idx];
860 // load in regular frames
861 required_string("$Name:");
862 stuff_string(name, F_NAME, NULL);
864 if ( Fred_running ) {
867 load_this_icon = brief_icon_used_in_briefing(num_icons);
870 if ( load_this_icon ) {
871 hf->first_frame = bm_load_animation(name, &hf->num_frames);
872 if ( hf->first_frame == -1 ) {
873 Int3(); // missing briefing icon
877 // load in fade frames
878 required_string("$Name:");
879 stuff_string(name, F_NAME, NULL);
880 ha = &Icon_fade_anims[num_icons][idx];
881 hud_anim_init(ha, 0, 0, name);
883 // load in highlighting frames
884 required_string("$Name:");
885 stuff_string(name, F_NAME, NULL);
886 ha = &Icon_highlight_anims[num_icons][idx];
887 hud_anim_init(ha, 0, 0, name);
893 required_string("#End");
894 } catch (parse_error_t rval) {
895 Error(LOCATION, "Unable to parse icons.tbl! Code = %i.\n", (int)rval);
898 // close localization
901 // load up hard coded values for FS1
902 char name[NAME_LENGTH];
906 int load_this_icon = 0;
908 for (idx = 0; idx < MAX_BRIEF_ICONS; idx++) {
909 hf = &Icon_bitmaps[idx][0];
911 // load in regular frames
912 SDL_strlcpy(name, fs1_icon_tbl[idx][0], NAME_LENGTH);
914 if ( Fred_running ) {
917 load_this_icon = brief_icon_used_in_briefing(idx);
920 if ( load_this_icon ) {
921 hf->first_frame = bm_load_animation(name, &hf->num_frames);
922 if ( hf->first_frame == -1 ) {
923 Int3(); // missing briefing icon
927 // load in fade frames
928 SDL_strlcpy(name, fs1_icon_tbl[idx][1], NAME_LENGTH);
929 ha = &Icon_fade_anims[idx][0];
930 hud_anim_init(ha, 0, 0, name);
932 // load in highlighting frames
933 SDL_strlcpy(name, fs1_icon_tbl[idx][2], NAME_LENGTH);
934 ha = &Icon_highlight_anims[idx][0];
935 hud_anim_init(ha, 0, 0, name);
940 // --------------------------------------------------------------------------------------
944 void brief_close_map()
946 brief_unload_icons();
949 void brief_preload_highlight_anim(brief_icon *bi)
952 int species = ship_get_species_by_type(bi->ship_class);
958 ha = &Icon_highlight_anims[bi->type][species];
959 if ( !SDL_strcasecmp(NOX("none"), ha->name) ) {
963 // force read of data from disk, so we don't glitch on initial playback
964 if ( ha->first_frame == -1 ) {
966 SDL_assert(ha->first_frame >= 0);
969 bi->highlight_anim = *ha;
971 gr_set_bitmap(ha->first_frame, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
975 void brief_preload_fade_anim(brief_icon *bi)
978 int species = ship_get_species_by_type(bi->ship_class);
984 ha = &Icon_fade_anims[bi->type][species];
985 if ( !SDL_strcasecmp(NOX("none"), ha->name) ) {
989 // force read of data from disk, so we don't glitch on initial playback
990 if ( ha->first_frame == -1 ) {
992 SDL_assert(ha->first_frame >= 0);
995 gr_set_bitmap(ha->first_frame, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
999 // preload highlight, fadein and fadeout animations that are used in this stage
1000 void brief_preload_anims()
1002 int num_icons, num_stages, i, j;
1005 num_stages = Briefing->num_stages;
1007 for ( i = 0; i < num_stages; i++ ) {
1008 num_icons = Briefing->stages[i].num_icons;
1009 for ( j = 0; j < num_icons; j++ ) {
1010 bi = &Briefing->stages[i].icons[j];
1011 if ( bi->flags & BI_HIGHLIGHT ) {
1012 brief_preload_highlight_anim(bi);
1014 brief_preload_fade_anim(bi);
1019 // --------------------------------------------------------------------------------------
1023 void brief_init_map()
1028 SDL_assert( Briefing != NULL );
1030 pos = &Briefing->stages[0].camera_pos;
1031 orient = &Briefing->stages[0].camera_orient;
1032 vm_vec_zero(&Current_lookat_pos);
1033 vm_vec_zero(&Target_lookat_pos);
1034 Elapsed_time = 0.0f;
1035 Total_move_time = 0.0f;
1037 The_grid = brief_create_default_grid();
1038 brief_maybe_create_new_grid(The_grid, pos, orient, 1);
1042 brief_move_icon_reset();
1043 brief_preload_anims();
1045 Brief_text_wipe_snd = -1;
1046 Last_new_stage = -1;
1051 #pragma optimize("", off)
1054 // render fade-out anim frame
1056 void brief_render_fade_outs(float frametime)
1060 vertex tv; // temp vertex used to find screen position for text
1064 for (i=0; i<Num_fade_icons; i++) {
1065 fi = &Fading_icons[i];
1067 g3_rotate_vertex(&tv, &fi->pos);
1069 if (!(tv.flags & PF_PROJECTED))
1070 g3_project_vertex(&tv);
1072 if (!(tv.flags & PF_OVERFLOW) ) { // make sure point projected before drawing text
1074 brief_set_icon_color(fi->team);
1076 if ( fi->fade_anim.first_frame < 0 ) {
1080 bm_get_info( fi->fade_anim.first_frame, &w, &h, NULL);
1082 bxf = tv.sx - w / 2.0f + 0.5f;
1083 byf = tv.sy - h / 2.0f + 0.5f;
1087 if ( fi->fade_anim.first_frame >= 0 ) {
1088 fi->fade_anim.sx = bx;
1089 fi->fade_anim.sy = by;
1091 // FS1 has the anis reversed from FS2 so play them backwards
1092 hud_anim_render(&fi->fade_anim, frametime, 1, 0, 0, 1);
1094 hud_anim_render(&fi->fade_anim, frametime, 1, 0, 0, 0);
1101 // figure out how far an icon should move based on the elapsed time
1102 float brief_icon_get_dist_moved(icon_move_info *mi, float elapsed_time)
1104 float time, dist_moved=0.0f;
1106 // first half of movement
1107 if ( elapsed_time < mi->total_move_time/2.0f ) {
1108 dist_moved=0.5f*mi->accel*elapsed_time*elapsed_time; // d = 1/2at^2
1112 // second half of movement
1113 time=elapsed_time - mi->total_move_time/2.0f;
1114 dist_moved=(mi->total_dist/2.0f)+(mi->peak_speed*time) - 0.5f*mi->accel*time*time;
1118 // Draw a line between two icons on the briefing screen
1119 void brief_render_icon_line(int stage_num, int line_num)
1122 brief_icon *icon[2];
1123 vertex icon_vertex[2];
1124 int icon_status[2] = {0,0};
1125 int icon_w, icon_h, i;
1126 float icon_x[2], icon_y[2];
1128 bl = &Briefing->stages[stage_num].lines[line_num];
1129 icon[0] = &Briefing->stages[stage_num].icons[bl->start_icon];
1130 icon[1] = &Briefing->stages[stage_num].icons[bl->end_icon];
1133 for (i=0; i<2; i++) {
1134 g3_rotate_vertex(&icon_vertex[i],&icon[i]->pos);
1135 if (!(icon_vertex[i].flags&PF_PROJECTED))
1136 g3_project_vertex(&icon_vertex[i]);
1138 if (!(icon_vertex[i].flags & PF_OVERFLOW) ) { // make sure point projected before drawing text
1143 if ( !icon_status[0] || !icon_status[1] ) {
1147 // get screen (x,y) for icons
1148 for (i=0; i<2; i++) {
1149 brief_common_get_icon_dimensions(&icon_w, &icon_h, icon[i]->type, icon[i]->ship_class);
1150 icon_x[i] = icon_vertex[i].sx;
1151 icon_y[i] = icon_vertex[i].sy;
1154 brief_set_icon_color(icon[0]->team);
1156 gr_line(fl2i(icon_x[0]), fl2i(icon_y[0]), fl2i(icon_x[1]), fl2i(icon_y[1]));
1159 // -------------------------------------------------------------------------------------
1160 // Draw a briefing icon
1162 // parameters: stage_num => briefing stage number (start at 0)
1163 // icon_num => icon number in stage
1164 // frametime => time elapsed in seconds
1165 // selected => FRED only (will be 0 or non-zero)
1166 // w_scale_factor => scale icon in width by this amount (default 1.0f)
1167 // h_scale_factor => scale icon in height by this amount (default 1.0f)
1168 void brief_render_icon(int stage_num, int icon_num, float frametime, int selected, float w_scale_factor, float h_scale_factor)
1170 brief_icon *bi, *closeup_icon;
1172 vertex tv; // temp vertex used to find screen position for text
1174 int bx,by,bc,w,h,icon_w,icon_h,icon_bitmap=-1;
1175 float bxf, byf, dist=0.0f;
1177 SDL_assert( Briefing != NULL );
1179 bi = &Briefing->stages[stage_num].icons[icon_num];
1181 icon_move_info *mi, *next;
1182 int interp_pos_found = 0;
1184 mi = GET_FIRST(&Icon_move_list);
1186 while ( mi != &Icon_move_list ) {
1188 if ( ( mi->id != 0 ) && ( mi->id == bi->id ) ) {
1190 if ( !mi->reached_dest ) {
1191 dist = brief_icon_get_dist_moved(mi, Elapsed_time);
1192 if ( dist < mi->last_dist ) {
1199 if ( !mi->reached_dest ) {
1201 vm_vec_copy_scale(&dist_moved, &mi->direction, dist);
1202 vm_vec_add(&mi->current, &mi->start, &dist_moved);
1204 mi->current = mi->finish;
1208 interp_pos_found = 1;
1214 if ( !interp_pos_found )
1217 brief_render_elements(pos, The_grid);
1218 g3_rotate_vertex(&tv,pos);
1220 if (!(tv.flags&PF_PROJECTED))
1221 g3_project_vertex(&tv);
1223 if (!(tv.flags & PF_OVERFLOW) ) { // make sure point projected before drawing text
1225 brief_set_icon_color(bi->team);
1227 int species = ship_get_species_by_type(bi->ship_class);
1233 ib = &Icon_bitmaps[bi->type][species];
1234 if ( ib->first_frame < 0 ) {
1239 brief_common_get_icon_dimensions(&icon_w, &icon_h, bi->type, bi->ship_class);
1241 closeup_icon = brief_get_closeup_icon();
1243 if ( bi == closeup_icon || selected ) {
1244 icon_bitmap=ib->first_frame+1;
1245 // gr_set_bitmap(ib->first_frame+1);
1248 icon_bitmap=ib->first_frame;
1249 // gr_set_bitmap(ib->first_frame);
1252 // draw icon centered at draw position
1253 // bx = fl2i(tv.sx - ib->icon_w/2.0f);
1254 // by = fl2i(tv.sy - ib->icon_h/2.0f);
1255 // bc = bx + fl2i(ib->icon_w/2.0f);
1256 //gr_aabitmap(bx, by);
1258 float scaled_w, scaled_h;
1260 scaled_w = icon_w * w_scale_factor;
1261 scaled_h = icon_h * h_scale_factor;
1262 bxf = tv.sx - scaled_w / 2.0f + 0.5f;
1263 byf = tv.sy - scaled_h / 2.0f + 0.5f;
1268 if ( !Fred_running && ((bx < 0) || (bx > gr_screen.max_w) || (by < 0) || (by > gr_screen.max_h)) ) {
1280 vb.sx = bxf+scaled_w-1;
1281 vb.sy = byf+scaled_h-1;
1285 // render highlight anim frame
1286 if ( (bi->flags&BI_SHOWHIGHLIGHT) && (bi->flags&BI_HIGHLIGHT) ) {
1287 hud_anim *ha = &bi->highlight_anim;
1288 if ( ha->first_frame >= 0 ) {
1289 ha->sx = bi->hold_x;
1290 if ( strlen(bi->label) > 0 ) {
1291 ha->sy = bi->hold_y - fl2i(gr_get_font_height()/2.0f +0.5) - 2;
1293 ha->sy = bi->hold_y;
1296 //hud_set_iff_color(bi->team);
1297 brief_set_icon_color(bi->team);
1299 hud_anim_render(ha, frametime, 1, 0, 1);
1301 if ( Brief_stage_highlight_sound_handle < 0 ) {
1302 if ( !Fred_running) {
1303 Brief_stage_highlight_sound_handle = snd_play(&Snds_iface[SND_ICON_HIGHLIGHT]);
1309 // render fade-in anim frame
1310 if ( bi->flags & BI_FADEIN ) {
1311 hud_anim *ha = &bi->fadein_anim;
1312 if ( ha->first_frame >= 0 ) {
1315 // hud_set_iff_color(bi->team);
1316 brief_set_icon_color(bi->team);
1319 // FS1 has the anims backwards from FS2 so play in reverse
1320 if ( hud_anim_render(ha, frametime, 1, 0, 0, 0) == 0 ) {
1322 if ( hud_anim_render(ha, frametime, 1, 0, 0, 1) == 0 ) {
1324 bi->flags &= ~BI_FADEIN;
1327 bi->flags &= ~BI_FADEIN;
1331 if ( !(bi->flags & BI_FADEIN) ) {
1332 gr_set_bitmap(icon_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1334 if ( Fred_running ) {
1335 gr_aascaler(&va, &vb);
1337 // Don't bother scaling for the game
1338 gr_aabitmap(bx, by);
1341 // draw text centered over the icon (make text darker)
1342 if ( bi->type == ICON_FIGHTER_PLAYER || bi->type == ICON_BOMBER_PLAYER ) {
1343 gr_get_string_size(&w,&h,Players[Player_num].callsign);
1344 gr_printf(bc - fl2i(w/2.0f), by - h, Players[Player_num].callsign);
1349 SDL_strlcpy(buf, bi->label, SDL_arraysize(buf));
1350 lcl_translate_brief_icon_name(buf, SDL_arraysize(buf));
1351 gr_get_string_size(&w, &h, buf);
1352 gr_printf(bc - fl2i(w/2.0f), by - h, buf);
1355 SDL_strlcpy(buf, bi->label, SDL_arraysize(buf));
1356 lcl_translate_brief_icon_name_pl(buf, SDL_arraysize(buf));
1357 gr_get_string_size(&w, &h, buf);
1358 gr_printf(bc - fl2i(w/2.0f), by - h, buf);
1360 gr_get_string_size(&w,&h,bi->label);
1361 gr_printf(bc - fl2i(w/2.0f), by - h, bi->label);
1365 // show icon as selected (FRED only)
1367 gr_get_string_size(&w,&h,NOX("(S)"));
1368 gr_printf(bc - fl2i(w/2.0f), by - h*2, NOX("(S)"));
1372 // store screen x,y,w,h
1375 bi->w = fl2i(scaled_w);
1376 bi->h = fl2i(scaled_h);
1378 } // end if vertex is projected
1382 #pragma optimize("", on)
1385 // -------------------------------------------------------------------------------------
1386 // brief_render_icons()
1388 void brief_render_icons(int stage_num, float frametime)
1390 int i, num_icons, num_lines;
1392 SDL_assert( Briefing != NULL );
1394 num_icons = Briefing->stages[stage_num].num_icons;
1395 num_lines = Briefing->stages[stage_num].num_lines;
1397 if ( Cam_target_reached ) {
1398 for ( i = 0; i < num_lines; i++ ) {
1399 brief_render_icon_line(stage_num, i);
1403 for ( i = 0; i < num_icons; i++ ) {
1404 brief_render_icon(stage_num, i, frametime, 0);
1408 // ------------------------------------------------------------------------------------
1409 // brief_start_highlight_anims()
1411 // see if there are any highlight animations to play
1413 void brief_start_highlight_anims(int stage_num)
1417 int x,y,i,anim_w,anim_h;
1419 SDL_assert( Briefing != NULL );
1420 bs = &Briefing->stages[stage_num];
1422 for ( i = 0; i < bs->num_icons; i++ ) {
1424 if ( bi->flags & BI_HIGHLIGHT ) {
1425 bi->flags &= ~BI_SHOWHIGHLIGHT;
1426 if ( bi->highlight_anim.first_frame < 0 ) {
1430 bi->highlight_anim.time_elapsed=0.0f;
1432 bm_get_info( bi->highlight_anim.first_frame, &anim_w, &anim_h, NULL);
1433 x = fl2i( i2fl(bi->x) + bi->w/2.0f - anim_w/2.0f );
1434 y = fl2i( i2fl(bi->y) + bi->h/2.0f - anim_h/2.0f );
1437 bi->flags |= BI_SHOWHIGHLIGHT;
1438 bi->highlight_anim.time_elapsed=0.0f;
1443 // -------------------------------------------------------------------------------------
1444 // brief_render_map()
1447 void brief_render_map(int stage_num, float frametime)
1449 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);
1451 // REMOVED by neilk: removed gr_clear for FS2 because interface no longer calls for black background on grid
1456 SDL_assert(Briefing);
1458 if (stage_num >= Briefing->num_stages) {
1464 g3_set_view_matrix(&Current_cam_pos, &Current_cam_orient, 0.5f);
1466 brief_maybe_create_new_grid(The_grid, &Current_cam_pos, &Current_cam_orient);
1467 brief_render_grid(The_grid);
1469 brief_render_fade_outs(frametime);
1471 // go ahead and render everything that is in the active objects list
1472 brief_render_icons(stage_num, frametime);
1474 if ( Cam_target_reached && brief_text_wipe_finished() ) {
1476 if ( Brief_textdraw_finished == 0 ) {
1477 Brief_textdraw_finished = 1;
1478 Brief_stage_time = 0;
1481 if ( Play_highlight_flag ) {
1482 brief_start_highlight_anims(stage_num);
1483 Play_highlight_flag = 0;
1487 anim_render_all(ON_BRIEFING_SELECT, frametime);
1494 // -------------------------------------------------------------------------------------
1495 // brief_text_set_color()
1497 void brief_text_set_color(char c) {
1509 gr_set_color_fast(&Color_red);
1512 gr_set_color_fast(&Color_green);
1515 gr_set_color_fast(&Color_blue);
1518 Int3(); // unsupported meta-code
1523 // Display what stage of the briefing is active
1524 void brief_blit_stage_num(int stage_num, int stage_max)
1529 SDL_assert( Briefing != NULL );
1531 gr_set_color_fast(&Color_bright_blue);
1533 gr_set_color_fast(&Color_text_heading);
1535 SDL_snprintf(buf, SDL_arraysize(buf), XSTR( "Stage %d of %d", 394), stage_num + 1, stage_max);
1536 if (Game_mode & GM_MULTIPLAYER) {
1537 gr_printf(Brief_stage_text_coords_multi[gr_screen.res][0], Brief_stage_text_coords_multi[gr_screen.res][1], buf);
1539 gr_printf(Brief_stage_text_coords[gr_screen.res][0], Brief_stage_text_coords[gr_screen.res][1], buf);
1542 // draw the title of the mission
1543 // if this goes above briefing text, it will need to be raised 10 pixels in multiplayer to make
1544 // room for stage num, which makes toom for chat box
1546 if (Game_mode & GM_MULTIPLAYER) {
1547 gr_get_string_size(&w,NULL,The_mission.name);
1548 gr_string(bscreen.map_x2 - w, bscreen.map_y2 + 5, The_mission.name);
1550 gr_get_string_size(&w,NULL,The_mission.name);
1551 gr_string(bscreen.map_x2 - w, bscreen.map_y2 + 5, The_mission.name);
1556 // Render a line of text for the briefings. Lines are drawn in as a wipe, with leading bright
1557 // white characters. Have to jump through some hoops since we support colored words. This means
1558 // that we need to process the line one character at a time.
1559 void brief_render_line(int line_num, int x, int y, int instance)
1561 int len, count, next, truncate_len, last_color, offset, w, h, bright_len, i;
1563 char line[MAX_BRIEF_LINE_LEN];
1565 src = &Colored_text[instance][line_num][0];
1566 len = Colored_text_len[instance][line_num];
1572 truncate_len = fl2i(Brief_text_wipe_time_elapsed / BRIEF_TEXT_WIPE_TIME * Max_briefing_line_len);
1573 if (truncate_len > len){
1578 if (truncate_len < len) {
1579 if (truncate_len <= BRIGHTEN_LEAD) {
1580 bright_len = truncate_len;
1584 bright_len = BRIGHTEN_LEAD;
1585 truncate_len -= BRIGHTEN_LEAD;
1593 gr_set_color_fast(&Color_white);
1594 last_color = BRIEF_TEXT_WHITE;
1595 for (i=0; i<truncate_len; i++) {
1596 if (count >= truncate_len){
1600 line[next] = src[count].letter;
1602 if (is_white_space(line[next])) {
1603 // end of word reached, blit it
1605 gr_string(x + offset, y, line);
1606 gr_get_string_size(&w, &h, line);
1611 if (last_color != BRIEF_TEXT_WHITE) {
1612 brief_set_text_color(BRIEF_TEXT_WHITE);
1613 last_color = BRIEF_TEXT_WHITE;
1620 if (src[count].color != last_color) {
1621 brief_set_text_color(src[count].color);
1622 last_color = src[count].color;
1630 gr_string(x + offset, y, line);
1633 // draw leading portion of the line bright white
1636 gr_set_color_fast(&Color_bright_white);
1637 for (i=0; i<truncate_len+bright_len; i++) {
1638 line[i] = src[i].letter;
1644 if ( truncate_len > 0 ) {
1645 int width_dim, height_dim;
1646 gr_get_string_size(&width_dim, &height_dim, line, truncate_len );
1647 gr_string(x+width_dim, y, &line[truncate_len]);
1649 gr_string(x, y, line);
1653 // // now erase the part we don't want to be bright white
1654 // gr_set_color_fast(&Color_black);
1655 // if (i > BRIGHTEN_LEAD) {
1656 // line[i - BRIGHTEN_LEAD] = 0;
1657 // gr_get_string_size(&w, &h, line);
1658 // gr_set_clip(x, y, w, gr_get_font_height());
1665 int brief_text_wipe_finished()
1667 if ( Brief_text_wipe_time_elapsed > (BRIEF_TEXT_WIPE_TIME+0.5f) ) {
1674 // -------------------------------------------------------------------------------------
1675 // brief_render_text()
1677 // input: frametime => Time in seconds of previous frame
1678 // instance => Optional parameter. Used to indicate which text stream is used.
1679 // This value is 0 unless multiple text streams are required
1680 int brief_render_text(int line_offset, int x, int y, int h, float frametime, int instance, int line_spacing)
1684 fh = gr_get_font_height();
1685 if (Brief_text_wipe_time_elapsed == 0) {
1686 if (snd_is_playing(Brief_text_wipe_snd)) {
1687 snd_stop(Brief_text_wipe_snd);
1689 gamesnd_play_iface(SND_BRIEF_TEXT_WIPE);
1690 Play_brief_voice = 1;
1693 Brief_text_wipe_time_elapsed += frametime;
1697 while (yy + fh <= h) {
1698 if (line >= Num_brief_text_lines[instance])
1701 brief_render_line(line, x, y + yy, instance);
1704 yy += fh + line_spacing;
1707 if ( brief_text_wipe_finished() && (Play_brief_voice) ) {
1708 Play_brief_voice = 0;
1715 // ------------------------------------------------------------------------------------
1716 // brief_render_elements()
1718 // Draw the lines that show objects positions on the grid
1720 void brief_render_elements(vector *pos, grid* gridp)
1722 vector gpos; // Location of point on grid.
1728 if ( pos->xyz.y < 1 && pos->xyz.y > -1 )
1731 tplane.A = gridp->gmatrix.v.uvec.xyz.x;
1732 tplane.B = gridp->gmatrix.v.uvec.xyz.y;
1733 tplane.C = gridp->gmatrix.v.uvec.xyz.z;
1734 tplane.D = gridp->planeD;
1736 compute_point_on_plane(&gpos, &tplane, pos);
1738 // dxz = vm_vec_dist(pos, &gpos)/8.0f;
1740 gv = &gridp->gmatrix.v.uvec;
1741 if (gv->xyz.x * pos->xyz.x + gv->xyz.y * pos->xyz.y + gv->xyz.z * pos->xyz.z < -gridp->planeD)
1742 gr_set_color(127, 127, 127);
1744 gr_set_color(255, 255, 255); // white
1746 // AL 11-20-97: don't draw elevation lines.. they are confusing
1748 brief_rpd_line(&gpos, pos); // Line from grid to object center.
1752 vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.rvec, -dxz/2);
1753 vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.fvec, -dxz/2);
1755 vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.rvec, dxz/2);
1756 vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.fvec, dxz/2);
1758 brief_rpd_line(&gpos, &tpos);
1760 vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.rvec, dxz);
1761 vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.rvec, -dxz);
1763 brief_rpd_line(&gpos, &tpos);
1768 // ------------------------------------------------------------------------------------
1769 // brief_reset_icons()
1771 void brief_reset_icons(int stage_num)
1777 SDL_assert( Briefing != NULL );
1778 bs = &Briefing->stages[stage_num];
1780 for ( i = 0; i < bs->num_icons; i++ ) {
1782 bi->flags &= ~BI_SHOWHIGHLIGHT;
1786 // ------------------------------------------------------------------------------------
1787 // brief_set_camera_target()
1789 // input: pos => target position for the camera
1790 // orient => target orientation for the camera
1791 // time => time in ms to reach target
1793 void brief_set_camera_target(vector *pos, matrix *orient, int time)
1795 float time_in_seconds;
1797 time_in_seconds = time / 1000.0f;
1800 Current_cam_pos = *pos;
1801 Current_cam_orient = *orient;
1804 Target_cam_pos = *pos;
1805 Target_cam_orient = *orient;
1806 Start_cam_orient = Current_cam_orient;
1807 Start_cam_pos = Current_cam_pos; // we need this when checking if camera movement complete
1808 Start_cam_move = timer_get_milliseconds()*1000.0f; // start time, convert to seconds
1809 Total_move_time = time_in_seconds;
1810 Elapsed_time = 0.0f;
1812 vm_vec_scale_add(&Start_lookat_pos, &Start_cam_pos, &Start_cam_orient.v.fvec, LOOKAT_DIST);
1813 vm_vec_scale_add(&Target_lookat_pos, &Target_cam_pos, &Target_cam_orient.v.fvec, LOOKAT_DIST);
1815 Play_highlight_flag = 1; // once target reached, play highlight anims
1816 Cam_target_reached = 0;
1817 Cam_movement_done=0;
1818 anim_release_all_instances(ON_BRIEFING_SELECT); // stop any briefing-specific anims
1820 // calculate camera velocity
1821 vm_vec_sub(&Cam_vel, pos, &Current_cam_pos);
1822 // vm_vec_scale(&Cam_vel, 1.0f/time_in_seconds);
1823 if ( !IS_VEC_NULL(&Cam_vel) ) {
1824 vm_vec_normalize(&Cam_vel);
1827 // calculate lookat point velocity
1828 vm_vec_sub(&Lookat_vel, &Target_lookat_pos, &Current_lookat_pos);
1829 vm_vec_scale(&Lookat_vel, 1.0f/time_in_seconds);
1831 Start_dist = vm_vec_dist(&Start_cam_pos, &Start_lookat_pos);
1832 End_dist = vm_vec_dist(&Target_cam_pos, &Target_lookat_pos);
1833 Dist_change_rate = (End_dist - Start_dist) / time_in_seconds;
1835 Total_dist=vm_vec_dist(&Start_cam_pos, &Target_cam_pos);
1837 // Peak_speed=Total_dist/Total_move_time*1.5f;
1838 // Cam_accel = Peak_speed/Total_move_time*3.0f;
1840 Peak_speed=Total_dist/Total_move_time*2.0f;
1841 Cam_accel = 4*Total_dist/(Total_move_time*Total_move_time);
1844 vm_vec_zero(&W_init);
1846 get_camera_limits(&Start_cam_orient, &Target_cam_orient, Total_move_time, &Acc_limit, &Vel_limit);
1850 ubyte brief_return_color_index(char c)
1854 return BRIEF_IFF_FRIENDLY;
1857 return BRIEF_IFF_HOSTILE;
1860 return BRIEF_IFF_NEUTRAL;
1863 return BRIEF_TEXT_RED;
1866 return BRIEF_TEXT_GREEN;
1869 return BRIEF_TEXT_BLUE;
1872 Int3(); // unsupported meta-code
1876 return BRIEF_TEXT_WHITE;
1879 void brief_set_text_color(int color_index)
1881 SDL_assert(color_index < MAX_BRIEF_TEXT_COLORS);
1882 gr_set_color_fast(Brief_text_colors[color_index]);
1885 // Set up the Colored_text array.
1886 // input: index => Index into Brief_text[] for source text.
1887 // instance => Which instance of Colored_text[] to use.
1888 // Value is 0 unless multiple text streams are required.
1889 int brief_text_colorize(int index, int instance)
1892 int len, i, skip_to_next_word, dest_len;
1894 ubyte active_color_index;
1896 src = Brief_text[index];
1897 dest = &Colored_text[instance][index][0];
1900 skip_to_next_word = 0;
1902 active_color_index = BRIEF_TEXT_WHITE;
1903 for (i=0; i<len; i++) {
1904 if (skip_to_next_word) {
1905 if (is_white_space(src[i])) {
1906 skip_to_next_word = 0;
1912 if ( src[i] == BRIEF_META_CHAR && is_white_space(src[i + 2]) ) {
1913 active_color_index = brief_return_color_index(src[i + 1]);
1914 skip_to_next_word = 1;
1918 if (is_white_space(src[i])) {
1919 active_color_index = BRIEF_TEXT_WHITE;
1922 dest[dest_len].letter = src[i];
1923 dest[dest_len].color = active_color_index;
1927 dest[dest_len].letter = 0;
1928 Colored_text_len[instance][index] = dest_len;
1932 // ------------------------------------------------------------------------------------
1933 // brief_color_text_init()
1935 // input: src => paragraph of text to process
1936 // w => max width of line in pixels
1937 // instance => optional parameter, used when multiple text streams are required
1938 // (default value is 0)
1939 int brief_color_text_init(char *src, int w, int instance)
1941 int i, n_lines, len;
1942 int n_chars[MAX_BRIEF_LINES];
1943 char *p_str[MAX_BRIEF_LINES];
1946 n_lines = split_str(src, w, n_chars, p_str, MAX_BRIEF_LINES, BRIEF_META_CHAR);
1947 SDL_assert(n_lines >= 0);
1949 Max_briefing_line_len = 1;
1950 for (i=0; i<n_lines; i++) {
1951 SDL_assert(n_chars[i] < MAX_BRIEF_LINE_LEN);
1952 len = SDL_min(n_chars[i] + 1, MAX_BRIEF_LINE_LEN);
1953 SDL_strlcpy(Brief_text[i], p_str[i], len);
1954 Brief_text[i][n_chars[i]] = 0;
1955 drop_leading_white_space(Brief_text[i]);
1956 len = brief_text_colorize(i, instance);
1957 if (len > Max_briefing_line_len)
1958 Max_briefing_line_len = len;
1961 Brief_text_wipe_time_elapsed = 0.0f;
1962 Play_brief_voice = 0;
1964 Num_brief_text_lines[instance] = n_lines;
1968 // ------------------------------------------------------------------------------------
1969 // brief_get_free_move_icon()
1971 // returns: failure => -1
1972 // success => handle to a free move icon struct
1974 int brief_get_free_move_icon()
1978 for ( i = 0; i < MAX_MOVE_ICONS; i++ ) {
1979 if ( Icon_movers[i].used == 0 )
1983 if ( i == MAX_MOVE_ICONS )
1986 Icon_movers[i].used = 1;
1991 // ------------------------------------------------------------------------------------
1992 // brief_set_move_list()
1994 // input: new_stage => new stage number that briefing is now moving to
1995 // current_stage => current stage that the briefing is on
1996 // time => time in seconds
1998 int brief_set_move_list(int new_stage, int current_stage, float time)
2000 brief_stage *newb, *cb;
2001 icon_move_info *imi;
2002 int i,j,k,num_movers,is_gone=0;
2003 vector zero_v = ZERO_VECTOR;
2005 SDL_assert(new_stage != current_stage);
2007 SDL_assert( Briefing != NULL );
2008 newb = &Briefing->stages[new_stage];
2009 cb = &Briefing->stages[current_stage];
2012 for ( i = 0; i < cb->num_icons; i++ ) {
2014 for ( j = 0; j < newb->num_icons; j++ ) {
2015 if ( ( cb->icons[i].id != 0 ) && ( cb->icons[i].id == newb->icons[j].id ) ) {
2017 if ( vm_vec_cmp(&cb->icons[i].pos, &newb->icons[j].pos) ) {
2018 //nprintf(("Alan","We found a match in icon %s\n", cb->icons[i].label));
2019 k = brief_get_free_move_icon();
2021 Int3(); // should never happen, get Alan
2024 imi = &Icon_movers[k];
2025 imi->id = cb->icons[i].id;
2026 imi->start = cb->icons[i].pos;
2027 imi->finish = newb->icons[j].pos;
2028 imi->current = imi->start;
2029 list_append(&Icon_move_list, imi);
2031 imi->total_dist = vm_vec_dist(&imi->start, &imi->finish);
2032 imi->total_move_time = time;
2033 imi->peak_speed = imi->total_dist/imi->total_move_time*2.0f;
2034 imi->accel = 4*imi->total_dist/(time*time);
2035 imi->last_dist=0.0f;
2036 imi->reached_dest=0;
2037 imi->direction = zero_v;
2039 vm_vec_sub(&imi->direction, &imi->finish, &imi->start);
2040 if ( !IS_VEC_NULL(&imi->direction) ) {
2041 vm_vec_normalize(&imi->direction);
2049 // Set up fading icon (to fade out)
2051 if ( Num_fade_icons >= MAX_FADE_ICONS ) {
2056 int species = ship_get_species_by_type(cb->icons[i].ship_class);
2062 Fading_icons[Num_fade_icons].fade_anim = Icon_fade_anims[cb->icons[i].type][species];
2063 Fading_icons[Num_fade_icons].pos = cb->icons[i].pos;
2064 Fading_icons[Num_fade_icons].team = cb->icons[i].team;
2069 // flag new icons for fading in
2070 for ( i=0; i<newb->num_icons; i++ ) {
2072 newb->icons[i].flags &= ~BI_FADEIN;
2073 for ( j=0; j<cb->num_icons; j++ ) {
2074 if ( ( cb->icons[j].id != 0 ) && ( cb->icons[j].id == newb->icons[i].id ) ) {
2079 int species = ship_get_species_by_type(newb->icons[i].ship_class);
2085 newb->icons[i].flags |= BI_FADEIN;
2086 newb->icons[i].fadein_anim = Icon_fade_anims[newb->icons[i].type][species];
2087 newb->icons[i].fadein_anim.time_elapsed = 0.0f;
2094 void brief_clear_fade_out_icons()
2100 // ------------------------------------------------------------------------------------
2101 // brief_set_new_stage()
2103 // input: pos => target position for the camera
2104 // orient => target orientation for the camera
2105 // time => time in ms to reach target
2106 // stage_num => stage number of briefing (start numbering at 0)
2109 void brief_set_new_stage(vector *pos, matrix *orient, int time, int stage_num)
2111 char msg[MAX_BRIEF_LEN];
2112 int num_movers, new_time, not_objv = 1;
2114 SDL_assert( Briefing != NULL );
2117 if (stage_num >= Briefing->num_stages) {
2118 not_objv = 0; // turns out this is an objectives stage
2122 if ( stage_num == Last_new_stage ) {
2127 brief_move_icon_reset();
2128 brief_clear_fade_out_icons();
2129 if ( (Last_new_stage != -1) && not_objv ) {
2130 num_movers = brief_set_move_list(stage_num, Last_new_stage, new_time / 1000.0f);
2133 if ( (Last_new_stage != -1) && (num_movers == 0) && not_objv ) {
2134 if ( !vm_vec_cmp( &Briefing->stages[stage_num].camera_pos, &Briefing->stages[Last_new_stage].camera_pos) ) {
2135 if ( !vm_vec_cmp( &Briefing->stages[stage_num].camera_orient.v.fvec, &Briefing->stages[Last_new_stage].camera_orient.v.fvec) ){
2142 if(Briefing->stages[stage_num].new_text == NULL){
2143 SDL_strlcpy(msg, "", SDL_arraysize(msg));
2145 SDL_strlcpy(msg, Briefing->stages[stage_num].new_text, SDL_arraysize(msg));
2148 SDL_strlcpy(msg, XSTR( "Please review your objectives for this mission.", 395), SDL_arraysize(msg));
2151 if (gr_screen.res == GR_640) {
2153 Num_brief_text_lines[0] = brief_color_text_init(msg, MAX_BRIEF_LINE_W_640);
2156 Num_brief_text_lines[0] = brief_color_text_init(msg, MAX_BRIEF_LINE_W_1024);
2158 Top_brief_text_line = 0;
2161 brief_set_camera_target(pos, orient, new_time);
2164 if ( snd_is_playing(Brief_stage_highlight_sound_handle) ) {
2165 snd_stop(Brief_stage_highlight_sound_handle);
2168 Brief_voice_ended = 0;
2169 Brief_textdraw_finished = 0;
2170 Brief_voice_started = 0;
2171 Brief_stage_time = 0;
2174 Brief_stage_highlight_sound_handle = -1;
2175 Last_new_stage = stage_num;
2178 // ------------------------------------------------------------------------------------
2179 // camera_pos_past_target()
2182 int camera_pos_past_target(vector *start, vector *current, vector *dest)
2187 vm_vec_sub(&num, current, start);
2188 vm_vec_sub(&den, start, dest);
2190 ratio = vm_vec_mag_quick(&num) / vm_vec_mag_quick(&den);
2197 // ------------------------------------------------------------------------------------
2198 // Interpolate between matrices.
2199 // elapsed_time/total_time gives percentage of interpolation between cur
2201 void interpolate_matrix(matrix *result, matrix *goal, matrix *start, float elapsed_time, float total_time)
2206 if ( !vm_matrix_cmp( goal, start ) ) {
2210 time0 = elapsed_time / total_time;
2211 time1 = (total_time - elapsed_time) / total_time;
2213 vm_vec_copy_scale(&fvec, &start->v.fvec, time1);
2214 vm_vec_scale_add2(&fvec, &goal->v.fvec, time0);
2216 vm_vec_copy_scale(&rvec, &start->v.rvec, time1);
2217 vm_vec_scale_add2(&rvec, &goal->v.rvec, time0);
2219 vm_vector_2_matrix(result, &fvec, NULL, &rvec);
2222 // calculate how far the camera should have moved
2223 float brief_camera_get_dist_moved(float elapsed_time)
2225 float time, dist_moved=0.0f;
2227 // first half of movement
2228 if ( elapsed_time < Total_move_time/2.0f ) {
2229 dist_moved=0.5f*Cam_accel*elapsed_time*elapsed_time; // d = 1/2at^2
2233 // second half of movement
2234 time=elapsed_time - Total_move_time/2.0f;
2235 dist_moved=(Total_dist/2.0f)+(Peak_speed*time) - 0.5f*Cam_accel*time*time;
2240 // ------------------------------------------------------------------------------------
2241 // Update the camera position
2242 void brief_camera_move(float frametime, int stage_num)
2249 Elapsed_time += frametime;
2251 if ( Cam_target_reached ) {
2252 // Current_cam_pos = Target_cam_pos;
2253 // Current_lookat_pos = Target_lookat_pos;
2254 // Current_cam_orient = Target_cam_orient;
2258 // Update orientation
2259 if ( (Elapsed_time < Total_move_time) ) {
2260 // interpolate_matrix(&Current_cam_orient, &Target_cam_orient, &Start_cam_orient, Elapsed_time, Total_move_time );
2261 vm_matrix_interpolate(&Target_cam_orient, &Current_cam_orient, &W_init, frametime, &result, &w_out, &Vel_limit, &Acc_limit);
2262 Current_cam_orient = result;
2267 // interpolate lookat position
2268 if ( vm_vec_cmp( &Current_lookat_pos, &Target_lookat_pos ) ) {
2269 vm_vec_copy_scale(&dist_moved, &Lookat_vel, Elapsed_time);
2270 vm_vec_add(&Current_lookat_pos, &Start_lookat_pos, &dist_moved);
2272 if ( camera_pos_past_target(&Start_lookat_pos, &Current_lookat_pos, &Target_lookat_pos) ) {
2273 Current_lookat_pos = Target_lookat_pos;
2277 cur_dist = Start_dist + Dist_change_rate * Elapsed_time;
2278 vm_vec_copy_scale(&dist_moved, &Current_cam_orient.v.fvec, -cur_dist);
2279 vm_vec_add(&Current_cam_pos, &Current_lookat_pos, &dist_moved);
2282 // use absolute pos to update position
2283 if ( vm_vec_cmp( &Current_cam_pos, &Target_cam_pos ) ) {
2284 dist = brief_camera_get_dist_moved(Elapsed_time);
2285 if ( dist < Last_dist ) {
2286 Cam_movement_done=1;
2291 if ( Cam_movement_done == 0 ) {
2292 vm_vec_copy_scale(&dist_moved, &Cam_vel, dist);
2293 vm_vec_add(&Current_cam_pos, &Start_cam_pos, &dist_moved);
2295 Current_cam_pos=Target_cam_pos;
2299 Cam_movement_done=1;
2300 Current_cam_pos=Target_cam_pos;
2303 if ( Cam_movement_done && (Elapsed_time >= Total_move_time) ) {
2304 Cam_target_reached=1;
2308 // Project the viewer's position onto the grid plane. If more than threshold distance
2309 // from grid center, move grid center.
2310 void brief_maybe_create_new_grid(grid* gridp, vector *pos, matrix *orient, int force)
2314 vector gpos, tmp, c;
2315 float dist_to_plane;
2316 float square_size, ux, uy, uz;
2318 ux = tplane.A = gridp->gmatrix.v.uvec.xyz.x;
2319 uy = tplane.B = gridp->gmatrix.v.uvec.xyz.y;
2320 uz = tplane.C = gridp->gmatrix.v.uvec.xyz.z;
2321 tplane.D = gridp->planeD;
2323 compute_point_on_plane(&c, &tplane, pos);
2324 dist_to_plane = fl_abs(vm_dist_to_plane(pos, &gridp->gmatrix.v.uvec, &c));
2327 while (dist_to_plane >= 25.0f)
2329 square_size *= 10.0f;
2330 dist_to_plane /= 10.0f;
2333 if (fvi_ray_plane(&gpos, &gridp->center, &gridp->gmatrix.v.uvec, pos, &orient->v.fvec, 0.0f)<0.0f) {
2335 vm_vec_scale_add(&p,pos,&orient->v.fvec, 100.0f );
2336 compute_point_on_plane(&gpos, &tplane, &p );
2339 if (vm_vec_dist(&gpos, &c) > 50.0f * square_size)
2341 vm_vec_sub(&tmp, &gpos, &c);
2342 vm_vec_normalize(&tmp);
2343 vm_vec_scale_add(&gpos, &c, &tmp, 50.0f * square_size);
2346 roundoff = (int) square_size * 10;
2348 gpos.xyz.x = fl_roundoff(gpos.xyz.x, roundoff);
2350 gpos.xyz.y = fl_roundoff(gpos.xyz.y, roundoff);
2352 gpos.xyz.z = fl_roundoff(gpos.xyz.z, roundoff);
2354 if ((square_size != gridp->square_size) ||
2355 (gpos.xyz.x != gridp->center.xyz.x) ||
2356 (gpos.xyz.y != gridp->center.xyz.y) ||
2357 (gpos.xyz.z != gridp->center.xyz.z) || force)
2359 gridp->square_size = square_size;
2360 gridp->center = gpos;
2361 brief_modify_grid(gridp);
2366 // *forward is vector pointing forward
2367 // *right is vector pointing right
2368 // *center is center point of grid
2369 // length is length of grid
2370 // width is width of grid
2371 // square_size is size of a grid square
2373 // *forward = (0.0, 0.0, 1.0)
2374 // *right = (1.0, 0.0, 0.0)
2375 // *center = (0.0, 0.0, 0.0)
2378 // square_size = 10.0
2379 // will generate a grid of squares 10 long by 5 wide.
2380 // Each grid square will be 10.0 x 10.0 units.
2381 // The center of the grid will be at the global origin.
2382 // The grid will be parallel to the xz plane (because the normal is 0,1,0).
2383 // (In fact, it will be the xz plane because it is centered on the origin.)
2385 // Stuffs grid in *gridp. If gridp == NULL, mallocs and returns a grid.
2386 grid *brief_create_grid(grid *gridp, vector *forward, vector *right, vector *center, int nrows, int ncols, float square_size)
2388 int i, ncols2, nrows2, d = 1;
2389 vector dfvec, drvec, cur, cur2, tvec, uvec, save, save2;
2391 SDL_assert(square_size > 0.0);
2392 if (double_fine_gridlines)
2396 gridp = (grid *) malloc(sizeof(grid));
2400 gridp->center = *center;
2401 gridp->square_size = square_size;
2403 // Create the plane equation.
2404 SDL_assert(!IS_VEC_NULL(forward));
2405 SDL_assert(!IS_VEC_NULL(right));
2407 vm_vec_copy_normalize(&dfvec, forward);
2408 vm_vec_copy_normalize(&drvec, right);
2410 vm_vec_cross(&uvec, &dfvec, &drvec);
2412 SDL_assert(!IS_VEC_NULL(&uvec));
2414 gridp->gmatrix.v.uvec = uvec;
2416 gridp->planeD = -(center->xyz.x * uvec.xyz.x + center->xyz.y * uvec.xyz.y + center->xyz.z * uvec.xyz.z);
2417 SDL_assert(!isnan(gridp->planeD));
2419 gridp->gmatrix.v.fvec = dfvec;
2420 gridp->gmatrix.v.rvec = drvec;
2422 vm_vec_scale(&dfvec, square_size);
2423 vm_vec_scale(&drvec, square_size);
2425 vm_vec_scale_add(&cur, center, &dfvec, (float) -nrows * d / 2);
2426 vm_vec_scale_add2(&cur, &drvec, (float) -ncols * d / 2);
2427 vm_vec_scale_add(&cur2, center, &dfvec, (float) -nrows * 5 / 2);
2428 vm_vec_scale_add2(&cur2, &drvec, (float) -ncols * 5 / 2);
2432 gridp->ncols = ncols;
2433 gridp->nrows = nrows;
2436 SDL_assert(ncols < MAX_GRIDLINE_POINTS && nrows < MAX_GRIDLINE_POINTS);
2438 // Create the points along the edges of the grid, so we can just draw lines
2439 // between them to form the grid.
2440 for (i=0; i<=ncols*d; i++) {
2441 gridp->gpoints1[i] = cur; // small, dark gridline points
2442 vm_vec_scale_add(&tvec, &cur, &dfvec, (float) nrows * d);
2443 gridp->gpoints2[i] = tvec;
2444 vm_vec_add2(&cur, &drvec);
2447 for (i=0; i<=ncols2; i++) {
2448 gridp->gpoints5[i] = cur2; // large, brighter gridline points
2449 vm_vec_scale_add(&tvec, &cur2, &dfvec, (float) nrows2 * 10);
2450 gridp->gpoints6[i] = tvec;
2451 vm_vec_scale_add2(&cur2, &drvec, 10.0f);
2456 for (i=0; i<=nrows*d; i++) {
2457 gridp->gpoints3[i] = cur; // small, dark gridline points
2458 vm_vec_scale_add(&tvec, &cur, &drvec, (float) ncols * d);
2459 gridp->gpoints4[i] = tvec;
2460 vm_vec_add2(&cur, &dfvec);
2463 for (i=0; i<=nrows2; i++) {
2464 gridp->gpoints7[i] = cur2; // large, brighter gridline points
2465 vm_vec_scale_add(&tvec, &cur2, &drvec, (float) ncols2 * 10);
2466 gridp->gpoints8[i] = tvec;
2467 vm_vec_scale_add2(&cur2, &dfvec, 10.0f);
2473 // Create a nice grid -- centered at origin, 10x10, 10.0 size squares, in xz plane.
2474 grid *brief_create_default_grid(void)
2477 vector fvec, rvec, cvec;
2479 rgrid = brief_create_grid(&Global_grid, vm_vec_make(&fvec, 0.0f, 0.0f, 1.0f),
2480 vm_vec_make(&rvec, 1.0f, 0.0f, 0.0f),
2481 vm_vec_make(&cvec, 0.0f, -10.0f, 0.0f), 100, 100, 5.0f);
2483 physics_init(&rgrid->physics);
2484 rgrid->physics.flags |= (PF_ACCELERATES | PF_SLIDE_ENABLED);
2488 // Rotate and project points and draw a line.
2489 void brief_rpd_line(vector *v0, vector *v1)
2492 g3_rotate_vertex(&tv0, v0);
2493 g3_rotate_vertex(&tv1, v1);
2496 g3_project_vertex(&tv0);
2497 g3_project_vertex(&tv1);
2499 if ( (tv0.flags & PF_OVERFLOW) || (tv1.flags & PF_OVERFLOW) )
2503 gr_set_color_fast(&Color_grey);
2504 g3_draw_line(&tv0, &tv1);
2507 // Renders a grid defined in a grid struct
2508 void brief_render_grid(grid *gridp)
2510 int i, ncols, nrows;
2512 ncols = gridp->ncols;
2513 nrows = gridp->nrows;
2514 if (double_fine_gridlines)
2520 gr_set_color(30,30,30);
2523 // Draw the column lines.
2524 for (i=0; i<=ncols; i++)
2525 brief_rpd_line(&gridp->gpoints1[i], &gridp->gpoints2[i]);
2527 // Draw the row lines.
2528 for (i=0; i<=nrows; i++)
2529 brief_rpd_line(&gridp->gpoints3[i], &gridp->gpoints4[i]);
2532 ncols = gridp->ncols / 2;
2533 nrows = gridp->nrows / 2;
2535 // now draw the larger, brighter gridlines that is x10 the scale of smaller one.
2538 for (i=0; i<=ncols; i++)
2539 brief_rpd_line(&gridp->gpoints5[i], &gridp->gpoints6[i]);
2541 for (i=0; i<=nrows; i++)
2542 brief_rpd_line(&gridp->gpoints7[i], &gridp->gpoints8[i]);
2546 void brief_modify_grid(grid *gridp)
2548 brief_create_grid(gridp, &gridp->gmatrix.v.fvec, &gridp->gmatrix.v.rvec, &gridp->center,
2549 gridp->nrows, gridp->ncols, gridp->square_size);
2552 void brief_unload_anims()
2557 for (i=0; i<MAX_BRIEF_ICONS; i++) {
2558 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
2559 hud_anim_release(&Icon_highlight_anims[i][idx]);
2560 hud_anim_release(&Icon_fade_anims[i][idx]);
2565 void brief_common_close()
2568 brief_unload_anims();
2572 void brief_restart_text_wipe()
2574 Brief_stage_time = 0;
2575 Brief_voice_ended = 0;
2576 Brief_voice_started = 0;
2577 Brief_text_wipe_time_elapsed = 0.0f;
2580 // initialize the array of handles to the different voice streams
2581 void brief_voice_init()
2584 for ( i = 0; i < MAX_BRIEF_STAGES; i++ ) {
2585 Brief_voices[i] = -1;
2589 void brief_load_voice_file(int voice_num, char *name)
2591 int load_attempts = 0;
2594 if ( load_attempts++ > 5 ) {
2598 Brief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
2599 if ( Brief_voices[voice_num] >= 0 ) {
2603 // Don't bother to ask for the CD in multiplayer
2604 if ( Game_mode & GM_MULTIPLAYER ) {
2608 // couldn't load animation, ask user to insert CD (if necessary)
2609 // if ( Brief_voice_ask_for_cd ) {
2610 // if ( game_do_cd_check() == 0 ) {
2611 // Brief_voice_ask_for_cd = 0;
2618 // open and pre-load the stream buffers for the different voice streams
2619 void brief_voice_load_all()
2624 // Brief_voice_ask_for_cd = 1;
2626 SDL_assert( Briefing != NULL );
2627 for ( i = 0; i < Briefing->num_stages; i++ ) {
2628 bs = &Briefing->stages[i];
2629 if ( SDL_strncasecmp(bs->voice, NOX("none"), 4) ) {
2630 brief_load_voice_file(i, bs->voice);
2631 // Brief_voices[i] = audiostream_open( bs->voice, ASF_VOICE );
2636 // close all the briefing voice streams
2637 void brief_voice_unload_all()
2641 for ( i = 0; i < MAX_BRIEF_STAGES; i++ ) {
2642 if ( Brief_voices[i] != -1 ) {
2643 audiostream_close_file(Brief_voices[i], 0);
2644 Brief_voices[i] = -1;
2649 // start playback of the voice for a particular briefing stage
2650 void brief_voice_play(int stage_num)
2652 if ( Brief_voices[stage_num] == -1 )
2653 return; // voice file doesn't exist
2655 if ( !Briefing_voice_enabled ) {
2659 if ( audiostream_is_playing( Brief_voices[stage_num]) )
2662 audiostream_play(Brief_voices[stage_num], Master_voice_volume, 0);
2663 Brief_voice_started = 1;
2666 // stop playback of the voice for a particular briefing stage
2667 void brief_voice_stop(int stage_num)
2669 if ( Brief_voices[stage_num] == -1 )
2672 audiostream_stop(Brief_voices[stage_num]); // stream is automatically rewound
2675 // pause playback of the voice for a particular briefing stage, to resume just
2676 // call brief_voice_unpause() again
2677 void brief_voice_pause(int stage_num)
2679 if ( Brief_voices[stage_num] == -1 )
2682 audiostream_pause(Brief_voices[stage_num]);
2685 void brief_voice_unpause(int stage_num)
2687 if ( Brief_voices[stage_num] == -1 )
2690 audiostream_unpause(Brief_voices[stage_num]);
2693 void brief_reset_last_new_stage()
2695 Last_new_stage = -1;
2698 // get the dimensions for a briefing icon
2699 void brief_common_get_icon_dimensions(int *w, int *h, int type, int ship_class)
2701 SDL_assert(type >= 0 && type < MAX_BRIEF_ICONS);
2703 // in case anything goes wrong
2707 int species = ship_get_species_by_type(ship_class);
2713 if ( Icon_bitmaps[type][species].first_frame >= 0 ) {
2714 bm_get_info( Icon_bitmaps[type][species].first_frame, w, h, NULL);
2721 void cmd_brief_reset()
2724 static int inited = 0;
2727 for (i=0; i<MAX_TEAMS; i++) {
2728 for (j=0; j<Cmd_briefs[i].num_stages; j++) {
2729 if (Cmd_briefs[i].stage[j].text)
2730 free(Cmd_briefs[i].stage[j].text);
2736 for (i=0; i<MAX_TEAMS; i++)
2737 Cmd_briefs[i].num_stages = 0;
2740 #define STAGE_ADVANCE_DELAY 1000 // time in ms to wait after voice stops before advancing stage
2742 // should briefing advance to the next stage?
2743 int brief_time_to_advance(int stage_num, float frametime)
2745 int voice_active, advance = 0;
2746 brief_icon *closeup_icon;
2748 closeup_icon = brief_get_closeup_icon();
2750 if ( closeup_icon ) {
2754 if ( !Player->auto_advance ) {
2758 Brief_stage_time += fl2i(frametime*1000 + 0.5f);
2760 if ( (Brief_voices[stage_num] >= 0) && Briefing_voice_enabled ) {
2766 if ( voice_active && (Brief_voice_ended == 0) && Brief_voice_started) {
2767 if ( !audiostream_is_playing( Brief_voices[stage_num]) ) {
2768 Brief_voice_ended = 1;
2769 Brief_stage_time = 0;
2773 if ( Brief_voice_ended ) {
2774 if ( Brief_stage_time > STAGE_ADVANCE_DELAY ) {
2779 if ( !voice_active && (Brief_textdraw_finished > 0) ) {
2780 if ( Brief_stage_time > SDL_max(5000, Num_brief_text_lines[0] * 3500) ) {