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.10 2004/07/04 11:39:06 taylor
19 * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
21 * Revision 1.9 2003/06/11 18:30:32 taylor
24 * Revision 1.8 2003/06/03 04:00:40 taylor
25 * Polish language support (Janusz Dziemidowicz)
27 * Revision 1.7 2003/05/25 02:30:42 taylor
30 * Revision 1.6 2002/06/17 06:33:09 relnev
31 * ryan's struct patch for gcc 2.95
33 * Revision 1.5 2002/06/09 04:41:22 relnev
34 * added copyright header
36 * Revision 1.4 2002/06/02 04:26:34 relnev
39 * Revision 1.3 2002/06/01 07:12:33 relnev
40 * a few NDEBUG updates.
42 * removed a few warnings.
44 * Revision 1.2 2002/05/07 03:16:46 theoddone33
45 * The Great Newline Fix
47 * Revision 1.1.1.1 2002/05/03 03:28:10 root
51 * 19 11/02/99 3:23p Jefff
52 * translate briefing icon names
54 * 18 9/09/99 9:44a Jefff
55 * doh, fixed reversed brief text color thingy. i am stoopid.
57 * 17 9/08/99 11:14a Jefff
58 * toned down hostile/friendly colors in briefing text
60 * 16 9/07/99 12:20p Mikeb
61 * return pos of briefing icon even it does not fit on screen.
63 * 15 9/03/99 1:32a Dave
64 * CD checking by act. Added support to play 2 cutscenes in a row
65 * seamlessly. Fixed super low level cfile bug related to files in the
66 * root directory of a CD. Added cheat code to set campaign mission # in
69 * 14 8/10/99 7:28p Jefff
70 * shuffled some text around
72 * 13 7/30/99 3:05p Jefff
73 * Fixed briefing icon fades -- in and out were reversed.
75 * 12 7/26/99 1:52p Mikeb
76 * Fixed strange briefing bug where a NULL wasn't being checked for when
77 * copying briefing stage text. Odd.
79 * 11 7/24/99 6:15p Jefff
80 * moved "stage x of y" text in multiplayer mode so its not covered by the
83 * 10 7/20/99 7:09p Jefff
84 * briefing text occupies full window in 1024x768
86 * 9 7/09/99 5:54p Dave
87 * Seperated cruiser types into individual types. Added tons of new
88 * briefing icons. Campaign screen.
90 * 8 6/29/99 7:39p Dave
91 * Lots of small bug fixes.
93 * 7 2/05/99 7:19p Neilk
94 * Removed black part from mission screen, fixed info text coords
96 * 6 1/29/99 4:17p Dave
97 * New interface screens.
99 * 5 12/18/98 1:13a Dave
100 * Rough 1024x768 support for Direct3D. Proper detection and usage through
103 * 4 10/23/98 3:51p Dave
104 * Full support for tstrings.tbl and foreign languages. All that remains
105 * is to make it active in Fred.
107 * 3 10/13/98 9:28a Dave
108 * Started neatening up freespace.h. Many variables renamed and
109 * reorganized. Added AlphaColors.[h,cpp]
111 * 2 10/07/98 10:53a Dave
114 * 1 10/07/98 10:49a Dave
116 * 122 6/09/98 10:31a Hoffoss
117 * Created index numbers for all xstr() references. Any new xstr() stuff
118 * added from here on out should be added to the end if the list. The
119 * current list count can be found in FreeSpace.cpp (search for
122 * 121 6/05/98 9:54a Lawrance
125 * 120 6/01/98 11:43a John
126 * JAS & MK: Classified all strings for localization.
128 * 119 5/23/98 10:38p Lawrance
129 * Avoid doing a cfile refresh when running debug
131 * 118 5/23/98 6:49p Lawrance
132 * Fix problems with refreshing the file list when a CD is inserted
134 * 117 5/21/98 6:57p Lawrance
135 * Don't prompt for the CD if voice not found
137 * 116 5/21/98 12:35a Lawrance
138 * Tweak how CD is checked for
140 * 115 5/12/98 11:46a John
141 * Changed the way the "glowing movement" type text draw. Use Hoffoss's
142 * gr_get_string_size optional length parameter to determine length of
143 * string which accounts for kerning on the last character and then I only
144 * draw each character only once.
146 * 114 5/08/98 5:32p Lawrance
147 * prompt for CD if can't load animations or voice
149 * 113 5/06/98 5:30p John
150 * Removed unused cfilearchiver. Removed/replaced some unused/little used
151 * graphics functions, namely gradient_h and _v and pixel_sp. Put in new
152 * DirectX header files and libs that fixed the Direct3D alpha blending
155 * 112 4/27/98 9:08p Allender
156 * fix the debriefing stage problems when clients get to screen long after
159 * 111 4/25/98 3:49p Lawrance
160 * Save briefing auto-advance pref
162 * 110 4/20/98 3:53p Lawrance
163 * Fix various bugs with auto-advancing through briefings.
168 #include "freespace.h"
176 #include "linklist.h"
183 #include "missionbrief.h"
184 #include "missiongrid.h"
185 #include "missionbriefcommon.h"
186 #include "animplay.h"
192 #include "audiostr.h"
193 #include "missioncmdbrief.h"
194 #include "missiondebrief.h"
195 #include "alphacolors.h"
196 #include "localize.h"
199 // --------------------------------------------------------------------------------------
201 // --------------------------------------------------------------------------------------
202 hud_frames Icon_bitmaps[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
203 hud_anim Icon_highlight_anims[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
204 hud_anim Icon_fade_anims[MAX_BRIEF_ICONS][MAX_SPECIES_NAMES];
207 // --------------------------------------------------------------------------------------
209 // --------------------------------------------------------------------------------------
211 brief_screen bscreen;
213 // briefing screen sections
214 #define BRIEF_CUP_X1 400
215 #define BRIEF_CUP_Y1 70
216 #define BRIEF_CUP_X2 639
217 #define BRIEF_CUP_Y2 245
218 #define BRIEF_CUPINFO_X1 445
219 #define BRIEF_CUPINFO_Y1 247
220 #define BRIEF_CUPINFO_X2 639
221 #define BRIEF_CUPINFO_Y2 438
223 char *Brief_static_name[GR_NUM_RESOLUTIONS] = {
228 int Brief_static_coords[GR_NUM_RESOLUTIONS][2] = {
241 int Brief_bmap_coords[GR_NUM_RESOLUTIONS][2] = {
254 int Brief_grid_coords[GR_NUM_RESOLUTIONS][4] = {
267 int Brief_text_coords[GR_NUM_RESOLUTIONS][4] = {
280 int Brief_stage_text_coords[GR_NUM_RESOLUTIONS][2] = {
293 int Brief_stage_text_coords_multi[GR_NUM_RESOLUTIONS][2] = {
306 int Brief_text_max_lines[GR_NUM_RESOLUTIONS] = {
310 #define LOOKAT_DIST 500.0f
312 // --------------------------------------------------------------------------------------
313 // Game-wide global data
314 // --------------------------------------------------------------------------------------
315 briefing Briefings[MAX_TEAMS]; // there is exactly one briefing per mission
316 debriefing Debriefings[MAX_TEAMS]; // there can be multiple debriefings per mission
317 briefing *Briefing; // pointer used in code -- points to correct briefing
318 debriefing *Debriefing; // pointer to correct debriefing
320 int Briefing_voice_enabled=1; // flag which turn on/off voice playback of briefings/debriefings
322 // --------------------------------------------------------------------------------------
323 // Module global data
324 // --------------------------------------------------------------------------------------
326 static int Last_new_stage;
329 const char BRIEF_META_CHAR = '$';
331 // static int Brief_voice_ask_for_cd;
334 static vector Current_cam_pos; // current camera position
335 static vector Target_cam_pos; // desired camera position
336 static matrix Current_cam_orient; // current camera orientation
337 static matrix Target_cam_orient; // desired camera orientation
338 static matrix Start_cam_orient; // start camera orientation
339 static vector Start_cam_pos; // position of camera at the start of a translation
340 static vector Cam_vel; // camera velocity
341 static vector Current_lookat_pos; // lookat point
342 static vector Target_lookat_pos; // lookat point
343 static vector Start_lookat_pos;
344 static vector Lookat_vel; // lookat point velocity
346 static float Start_cam_move; // time at which camera started moving (seconds)
347 static float Total_move_time; // time in which camera should move from current pos to target pos (seconds)
348 static float Elapsed_time;
350 static float Start_dist;
351 static float End_dist;
352 static float Dist_change_rate;
354 static vector Acc_limit;
355 static vector Vel_limit;
357 static float Total_dist;
358 static float Peak_speed;
359 static float Cam_accel;
360 static float Last_dist;
361 static vector W_init;
363 // flag to indicate that the sound for a spinning highlight animation has played
364 static int Brief_stage_highlight_sound_handle = -1;
366 // used for scrolling briefing text ( if necessary )
367 int Num_brief_text_lines[MAX_TEXT_STREAMS];
368 int Top_brief_text_line;
369 static char Brief_text[MAX_BRIEF_LINES][MAX_BRIEF_LINE_LEN];
371 // Used to support drawing colored text for the briefing. Gets complicates since we
372 // need to be able to draw one character at a time as well when the briefing text
374 typedef struct colored_char
377 ubyte color; // index into Brief_text_colors[]
380 static colored_char Colored_text[MAX_TEXT_STREAMS][MAX_BRIEF_LINES][MAX_BRIEF_LINE_LEN];
381 static int Colored_text_len[MAX_TEXT_STREAMS][MAX_BRIEF_LINES];
383 #define MAX_BRIEF_TEXT_COLORS 9
384 #define BRIEF_TEXT_WHITE 0
385 #define BRIEF_TEXT_BRIGHT_WHITE 1
386 #define BRIEF_TEXT_RED 2
387 #define BRIEF_TEXT_GREEN 3
388 #define BRIEF_TEXT_YELLOW 4
389 #define BRIEF_TEXT_BLUE 5
390 #define BRIEF_IFF_FRIENDLY 6
391 #define BRIEF_IFF_HOSTILE 7
392 #define BRIEF_IFF_NEUTRAL 8
394 color Brief_color_red, Brief_color_green;
396 color *Brief_text_colors[MAX_BRIEF_TEXT_COLORS] =
406 &IFF_colors[IFF_COLOR_NEUTRAL][0],
409 #define BRIGHTEN_LEAD 2
411 float Brief_text_wipe_time_elapsed;
412 static int Max_briefing_line_len;
414 static int Brief_voice_ended;
415 static int Brief_textdraw_finished;
416 static int Brief_voice_started;
417 static int Brief_stage_time;
419 const float BRIEF_TEXT_WIPE_TIME = 1.5f; // time in seconds for wipe to occur
420 static int Brief_text_wipe_snd; // sound handle of sound effect for text wipe
421 static int Play_brief_voice;
424 static int Play_highlight_flag;
425 static int Cam_target_reached;
426 static int Cam_movement_done;
429 typedef struct icon_move_info
431 icon_move_info *next, *prev;
438 // used to move icons smoothly
442 float total_move_time;
448 #define MAX_MOVE_ICONS 10
449 icon_move_info Icon_movers[MAX_MOVE_ICONS];
450 icon_move_info Icon_move_list; // head of linked list
453 typedef struct fade_icon
455 hud_anim fade_anim; // anim info
460 #define MAX_FADE_ICONS 30
461 fade_icon Fading_icons[MAX_FADE_ICONS];
464 // voice id's for briefing text
465 int Brief_voices[MAX_BRIEF_STAGES];
467 cmd_brief *Cur_cmd_brief;
468 cmd_brief Cmd_briefs[MAX_TEAMS];
470 // --------------------------------------------------------------------------------------
471 // forward declarations
472 // --------------------------------------------------------------------------------------
473 void brief_render_elements(vector *pos, grid *gridp);
474 void brief_render_icons(int stage_num, float frametime);
475 void brief_parse_icon_tbl();
476 void brief_grid_read_camera_controls( control_info * ci, float frametime );
477 void brief_maybe_create_new_grid(grid *gridp, vector *pos, matrix *orient, int force = 0);
478 grid *brief_create_grid(grid *gridp, vector *forward, vector *right, vector *center, int nrows, int ncols, float square_size);
479 grid *brief_create_default_grid(void);
480 void brief_render_grid(grid *gridp);
481 void brief_modify_grid(grid *gridp);
482 void brief_rpd_line(vector *v0, vector *v1);
483 void brief_set_text_color(int color_index);
484 extern void get_camera_limits(matrix *start_camera, matrix *end_camera, float time, vector *acc_max, vector *w_max);
485 int brief_text_wipe_finished();
487 void brief_set_icon_color(int team)
490 case TEAM_FRIENDLY: SET_COLOR_FRIENDLY; break;
491 case TEAM_HOSTILE: SET_COLOR_HOSTILE; break;
492 case TEAM_NEUTRAL: SET_COLOR_NEUTRAL; break;
493 case TEAM_TRAITOR: SET_COLOR_HOSTILE; break;
495 SET_COLOR_HOSTILE; break;
499 // --------------------------------------------------------------------------------------
500 // brief_move_icon_reset()
503 void brief_move_icon_reset()
507 list_init(&Icon_move_list);
508 for ( i = 0; i < MAX_MOVE_ICONS; i++ )
509 Icon_movers[i].used = 0;
513 // --------------------------------------------------------------------------------------
514 // Does one time initialization of the briefing and debriefing structures.
515 // Namely setting all malloc'ble pointers to NULL. Called once at game startup.
516 void mission_brief_common_init()
520 // setup brief text colors
521 gr_init_alphacolor( &Brief_color_green, 50, 100, 50, 255 );
522 gr_init_alphacolor( &Brief_color_red, 140, 20, 20, 255 );
524 // extra catch to reset anything that's already loaded (ie. mission restart)
525 mission_brief_common_reset();
526 mission_debrief_common_reset();
528 if ( Fred_running ) {
529 // If Fred is running malloc out max space
530 for (i=0; i<MAX_TEAMS; i++ ) {
531 for (j=0; j<MAX_BRIEF_STAGES; j++ ) {
532 Briefings[i].stages[j].new_text = (char *)malloc(MAX_BRIEF_LEN);
533 Assert(Briefings[i].stages[j].new_text!=NULL);
534 Briefings[i].stages[j].icons = (brief_icon *)malloc(sizeof(brief_icon)*MAX_STAGE_ICONS);
535 Assert(Briefings[i].stages[j].icons!=NULL);
536 Briefings[i].stages[j].lines = (brief_line *)malloc(sizeof(brief_line)*MAX_BRIEF_STAGE_LINES);
537 Assert(Briefings[i].stages[j].lines!=NULL);
538 Briefings[i].stages[j].num_icons = 0;
539 Briefings[i].stages[j].num_lines = 0;
543 for (i=0; i<MAX_TEAMS; i++ ) {
544 for (j=0; j<MAX_DEBRIEF_STAGES; j++ ) {
545 Debriefings[i].stages[j].new_text = (char *)malloc(MAX_DEBRIEF_LEN);
546 Assert(Debriefings[i].stages[j].new_text!=NULL);
547 Debriefings[i].stages[j].new_recommendation_text = (char *)malloc(MAX_RECOMMENDATION_LEN);
548 Assert(Debriefings[i].stages[j].new_recommendation_text!=NULL);
553 // If game is running don't malloc anything
554 for (i=0; i<MAX_TEAMS; i++ ) {
555 for (j=0; j<MAX_BRIEF_STAGES; j++ ) {
556 Briefings[i].stages[j].new_text = NULL;
557 Briefings[i].stages[j].num_icons = 0;
558 Briefings[i].stages[j].icons = NULL;
559 Briefings[i].stages[j].num_lines = 0;
560 Briefings[i].stages[j].lines = NULL;
564 for (i=0; i<MAX_TEAMS; i++ ) {
565 for (j=0; j<MAX_DEBRIEF_STAGES; j++ ) {
566 Debriefings[i].stages[j].new_text = NULL;
567 Debriefings[i].stages[j].new_recommendation_text = NULL;
576 //--------------------------------------------------------------------------------------
577 // Frees all the memory allocated in the briefing and debriefing structures
578 // and sets all pointers to NULL.
579 void mission_brief_common_reset()
583 if ( Fred_running ) {
584 return; // Don't free these under Fred.
587 for (i=0; i<MAX_TEAMS; i++ ) {
588 for (j=0; j<MAX_BRIEF_STAGES; j++ ) {
589 if ( Briefings[i].stages[j].new_text ) {
590 free(Briefings[i].stages[j].new_text);
591 Briefings[i].stages[j].new_text = NULL;
594 if ( Briefings[i].stages[j].icons ) {
595 free(Briefings[i].stages[j].icons);
596 Briefings[i].stages[j].icons = NULL;
599 if ( Briefings[i].stages[j].lines ) {
600 free(Briefings[i].stages[j].lines);
601 Briefings[i].stages[j].lines = NULL;
607 // split from above since we need to clear them separately
608 void mission_debrief_common_reset()
612 if ( Fred_running ) {
613 return; // Don't free these under Fred.
616 for (i=0; i<MAX_TEAMS; i++ ) {
617 for (j=0; j<MAX_DEBRIEF_STAGES; j++ ) {
618 if ( Debriefings[i].stages[j].new_text ) {
619 free(Debriefings[i].stages[j].new_text);
620 Debriefings[i].stages[j].new_text = NULL;
623 if ( Debriefings[i].stages[j].new_recommendation_text ) {
624 free(Debriefings[i].stages[j].new_recommendation_text);
625 Debriefings[i].stages[j].new_recommendation_text = NULL;
634 // --------------------------------------------------------------------------------------
643 for ( i = 0; i < MAX_TEAMS; i++ )
644 Briefings[i].num_stages = 0;
648 // --------------------------------------------------------------------------------------
657 for ( i = 0; i < MAX_TEAMS; i++ ) {
658 Debriefings[i].num_stages = 0;
659 for (j=0; j<MAX_DEBRIEF_STAGES; j++ ) {
660 if ( Debriefings[i].stages[j].new_recommendation_text ) {
661 Debriefings[i].stages[j].new_recommendation_text[0] = 0;
666 // MWA 4/27/98 -- must initialize this variable here since we cannot do it as debrief
667 // init time because race conditions between all players in the game make that type of
668 // initialization unsafe.
669 Debrief_multi_stages_loaded = 0;
672 // --------------------------------------------------------------------------------------
673 // brief_init_screen()
675 // Set up the screen regions. A mulitplayer briefing will look different than a single player
678 void brief_init_screen(int multiplayer_flag)
680 bscreen.map_x1 = Brief_grid_coords[gr_screen.res][0];
681 bscreen.map_x2 = Brief_grid_coords[gr_screen.res][0] + Brief_grid_coords[gr_screen.res][2];
682 bscreen.map_y1 = Brief_grid_coords[gr_screen.res][1];
683 bscreen.map_y2 = Brief_grid_coords[gr_screen.res][1] + Brief_grid_coords[gr_screen.res][3];
685 bscreen.map_x1 = BRIEF_GRID3_X1;
686 bscreen.map_x2 = BRIEF_GRID0_X2;
687 bscreen.map_y1 = BRIEF_GRID3_Y1;
688 bscreen.map_y2 = BRIEF_GRID0_Y2+4;
689 bscreen.btext_x1 = BRIEF_TEXT_X1;
690 bscreen.btext_x2 = BRIEF_TEXT_X2;
691 bscreen.btext_y1 = BRIEF_TEXT_Y1;
692 bscreen.btext_y2 = BRIEF_TEXT_Y2;
693 bscreen.cup_x1 = BRIEF_CUP_X1;
694 bscreen.cup_y1 = BRIEF_CUP_Y1;
695 bscreen.cup_x2 = BRIEF_CUP_X2;
696 bscreen.cup_y2 = BRIEF_CUP_Y2;
697 bscreen.cupinfo_x1 = BRIEF_CUPINFO_X1;
698 bscreen.cupinfo_y1 = BRIEF_CUPINFO_Y1;
699 bscreen.cupinfo_x2 = BRIEF_CUPINFO_X2;
700 bscreen.cupinfo_y2 = BRIEF_CUPINFO_Y2;
704 // --------------------------------------------------------------------------------------
705 // brief_init_icons()
708 void brief_init_icons()
710 if ( Fred_running ) {
711 gr_init_alphacolor( &IFF_colors[IFF_COLOR_HOSTILE][0], 0xff, 0x00, 0x00, 15*16 );
712 gr_init_alphacolor( &IFF_colors[IFF_COLOR_FRIENDLY][0], 0x00, 0xff, 0x00, 15*16 );
715 // Load in the bitmaps for the icons from icons.tbl
716 brief_parse_icon_tbl();
719 // Reset the highlight and fade anims... call before brief_parse_icon_tbl();
720 void brief_init_anims()
727 for (i=0; i<MAX_BRIEF_ICONS; i++) {
729 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
730 Icon_highlight_anims[i][idx].num_frames=0;
731 Icon_fade_anims[i][idx].num_frames=0;
734 // one set of icons for all species in FS1
735 Icon_highlight_anims[i][1].num_frames=0;
736 Icon_fade_anims[i][1].num_frames=0;
741 // ------------------------------------------------------------------------
742 // brief_unload_icons()
745 void brief_unload_icons()
750 for ( i = 0; i < MAX_BRIEF_ICONS; i++ ) {
751 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
752 ib = &Icon_bitmaps[i][idx];
754 for ( j=0; j<ib->num_frames; j++ ) {
755 bm_unload(ib->first_frame+j);
761 // determine if icon type is used in the current briefing
762 int brief_icon_used_in_briefing(int icon_type)
764 int num_icons, num_stages, i, j;
766 num_stages = Briefing->num_stages;
768 for ( i = 0; i < num_stages; i++ ) {
769 num_icons = Briefing->stages[i].num_icons;
770 for ( j = 0; j < num_icons; j++ ) {
771 if ( Briefing->stages[i].icons[j].type == icon_type ) {
780 // --------------------------------------------------------------------------------------
781 // brief_parse_icon_tbl()
784 void brief_parse_icon_tbl()
787 char name[NAME_LENGTH];
795 if ((rval = setjmp(parse_abort)) != 0) {
796 Error(LOCATION, "Unable to parse icons.tbl! Code = %i.\n", rval);
799 read_file_text("icons.tbl");
804 required_string("#Start");
807 int load_this_icon = 0;
809 while (required_string_either("#End","$Name:")) {
810 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
811 Assert( num_icons < MAX_BRIEF_ICONS);
812 hf = &Icon_bitmaps[num_icons][idx];
814 // load in regular frames
815 required_string("$Name:");
816 stuff_string(name, F_NAME, NULL);
818 if ( Fred_running ) {
821 load_this_icon = brief_icon_used_in_briefing(num_icons);
824 if ( load_this_icon ) {
825 hf->first_frame = bm_load_animation(name, &hf->num_frames);
826 if ( hf->first_frame == -1 ) {
827 Int3(); // missing briefing icon
831 // load in fade frames
832 required_string("$Name:");
833 stuff_string(name, F_NAME, NULL);
834 ha = &Icon_fade_anims[num_icons][idx];
835 hud_anim_init(ha, 0, 0, name);
837 // load in highlighting frames
838 required_string("$Name:");
839 stuff_string(name, F_NAME, NULL);
840 ha = &Icon_highlight_anims[num_icons][idx];
841 hud_anim_init(ha, 0, 0, name);
847 required_string("#End");
849 // close localization
853 // --------------------------------------------------------------------------------------
857 void brief_close_map()
859 brief_unload_icons();
862 void brief_preload_highlight_anim(brief_icon *bi)
865 int species = ship_get_species_by_type(bi->ship_class);
871 ha = &Icon_highlight_anims[bi->type][species];
872 if ( !stricmp(NOX("none"), ha->name) ) {
876 // force read of data from disk, so we don't glitch on initial playback
877 if ( ha->first_frame == -1 ) {
879 Assert(ha->first_frame >= 0);
882 bi->highlight_anim = *ha;
884 gr_set_bitmap(ha->first_frame);
888 void brief_preload_fade_anim(brief_icon *bi)
891 int species = ship_get_species_by_type(bi->ship_class);
897 ha = &Icon_fade_anims[bi->type][species];
898 if ( !stricmp(NOX("none"), ha->name) ) {
902 // force read of data from disk, so we don't glitch on initial playback
903 if ( ha->first_frame == -1 ) {
905 Assert(ha->first_frame >= 0);
908 gr_set_bitmap(ha->first_frame);
912 // preload highlight, fadein and fadeout animations that are used in this stage
913 void brief_preload_anims()
915 int num_icons, num_stages, i, j;
918 num_stages = Briefing->num_stages;
920 for ( i = 0; i < num_stages; i++ ) {
921 num_icons = Briefing->stages[i].num_icons;
922 for ( j = 0; j < num_icons; j++ ) {
923 bi = &Briefing->stages[i].icons[j];
924 if ( bi->flags & BI_HIGHLIGHT ) {
925 brief_preload_highlight_anim(bi);
927 brief_preload_fade_anim(bi);
932 // --------------------------------------------------------------------------------------
936 void brief_init_map()
941 Assert( Briefing != NULL );
943 pos = &Briefing->stages[0].camera_pos;
944 orient = &Briefing->stages[0].camera_orient;
945 vm_vec_zero(&Current_lookat_pos);
946 vm_vec_zero(&Target_lookat_pos);
948 Total_move_time = 0.0f;
950 The_grid = brief_create_default_grid();
951 brief_maybe_create_new_grid(The_grid, pos, orient, 1);
955 brief_move_icon_reset();
956 brief_preload_anims();
958 Brief_text_wipe_snd = -1;
964 #pragma optimize("", off)
967 // render fade-out anim frame
969 void brief_render_fade_outs(float frametime)
973 vertex tv; // temp vertex used to find screen position for text
977 for (i=0; i<Num_fade_icons; i++) {
978 fi = &Fading_icons[i];
980 g3_rotate_vertex(&tv, &fi->pos);
982 if (!(tv.flags & PF_PROJECTED))
983 g3_project_vertex(&tv);
985 if (!(tv.flags & PF_OVERFLOW) ) { // make sure point projected before drawing text
987 brief_set_icon_color(fi->team);
989 if ( fi->fade_anim.first_frame < 0 ) {
993 bm_get_info( fi->fade_anim.first_frame, &w, &h, NULL);
995 bxf = tv.sx - w / 2.0f + 0.5f;
996 byf = tv.sy - h / 2.0f + 0.5f;
1000 if ( fi->fade_anim.first_frame >= 0 ) {
1001 fi->fade_anim.sx = bx;
1002 fi->fade_anim.sy = by;
1004 // FS1 has the anis reversed from FS2 so play them backwards
1005 hud_anim_render(&fi->fade_anim, frametime, 1, 0, 0, 1);
1007 hud_anim_render(&fi->fade_anim, frametime, 1, 0, 0, 0);
1014 // figure out how far an icon should move based on the elapsed time
1015 float brief_icon_get_dist_moved(icon_move_info *mi, float elapsed_time)
1017 float time, dist_moved=0.0f;
1019 // first half of movement
1020 if ( elapsed_time < mi->total_move_time/2.0f ) {
1021 dist_moved=0.5f*mi->accel*elapsed_time*elapsed_time; // d = 1/2at^2
1025 // second half of movement
1026 time=elapsed_time - mi->total_move_time/2.0f;
1027 dist_moved=(mi->total_dist/2.0f)+(mi->peak_speed*time) - 0.5f*mi->accel*time*time;
1031 // Draw a line between two icons on the briefing screen
1032 void brief_render_icon_line(int stage_num, int line_num)
1035 brief_icon *icon[2];
1036 vertex icon_vertex[2];
1037 int icon_status[2] = {0,0};
1038 int icon_w, icon_h, i;
1039 float icon_x[2], icon_y[2];
1041 bl = &Briefing->stages[stage_num].lines[line_num];
1042 icon[0] = &Briefing->stages[stage_num].icons[bl->start_icon];
1043 icon[1] = &Briefing->stages[stage_num].icons[bl->end_icon];
1046 for (i=0; i<2; i++) {
1047 g3_rotate_vertex(&icon_vertex[i],&icon[i]->pos);
1048 if (!(icon_vertex[i].flags&PF_PROJECTED))
1049 g3_project_vertex(&icon_vertex[i]);
1051 if (!(icon_vertex[i].flags & PF_OVERFLOW) ) { // make sure point projected before drawing text
1056 if ( !icon_status[0] || !icon_status[1] ) {
1060 // get screen (x,y) for icons
1061 for (i=0; i<2; i++) {
1062 brief_common_get_icon_dimensions(&icon_w, &icon_h, icon[i]->type, icon[i]->ship_class);
1063 icon_x[i] = icon_vertex[i].sx;
1064 icon_y[i] = icon_vertex[i].sy;
1067 brief_set_icon_color(icon[0]->team);
1069 gr_line(fl2i(icon_x[0]), fl2i(icon_y[0]), fl2i(icon_x[1]), fl2i(icon_y[1]));
1072 // -------------------------------------------------------------------------------------
1073 // Draw a briefing icon
1075 // parameters: stage_num => briefing stage number (start at 0)
1076 // icon_num => icon number in stage
1077 // frametime => time elapsed in seconds
1078 // selected => FRED only (will be 0 or non-zero)
1079 // w_scale_factor => scale icon in width by this amount (default 1.0f)
1080 // h_scale_factor => scale icon in height by this amount (default 1.0f)
1081 void brief_render_icon(int stage_num, int icon_num, float frametime, int selected, float w_scale_factor, float h_scale_factor)
1083 brief_icon *bi, *closeup_icon;
1085 vertex tv; // temp vertex used to find screen position for text
1087 int bx,by,bc,w,h,icon_w,icon_h,icon_bitmap=-1;
1088 float bxf, byf, dist=0.0f;
1090 Assert( Briefing != NULL );
1092 bi = &Briefing->stages[stage_num].icons[icon_num];
1094 icon_move_info *mi, *next;
1095 int interp_pos_found = 0;
1097 mi = GET_FIRST(&Icon_move_list);
1099 while ( mi != &Icon_move_list ) {
1101 if ( ( mi->id != 0 ) && ( mi->id == bi->id ) ) {
1103 if ( !mi->reached_dest ) {
1104 dist = brief_icon_get_dist_moved(mi, Elapsed_time);
1105 if ( dist < mi->last_dist ) {
1112 if ( !mi->reached_dest ) {
1114 vm_vec_copy_scale(&dist_moved, &mi->direction, dist);
1115 vm_vec_add(&mi->current, &mi->start, &dist_moved);
1117 mi->current = mi->finish;
1121 interp_pos_found = 1;
1127 if ( !interp_pos_found )
1130 brief_render_elements(pos, The_grid);
1131 g3_rotate_vertex(&tv,pos);
1133 if (!(tv.flags&PF_PROJECTED))
1134 g3_project_vertex(&tv);
1136 if (!(tv.flags & PF_OVERFLOW) ) { // make sure point projected before drawing text
1138 brief_set_icon_color(bi->team);
1140 int species = ship_get_species_by_type(bi->ship_class);
1146 ib = &Icon_bitmaps[bi->type][species];
1147 if ( ib->first_frame < 0 ) {
1152 brief_common_get_icon_dimensions(&icon_w, &icon_h, bi->type, bi->ship_class);
1154 closeup_icon = brief_get_closeup_icon();
1156 if ( bi == closeup_icon || selected ) {
1157 icon_bitmap=ib->first_frame+1;
1158 // gr_set_bitmap(ib->first_frame+1);
1161 icon_bitmap=ib->first_frame;
1162 // gr_set_bitmap(ib->first_frame);
1165 // draw icon centered at draw position
1166 // bx = fl2i(tv.sx - ib->icon_w/2.0f);
1167 // by = fl2i(tv.sy - ib->icon_h/2.0f);
1168 // bc = bx + fl2i(ib->icon_w/2.0f);
1169 //gr_aabitmap(bx, by);
1171 float scaled_w, scaled_h;
1173 scaled_w = icon_w * w_scale_factor;
1174 scaled_h = icon_h * h_scale_factor;
1175 bxf = tv.sx - scaled_w / 2.0f + 0.5f;
1176 byf = tv.sy - scaled_h / 2.0f + 0.5f;
1181 if ( (bx < 0) || (bx > gr_screen.max_w) || (by < 0) || (by > gr_screen.max_h) && !Fred_running ) {
1193 vb.sx = bxf+scaled_w-1;
1194 vb.sy = byf+scaled_h-1;
1198 // render highlight anim frame
1199 if ( (bi->flags&BI_SHOWHIGHLIGHT) && (bi->flags&BI_HIGHLIGHT) ) {
1200 hud_anim *ha = &bi->highlight_anim;
1201 if ( ha->first_frame >= 0 ) {
1202 ha->sx = bi->hold_x;
1203 if ( strlen(bi->label) > 0 ) {
1204 ha->sy = bi->hold_y - fl2i(gr_get_font_height()/2.0f +0.5) - 2;
1206 ha->sy = bi->hold_y;
1209 //hud_set_iff_color(bi->team);
1210 brief_set_icon_color(bi->team);
1212 hud_anim_render(ha, frametime, 1, 0, 1);
1214 if ( Brief_stage_highlight_sound_handle < 0 ) {
1215 if ( !Fred_running) {
1216 Brief_stage_highlight_sound_handle = snd_play(&Snds_iface[SND_ICON_HIGHLIGHT]);
1222 // render fade-in anim frame
1223 if ( bi->flags & BI_FADEIN ) {
1224 hud_anim *ha = &bi->fadein_anim;
1225 if ( ha->first_frame >= 0 ) {
1228 // hud_set_iff_color(bi->team);
1229 brief_set_icon_color(bi->team);
1232 // FS1 has the anims backwards from FS2 so play in reverse
1233 if ( hud_anim_render(ha, frametime, 1, 0, 0, 0) == 0 ) {
1235 if ( hud_anim_render(ha, frametime, 1, 0, 0, 1) == 0 ) {
1237 bi->flags &= ~BI_FADEIN;
1240 bi->flags &= ~BI_FADEIN;
1244 if ( !(bi->flags & BI_FADEIN) ) {
1245 gr_set_bitmap(icon_bitmap);
1247 if ( Fred_running ) {
1248 gr_aascaler(&va, &vb);
1250 // Don't bother scaling for the game
1251 gr_aabitmap(bx, by);
1254 // draw text centered over the icon (make text darker)
1255 if ( bi->type == ICON_FIGHTER_PLAYER || bi->type == ICON_BOMBER_PLAYER ) {
1256 gr_get_string_size(&w,&h,Players[Player_num].callsign);
1257 gr_printf(bc - fl2i(w/2.0f), by - h, Players[Player_num].callsign);
1262 strcpy(buf, bi->label);
1263 lcl_translate_brief_icon_name(buf);
1264 gr_get_string_size(&w, &h, buf);
1265 gr_printf(bc - fl2i(w/2.0f), by - h, buf);
1268 strcpy(buf, bi->label);
1269 lcl_translate_brief_icon_name_pl(buf);
1270 gr_get_string_size(&w, &h, buf);
1271 gr_printf(bc - fl2i(w/2.0f), by - h, buf);
1273 gr_get_string_size(&w,&h,bi->label);
1274 gr_printf(bc - fl2i(w/2.0f), by - h, bi->label);
1278 // show icon as selected (FRED only)
1280 gr_get_string_size(&w,&h,NOX("(S)"));
1281 gr_printf(bc - fl2i(w/2.0f), by - h*2, NOX("(S)"));
1285 // store screen x,y,w,h
1288 bi->w = fl2i(scaled_w);
1289 bi->h = fl2i(scaled_h);
1291 } // end if vertex is projected
1295 #pragma optimize("", on)
1298 // -------------------------------------------------------------------------------------
1299 // brief_render_icons()
1301 void brief_render_icons(int stage_num, float frametime)
1303 int i, num_icons, num_lines;
1305 Assert( Briefing != NULL );
1307 num_icons = Briefing->stages[stage_num].num_icons;
1308 num_lines = Briefing->stages[stage_num].num_lines;
1310 if ( Cam_target_reached ) {
1311 for ( i = 0; i < num_lines; i++ ) {
1312 brief_render_icon_line(stage_num, i);
1316 for ( i = 0; i < num_icons; i++ ) {
1317 brief_render_icon(stage_num, i, frametime, 0);
1321 // ------------------------------------------------------------------------------------
1322 // brief_start_highlight_anims()
1324 // see if there are any highlight animations to play
1326 void brief_start_highlight_anims(int stage_num)
1330 int x,y,i,anim_w,anim_h;
1332 Assert( Briefing != NULL );
1333 bs = &Briefing->stages[stage_num];
1335 for ( i = 0; i < bs->num_icons; i++ ) {
1337 if ( bi->flags & BI_HIGHLIGHT ) {
1338 bi->flags &= ~BI_SHOWHIGHLIGHT;
1339 if ( bi->highlight_anim.first_frame < 0 ) {
1343 bi->highlight_anim.time_elapsed=0.0f;
1345 bm_get_info( bi->highlight_anim.first_frame, &anim_w, &anim_h, NULL);
1346 x = fl2i( i2fl(bi->x) + bi->w/2.0f - anim_w/2.0f );
1347 y = fl2i( i2fl(bi->y) + bi->h/2.0f - anim_h/2.0f );
1350 bi->flags |= BI_SHOWHIGHLIGHT;
1351 bi->highlight_anim.time_elapsed=0.0f;
1356 // -------------------------------------------------------------------------------------
1357 // brief_render_map()
1360 void brief_render_map(int stage_num, float frametime)
1364 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);
1366 // REMOVED by neilk: removed gr_clear for FS2 because interface no longer calls for black background on grid
1371 if (stage_num >= Briefing->num_stages) {
1377 bs = &Briefing->stages[stage_num];
1380 g3_set_view_matrix(&Current_cam_pos, &Current_cam_orient, 0.5f);
1382 brief_maybe_create_new_grid(The_grid, &Current_cam_pos, &Current_cam_orient);
1383 brief_render_grid(The_grid);
1385 brief_render_fade_outs(frametime);
1387 // go ahead and render everything that is in the active objects list
1388 brief_render_icons(stage_num, frametime);
1390 if ( Cam_target_reached && brief_text_wipe_finished() ) {
1392 if ( Brief_textdraw_finished == 0 ) {
1393 Brief_textdraw_finished = 1;
1394 Brief_stage_time = 0;
1397 if ( Play_highlight_flag ) {
1398 brief_start_highlight_anims(stage_num);
1399 Play_highlight_flag = 0;
1403 anim_render_all(ON_BRIEFING_SELECT, frametime);
1410 // -------------------------------------------------------------------------------------
1411 // brief_text_set_color()
1413 void brief_text_set_color(char c) {
1425 gr_set_color_fast(&Color_red);
1428 gr_set_color_fast(&Color_green);
1431 gr_set_color_fast(&Color_blue);
1434 Int3(); // unsupported meta-code
1439 // Display what stage of the briefing is active
1440 void brief_blit_stage_num(int stage_num, int stage_max)
1445 Assert( Briefing != NULL );
1447 gr_set_color_fast(&Color_bright_blue);
1449 gr_set_color_fast(&Color_text_heading);
1451 sprintf(buf, XSTR( "Stage %d of %d", 394), stage_num + 1, stage_max);
1452 if (Game_mode & GM_MULTIPLAYER) {
1453 gr_printf(Brief_stage_text_coords_multi[gr_screen.res][0], Brief_stage_text_coords_multi[gr_screen.res][1], buf);
1455 gr_printf(Brief_stage_text_coords[gr_screen.res][0], Brief_stage_text_coords[gr_screen.res][1], buf);
1458 // draw the title of the mission
1459 // if this goes above briefing text, it will need to be raised 10 pixels in multiplayer to make
1460 // room for stage num, which makes toom for chat box
1462 if (Game_mode & GM_MULTIPLAYER) {
1463 gr_get_string_size(&w,NULL,The_mission.name);
1464 gr_string(bscreen.map_x2 - w, bscreen.map_y2 + 5, The_mission.name);
1466 gr_get_string_size(&w,NULL,The_mission.name);
1467 gr_string(bscreen.map_x2 - w, bscreen.map_y2 + 5, The_mission.name);
1472 // Render a line of text for the briefings. Lines are drawn in as a wipe, with leading bright
1473 // white characters. Have to jump through some hoops since we support colored words. This means
1474 // that we need to process the line one character at a time.
1475 void brief_render_line(int line_num, int x, int y, int instance)
1477 int len, count, next, truncate_len, last_color, offset, w, h, bright_len, i;
1479 char line[MAX_BRIEF_LINE_LEN];
1481 src = &Colored_text[instance][line_num][0];
1482 len = Colored_text_len[instance][line_num];
1488 truncate_len = fl2i(Brief_text_wipe_time_elapsed / BRIEF_TEXT_WIPE_TIME * Max_briefing_line_len);
1489 if (truncate_len > len){
1494 if (truncate_len < len) {
1495 if (truncate_len <= BRIGHTEN_LEAD) {
1496 bright_len = truncate_len;
1500 bright_len = BRIGHTEN_LEAD;
1501 truncate_len -= BRIGHTEN_LEAD;
1509 gr_set_color_fast(&Color_white);
1510 last_color = BRIEF_TEXT_WHITE;
1511 for (i=0; i<truncate_len; i++) {
1512 if (count >= truncate_len){
1516 line[next] = src[count].letter;
1518 if (is_white_space(line[next])) {
1519 // end of word reached, blit it
1521 gr_string(x + offset, y, line);
1522 gr_get_string_size(&w, &h, line);
1527 if (last_color != BRIEF_TEXT_WHITE) {
1528 brief_set_text_color(BRIEF_TEXT_WHITE);
1529 last_color = BRIEF_TEXT_WHITE;
1536 if (src[count].color != last_color) {
1537 brief_set_text_color(src[count].color);
1538 last_color = src[count].color;
1546 gr_string(x + offset, y, line);
1549 // draw leading portion of the line bright white
1552 gr_set_color_fast(&Color_bright_white);
1553 for (i=0; i<truncate_len+bright_len; i++) {
1554 line[i] = src[i].letter;
1560 if ( truncate_len > 0 ) {
1561 int width_dim, height_dim;
1562 gr_get_string_size(&width_dim, &height_dim, line, truncate_len );
1563 gr_string(x+width_dim, y, &line[truncate_len]);
1565 gr_string(x, y, line);
1569 // // now erase the part we don't want to be bright white
1570 // gr_set_color_fast(&Color_black);
1571 // if (i > BRIGHTEN_LEAD) {
1572 // line[i - BRIGHTEN_LEAD] = 0;
1573 // gr_get_string_size(&w, &h, line);
1574 // gr_set_clip(x, y, w, gr_get_font_height());
1581 int brief_text_wipe_finished()
1583 if ( Brief_text_wipe_time_elapsed > (BRIEF_TEXT_WIPE_TIME+0.5f) ) {
1590 // -------------------------------------------------------------------------------------
1591 // brief_render_text()
1593 // input: frametime => Time in seconds of previous frame
1594 // instance => Optional parameter. Used to indicate which text stream is used.
1595 // This value is 0 unless multiple text streams are required
1596 int brief_render_text(int line_offset, int x, int y, int h, float frametime, int instance, int line_spacing)
1600 fh = gr_get_font_height();
1601 if (Brief_text_wipe_time_elapsed == 0) {
1602 if (snd_is_playing(Brief_text_wipe_snd)) {
1603 snd_stop(Brief_text_wipe_snd);
1605 gamesnd_play_iface(SND_BRIEF_TEXT_WIPE);
1606 Play_brief_voice = 1;
1609 Brief_text_wipe_time_elapsed += frametime;
1613 while (yy + fh <= h) {
1614 if (line >= Num_brief_text_lines[instance])
1617 brief_render_line(line, x, y + yy, instance);
1620 yy += fh + line_spacing;
1623 if ( brief_text_wipe_finished() && (Play_brief_voice) ) {
1624 Play_brief_voice = 0;
1631 // ------------------------------------------------------------------------------------
1632 // brief_render_elements()
1634 // Draw the lines that show objects positions on the grid
1636 void brief_render_elements(vector *pos, grid* gridp)
1638 vector gpos; // Location of point on grid.
1644 if ( pos->xyz.y < 1 && pos->xyz.y > -1 )
1647 tplane.A = gridp->gmatrix.v.uvec.xyz.x;
1648 tplane.B = gridp->gmatrix.v.uvec.xyz.y;
1649 tplane.C = gridp->gmatrix.v.uvec.xyz.z;
1650 tplane.D = gridp->planeD;
1652 compute_point_on_plane(&gpos, &tplane, pos);
1654 dxz = vm_vec_dist(pos, &gpos)/8.0f;
1656 gv = &gridp->gmatrix.v.uvec;
1657 if (gv->xyz.x * pos->xyz.x + gv->xyz.y * pos->xyz.y + gv->xyz.z * pos->xyz.z < -gridp->planeD)
1658 gr_set_color(127, 127, 127);
1660 gr_set_color(255, 255, 255); // white
1662 // AL 11-20-97: don't draw elevation lines.. they are confusing
1664 brief_rpd_line(&gpos, pos); // Line from grid to object center.
1668 vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.rvec, -dxz/2);
1669 vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.fvec, -dxz/2);
1671 vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.rvec, dxz/2);
1672 vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.fvec, dxz/2);
1674 brief_rpd_line(&gpos, &tpos);
1676 vm_vec_scale_add2(&gpos, &gridp->gmatrix.v.rvec, dxz);
1677 vm_vec_scale_add2(&tpos, &gridp->gmatrix.v.rvec, -dxz);
1679 brief_rpd_line(&gpos, &tpos);
1684 // ------------------------------------------------------------------------------------
1685 // brief_reset_icons()
1687 void brief_reset_icons(int stage_num)
1693 Assert( Briefing != NULL );
1694 bs = &Briefing->stages[stage_num];
1696 for ( i = 0; i < bs->num_icons; i++ ) {
1698 bi->flags &= ~BI_SHOWHIGHLIGHT;
1702 // ------------------------------------------------------------------------------------
1703 // brief_set_camera_target()
1705 // input: pos => target position for the camera
1706 // orient => target orientation for the camera
1707 // time => time in ms to reach target
1709 void brief_set_camera_target(vector *pos, matrix *orient, int time)
1711 float time_in_seconds;
1713 time_in_seconds = time / 1000.0f;
1716 Current_cam_pos = *pos;
1717 Current_cam_orient = *orient;
1720 Target_cam_pos = *pos;
1721 Target_cam_orient = *orient;
1722 Start_cam_orient = Current_cam_orient;
1723 Start_cam_pos = Current_cam_pos; // we need this when checking if camera movement complete
1724 Start_cam_move = timer_get_milliseconds()*1000.0f; // start time, convert to seconds
1725 Total_move_time = time_in_seconds;
1726 Elapsed_time = 0.0f;
1728 vm_vec_scale_add(&Start_lookat_pos, &Start_cam_pos, &Start_cam_orient.v.fvec, LOOKAT_DIST);
1729 vm_vec_scale_add(&Target_lookat_pos, &Target_cam_pos, &Target_cam_orient.v.fvec, LOOKAT_DIST);
1731 Play_highlight_flag = 1; // once target reached, play highlight anims
1732 Cam_target_reached = 0;
1733 Cam_movement_done=0;
1734 anim_release_all_instances(ON_BRIEFING_SELECT); // stop any briefing-specific anims
1736 // calculate camera velocity
1737 vm_vec_sub(&Cam_vel, pos, &Current_cam_pos);
1738 // vm_vec_scale(&Cam_vel, 1.0f/time_in_seconds);
1739 if ( !IS_VEC_NULL(&Cam_vel) ) {
1740 vm_vec_normalize(&Cam_vel);
1743 // calculate lookat point velocity
1744 vm_vec_sub(&Lookat_vel, &Target_lookat_pos, &Current_lookat_pos);
1745 vm_vec_scale(&Lookat_vel, 1.0f/time_in_seconds);
1747 Start_dist = vm_vec_dist(&Start_cam_pos, &Start_lookat_pos);
1748 End_dist = vm_vec_dist(&Target_cam_pos, &Target_lookat_pos);
1749 Dist_change_rate = (End_dist - Start_dist) / time_in_seconds;
1751 Total_dist=vm_vec_dist(&Start_cam_pos, &Target_cam_pos);
1753 // Peak_speed=Total_dist/Total_move_time*1.5f;
1754 // Cam_accel = Peak_speed/Total_move_time*3.0f;
1756 Peak_speed=Total_dist/Total_move_time*2.0f;
1757 Cam_accel = 4*Total_dist/(Total_move_time*Total_move_time);
1760 vm_vec_zero(&W_init);
1762 get_camera_limits(&Start_cam_orient, &Target_cam_orient, Total_move_time, &Acc_limit, &Vel_limit);
1766 ubyte brief_return_color_index(char c)
1770 return BRIEF_IFF_FRIENDLY;
1773 return BRIEF_IFF_HOSTILE;
1776 return BRIEF_IFF_NEUTRAL;
1779 return BRIEF_TEXT_RED;
1782 return BRIEF_TEXT_GREEN;
1785 return BRIEF_TEXT_BLUE;
1788 Int3(); // unsupported meta-code
1792 return BRIEF_TEXT_WHITE;
1795 void brief_set_text_color(int color_index)
1797 Assert(color_index < MAX_BRIEF_TEXT_COLORS);
1798 gr_set_color_fast(Brief_text_colors[color_index]);
1801 // Set up the Colored_text array.
1802 // input: index => Index into Brief_text[] for source text.
1803 // instance => Which instance of Colored_text[] to use.
1804 // Value is 0 unless multiple text streams are required.
1805 int brief_text_colorize(int index, int instance)
1808 int len, i, skip_to_next_word, dest_len;
1810 ubyte active_color_index;
1812 src = Brief_text[index];
1813 dest = &Colored_text[instance][index][0];
1816 skip_to_next_word = 0;
1818 active_color_index = BRIEF_TEXT_WHITE;
1819 for (i=0; i<len; i++) {
1820 if (skip_to_next_word) {
1821 if (is_white_space(src[i])) {
1822 skip_to_next_word = 0;
1828 if ( src[i] == BRIEF_META_CHAR && is_white_space(src[i + 2]) ) {
1829 active_color_index = brief_return_color_index(src[i + 1]);
1830 skip_to_next_word = 1;
1834 if (is_white_space(src[i])) {
1835 active_color_index = BRIEF_TEXT_WHITE;
1838 dest[dest_len].letter = src[i];
1839 dest[dest_len].color = active_color_index;
1843 dest[dest_len].letter = 0;
1844 Colored_text_len[instance][index] = dest_len;
1848 // ------------------------------------------------------------------------------------
1849 // brief_color_text_init()
1851 // input: src => paragraph of text to process
1852 // w => max width of line in pixels
1853 // instance => optional parameter, used when multiple text streams are required
1854 // (default value is 0)
1855 int brief_color_text_init(char *src, int w, int instance)
1857 int i, n_lines, len;
1858 int n_chars[MAX_BRIEF_LINES];
1859 char *p_str[MAX_BRIEF_LINES];
1862 n_lines = split_str(src, w, n_chars, p_str, MAX_BRIEF_LINES, BRIEF_META_CHAR);
1863 Assert(n_lines >= 0);
1865 Max_briefing_line_len = 1;
1866 for (i=0; i<n_lines; i++) {
1867 Assert(n_chars[i] < MAX_BRIEF_LINE_LEN);
1868 strncpy(Brief_text[i], p_str[i], n_chars[i]);
1869 Brief_text[i][n_chars[i]] = 0;
1870 drop_leading_white_space(Brief_text[i]);
1871 len = brief_text_colorize(i, instance);
1872 if (len > Max_briefing_line_len)
1873 Max_briefing_line_len = len;
1876 Brief_text_wipe_time_elapsed = 0.0f;
1877 Play_brief_voice = 0;
1879 Num_brief_text_lines[instance] = n_lines;
1883 // ------------------------------------------------------------------------------------
1884 // brief_get_free_move_icon()
1886 // returns: failure => -1
1887 // success => handle to a free move icon struct
1889 int brief_get_free_move_icon()
1893 for ( i = 0; i < MAX_MOVE_ICONS; i++ ) {
1894 if ( Icon_movers[i].used == 0 )
1898 if ( i == MAX_MOVE_ICONS )
1901 Icon_movers[i].used = 1;
1906 // ------------------------------------------------------------------------------------
1907 // brief_set_move_list()
1909 // input: new_stage => new stage number that briefing is now moving to
1910 // current_stage => current stage that the briefing is on
1911 // time => time in seconds
1913 int brief_set_move_list(int new_stage, int current_stage, float time)
1915 brief_stage *newb, *cb;
1916 icon_move_info *imi;
1917 int i,j,k,num_movers,is_gone=0;
1918 vector zero_v = ZERO_VECTOR;
1920 Assert(new_stage != current_stage);
1922 Assert( Briefing != NULL );
1923 newb = &Briefing->stages[new_stage];
1924 cb = &Briefing->stages[current_stage];
1927 for ( i = 0; i < cb->num_icons; i++ ) {
1929 for ( j = 0; j < newb->num_icons; j++ ) {
1930 if ( ( cb->icons[i].id != 0 ) && ( cb->icons[i].id == newb->icons[j].id ) ) {
1932 if ( vm_vec_cmp(&cb->icons[i].pos, &newb->icons[j].pos) ) {
1933 //nprintf(("Alan","We found a match in icon %s\n", cb->icons[i].label));
1934 k = brief_get_free_move_icon();
1936 Int3(); // should never happen, get Alan
1939 imi = &Icon_movers[k];
1940 imi->id = cb->icons[i].id;
1941 imi->start = cb->icons[i].pos;
1942 imi->finish = newb->icons[j].pos;
1943 imi->current = imi->start;
1944 list_append(&Icon_move_list, imi);
1946 imi->total_dist = vm_vec_dist(&imi->start, &imi->finish);
1947 imi->total_move_time = time;
1948 imi->peak_speed = imi->total_dist/imi->total_move_time*2.0f;
1949 imi->accel = 4*imi->total_dist/(time*time);
1950 imi->last_dist=0.0f;
1951 imi->reached_dest=0;
1952 imi->direction = zero_v;
1954 vm_vec_sub(&imi->direction, &imi->finish, &imi->start);
1955 if ( !IS_VEC_NULL(&imi->direction) ) {
1956 vm_vec_normalize(&imi->direction);
1964 // Set up fading icon (to fade out)
1966 if ( Num_fade_icons >= MAX_FADE_ICONS ) {
1971 int species = ship_get_species_by_type(cb->icons[i].ship_class);
1976 Fading_icons[Num_fade_icons].fade_anim = Icon_fade_anims[cb->icons[i].type][species];
1977 Fading_icons[Num_fade_icons].pos = cb->icons[i].pos;
1978 Fading_icons[Num_fade_icons].team = cb->icons[i].team;
1983 // flag new icons for fading in
1984 for ( i=0; i<newb->num_icons; i++ ) {
1986 newb->icons[i].flags &= ~BI_FADEIN;
1987 for ( j=0; j<cb->num_icons; j++ ) {
1988 if ( ( cb->icons[j].id != 0 ) && ( cb->icons[j].id == newb->icons[i].id ) ) {
1993 int species = ship_get_species_by_type(newb->icons[i].ship_class);
1998 newb->icons[i].flags |= BI_FADEIN;
1999 newb->icons[i].fadein_anim = Icon_fade_anims[newb->icons[i].type][species];
2000 newb->icons[i].fadein_anim.time_elapsed = 0.0f;
2007 void brief_clear_fade_out_icons()
2013 // ------------------------------------------------------------------------------------
2014 // brief_set_new_stage()
2016 // input: pos => target position for the camera
2017 // orient => target orientation for the camera
2018 // time => time in ms to reach target
2019 // stage_num => stage number of briefing (start numbering at 0)
2022 void brief_set_new_stage(vector *pos, matrix *orient, int time, int stage_num)
2024 char msg[MAX_BRIEF_LEN];
2025 int num_movers, new_time, not_objv = 1;
2027 Assert( Briefing != NULL );
2030 if (stage_num >= Briefing->num_stages) {
2031 not_objv = 0; // turns out this is an objectives stage
2035 if ( stage_num == Last_new_stage ) {
2040 brief_move_icon_reset();
2041 brief_clear_fade_out_icons();
2042 if ( (Last_new_stage != -1) && not_objv ) {
2043 num_movers = brief_set_move_list(stage_num, Last_new_stage, new_time / 1000.0f);
2046 if ( (Last_new_stage != -1) && (num_movers == 0) && not_objv ) {
2047 if ( !vm_vec_cmp( &Briefing->stages[stage_num].camera_pos, &Briefing->stages[Last_new_stage].camera_pos) ) {
2048 if ( !vm_vec_cmp( &Briefing->stages[stage_num].camera_orient.v.fvec, &Briefing->stages[Last_new_stage].camera_orient.v.fvec) ){
2055 if(Briefing->stages[stage_num].new_text == NULL){
2058 strcpy(msg, Briefing->stages[stage_num].new_text);
2061 strcpy(msg, XSTR( "Please review your objectives for this mission.", 395));
2064 if (gr_screen.res == GR_640) {
2066 Num_brief_text_lines[0] = brief_color_text_init(msg, MAX_BRIEF_LINE_W_640);
2069 Num_brief_text_lines[0] = brief_color_text_init(msg, MAX_BRIEF_LINE_W_1024);
2071 Top_brief_text_line = 0;
2074 brief_set_camera_target(pos, orient, new_time);
2077 if ( snd_is_playing(Brief_stage_highlight_sound_handle) ) {
2078 snd_stop(Brief_stage_highlight_sound_handle);
2081 Brief_voice_ended = 0;
2082 Brief_textdraw_finished = 0;
2083 Brief_voice_started = 0;
2084 Brief_stage_time = 0;
2087 Brief_stage_highlight_sound_handle = -1;
2088 Last_new_stage = stage_num;
2091 // ------------------------------------------------------------------------------------
2092 // camera_pos_past_target()
2095 int camera_pos_past_target(vector *start, vector *current, vector *dest)
2100 vm_vec_sub(&num, current, start);
2101 vm_vec_sub(&den, start, dest);
2103 ratio = vm_vec_mag_quick(&num) / vm_vec_mag_quick(&den);
2110 // ------------------------------------------------------------------------------------
2111 // Interpolate between matrices.
2112 // elapsed_time/total_time gives percentage of interpolation between cur
2114 void interpolate_matrix(matrix *result, matrix *goal, matrix *start, float elapsed_time, float total_time)
2119 if ( !vm_matrix_cmp( goal, start ) ) {
2123 time0 = elapsed_time / total_time;
2124 time1 = (total_time - elapsed_time) / total_time;
2126 vm_vec_copy_scale(&fvec, &start->v.fvec, time1);
2127 vm_vec_scale_add2(&fvec, &goal->v.fvec, time0);
2129 vm_vec_copy_scale(&rvec, &start->v.rvec, time1);
2130 vm_vec_scale_add2(&rvec, &goal->v.rvec, time0);
2132 vm_vector_2_matrix(result, &fvec, NULL, &rvec);
2135 // calculate how far the camera should have moved
2136 float brief_camera_get_dist_moved(float elapsed_time)
2138 float time, dist_moved=0.0f;
2140 // first half of movement
2141 if ( elapsed_time < Total_move_time/2.0f ) {
2142 dist_moved=0.5f*Cam_accel*elapsed_time*elapsed_time; // d = 1/2at^2
2146 // second half of movement
2147 time=elapsed_time - Total_move_time/2.0f;
2148 dist_moved=(Total_dist/2.0f)+(Peak_speed*time) - 0.5f*Cam_accel*time*time;
2153 // ------------------------------------------------------------------------------------
2154 // Update the camera position
2155 void brief_camera_move(float frametime, int stage_num)
2162 Elapsed_time += frametime;
2164 if ( Cam_target_reached ) {
2165 // Current_cam_pos = Target_cam_pos;
2166 // Current_lookat_pos = Target_lookat_pos;
2167 // Current_cam_orient = Target_cam_orient;
2171 // Update orientation
2172 if ( (Elapsed_time < Total_move_time) ) {
2173 // interpolate_matrix(&Current_cam_orient, &Target_cam_orient, &Start_cam_orient, Elapsed_time, Total_move_time );
2174 vm_matrix_interpolate(&Target_cam_orient, &Current_cam_orient, &W_init, frametime, &result, &w_out, &Vel_limit, &Acc_limit);
2175 Current_cam_orient = result;
2180 // interpolate lookat position
2181 if ( vm_vec_cmp( &Current_lookat_pos, &Target_lookat_pos ) ) {
2182 vm_vec_copy_scale(&dist_moved, &Lookat_vel, Elapsed_time);
2183 vm_vec_add(&Current_lookat_pos, &Start_lookat_pos, &dist_moved);
2185 if ( camera_pos_past_target(&Start_lookat_pos, &Current_lookat_pos, &Target_lookat_pos) ) {
2186 Current_lookat_pos = Target_lookat_pos;
2190 cur_dist = Start_dist + Dist_change_rate * Elapsed_time;
2191 vm_vec_copy_scale(&dist_moved, &Current_cam_orient.v.fvec, -cur_dist);
2192 vm_vec_add(&Current_cam_pos, &Current_lookat_pos, &dist_moved);
2195 // use absolute pos to update position
2196 if ( vm_vec_cmp( &Current_cam_pos, &Target_cam_pos ) ) {
2197 dist = brief_camera_get_dist_moved(Elapsed_time);
2198 if ( dist < Last_dist ) {
2199 Cam_movement_done=1;
2204 if ( Cam_movement_done == 0 ) {
2205 vm_vec_copy_scale(&dist_moved, &Cam_vel, dist);
2206 vm_vec_add(&Current_cam_pos, &Start_cam_pos, &dist_moved);
2208 Current_cam_pos=Target_cam_pos;
2212 Cam_movement_done=1;
2213 Current_cam_pos=Target_cam_pos;
2216 if ( Cam_movement_done && (Elapsed_time >= Total_move_time) ) {
2217 Cam_target_reached=1;
2221 // Project the viewer's position onto the grid plane. If more than threshold distance
2222 // from grid center, move grid center.
2223 void brief_maybe_create_new_grid(grid* gridp, vector *pos, matrix *orient, int force)
2227 vector gpos, tmp, c;
2228 float dist_to_plane;
2229 float square_size, ux, uy, uz;
2231 ux = tplane.A = gridp->gmatrix.v.uvec.xyz.x;
2232 uy = tplane.B = gridp->gmatrix.v.uvec.xyz.y;
2233 uz = tplane.C = gridp->gmatrix.v.uvec.xyz.z;
2234 tplane.D = gridp->planeD;
2236 compute_point_on_plane(&c, &tplane, pos);
2237 dist_to_plane = fl_abs(vm_dist_to_plane(pos, &gridp->gmatrix.v.uvec, &c));
2240 while (dist_to_plane >= 25.0f)
2242 square_size *= 10.0f;
2243 dist_to_plane /= 10.0f;
2246 if (fvi_ray_plane(&gpos, &gridp->center, &gridp->gmatrix.v.uvec, pos, &orient->v.fvec, 0.0f)<0.0f) {
2248 vm_vec_scale_add(&p,pos,&orient->v.fvec, 100.0f );
2249 compute_point_on_plane(&gpos, &tplane, &p );
2252 if (vm_vec_dist(&gpos, &c) > 50.0f * square_size)
2254 vm_vec_sub(&tmp, &gpos, &c);
2255 vm_vec_normalize(&tmp);
2256 vm_vec_scale_add(&gpos, &c, &tmp, 50.0f * square_size);
2259 roundoff = (int) square_size * 10;
2261 gpos.xyz.x = fl_roundoff(gpos.xyz.x, roundoff);
2263 gpos.xyz.y = fl_roundoff(gpos.xyz.y, roundoff);
2265 gpos.xyz.z = fl_roundoff(gpos.xyz.z, roundoff);
2267 if ((square_size != gridp->square_size) ||
2268 (gpos.xyz.x != gridp->center.xyz.x) ||
2269 (gpos.xyz.y != gridp->center.xyz.y) ||
2270 (gpos.xyz.z != gridp->center.xyz.z) || force)
2272 gridp->square_size = square_size;
2273 gridp->center = gpos;
2274 brief_modify_grid(gridp);
2279 // *forward is vector pointing forward
2280 // *right is vector pointing right
2281 // *center is center point of grid
2282 // length is length of grid
2283 // width is width of grid
2284 // square_size is size of a grid square
2286 // *forward = (0.0, 0.0, 1.0)
2287 // *right = (1.0, 0.0, 0.0)
2288 // *center = (0.0, 0.0, 0.0)
2291 // square_size = 10.0
2292 // will generate a grid of squares 10 long by 5 wide.
2293 // Each grid square will be 10.0 x 10.0 units.
2294 // The center of the grid will be at the global origin.
2295 // The grid will be parallel to the xz plane (because the normal is 0,1,0).
2296 // (In fact, it will be the xz plane because it is centered on the origin.)
2298 // Stuffs grid in *gridp. If gridp == NULL, mallocs and returns a grid.
2299 grid *brief_create_grid(grid *gridp, vector *forward, vector *right, vector *center, int nrows, int ncols, float square_size)
2301 int i, ncols2, nrows2, d = 1;
2302 vector dfvec, drvec, cur, cur2, tvec, uvec, save, save2;
2304 Assert(square_size > 0.0);
2305 if (double_fine_gridlines)
2309 gridp = (grid *) malloc(sizeof(grid));
2313 gridp->center = *center;
2314 gridp->square_size = square_size;
2316 // Create the plane equation.
2317 Assert(!IS_VEC_NULL(forward));
2318 Assert(!IS_VEC_NULL(right));
2320 vm_vec_copy_normalize(&dfvec, forward);
2321 vm_vec_copy_normalize(&drvec, right);
2323 vm_vec_cross(&uvec, &dfvec, &drvec);
2325 Assert(!IS_VEC_NULL(&uvec));
2327 gridp->gmatrix.v.uvec = uvec;
2329 gridp->planeD = -(center->xyz.x * uvec.xyz.x + center->xyz.y * uvec.xyz.y + center->xyz.z * uvec.xyz.z);
2330 Assert(!_isnan(gridp->planeD));
2332 gridp->gmatrix.v.fvec = dfvec;
2333 gridp->gmatrix.v.rvec = drvec;
2335 vm_vec_scale(&dfvec, square_size);
2336 vm_vec_scale(&drvec, square_size);
2338 vm_vec_scale_add(&cur, center, &dfvec, (float) -nrows * d / 2);
2339 vm_vec_scale_add2(&cur, &drvec, (float) -ncols * d / 2);
2340 vm_vec_scale_add(&cur2, center, &dfvec, (float) -nrows * 5 / 2);
2341 vm_vec_scale_add2(&cur2, &drvec, (float) -ncols * 5 / 2);
2345 gridp->ncols = ncols;
2346 gridp->nrows = nrows;
2349 Assert(ncols < MAX_GRIDLINE_POINTS && nrows < MAX_GRIDLINE_POINTS);
2351 // Create the points along the edges of the grid, so we can just draw lines
2352 // between them to form the grid.
2353 for (i=0; i<=ncols*d; i++) {
2354 gridp->gpoints1[i] = cur; // small, dark gridline points
2355 vm_vec_scale_add(&tvec, &cur, &dfvec, (float) nrows * d);
2356 gridp->gpoints2[i] = tvec;
2357 vm_vec_add2(&cur, &drvec);
2360 for (i=0; i<=ncols2; i++) {
2361 gridp->gpoints5[i] = cur2; // large, brighter gridline points
2362 vm_vec_scale_add(&tvec, &cur2, &dfvec, (float) nrows2 * 10);
2363 gridp->gpoints6[i] = tvec;
2364 vm_vec_scale_add2(&cur2, &drvec, 10.0f);
2369 for (i=0; i<=nrows*d; i++) {
2370 gridp->gpoints3[i] = cur; // small, dark gridline points
2371 vm_vec_scale_add(&tvec, &cur, &drvec, (float) ncols * d);
2372 gridp->gpoints4[i] = tvec;
2373 vm_vec_add2(&cur, &dfvec);
2376 for (i=0; i<=nrows2; i++) {
2377 gridp->gpoints7[i] = cur2; // large, brighter gridline points
2378 vm_vec_scale_add(&tvec, &cur2, &drvec, (float) ncols2 * 10);
2379 gridp->gpoints8[i] = tvec;
2380 vm_vec_scale_add2(&cur2, &dfvec, 10.0f);
2386 // Create a nice grid -- centered at origin, 10x10, 10.0 size squares, in xz plane.
2387 grid *brief_create_default_grid(void)
2390 vector fvec, rvec, cvec;
2392 rgrid = brief_create_grid(&Global_grid, vm_vec_make(&fvec, 0.0f, 0.0f, 1.0f),
2393 vm_vec_make(&rvec, 1.0f, 0.0f, 0.0f),
2394 vm_vec_make(&cvec, 0.0f, -10.0f, 0.0f), 100, 100, 5.0f);
2396 physics_init(&rgrid->physics);
2397 rgrid->physics.flags |= (PF_ACCELERATES | PF_SLIDE_ENABLED);
2401 // Rotate and project points and draw a line.
2402 void brief_rpd_line(vector *v0, vector *v1)
2405 g3_rotate_vertex(&tv0, v0);
2406 g3_rotate_vertex(&tv1, v1);
2409 g3_project_vertex(&tv0);
2410 g3_project_vertex(&tv1);
2412 if ( (tv0.flags & PF_OVERFLOW) || (tv1.flags & PF_OVERFLOW) )
2416 gr_set_color_fast(&Color_grey);
2417 g3_draw_line(&tv0, &tv1);
2420 // Renders a grid defined in a grid struct
2421 void brief_render_grid(grid *gridp)
2423 int i, ncols, nrows;
2425 ncols = gridp->ncols;
2426 nrows = gridp->nrows;
2427 if (double_fine_gridlines)
2433 gr_set_color(30,30,30);
2436 // Draw the column lines.
2437 for (i=0; i<=ncols; i++)
2438 brief_rpd_line(&gridp->gpoints1[i], &gridp->gpoints2[i]);
2440 // Draw the row lines.
2441 for (i=0; i<=nrows; i++)
2442 brief_rpd_line(&gridp->gpoints3[i], &gridp->gpoints4[i]);
2444 ncols = gridp->ncols / 2;
2445 nrows = gridp->nrows / 2;
2447 // now draw the larger, brighter gridlines that is x10 the scale of smaller one.
2450 for (i=0; i<=ncols; i++)
2451 brief_rpd_line(&gridp->gpoints5[i], &gridp->gpoints6[i]);
2453 for (i=0; i<=nrows; i++)
2454 brief_rpd_line(&gridp->gpoints7[i], &gridp->gpoints8[i]);
2458 void brief_modify_grid(grid *gridp)
2460 brief_create_grid(gridp, &gridp->gmatrix.v.fvec, &gridp->gmatrix.v.rvec, &gridp->center,
2461 gridp->nrows, gridp->ncols, gridp->square_size);
2464 void brief_unload_anims()
2471 for (i=0; i<MAX_BRIEF_ICONS; i++) {
2473 for(idx=0; idx<MAX_SPECIES_NAMES; idx++){
2474 hud_anim_release(&Icon_highlight_anims[i][idx]);
2475 hud_anim_release(&Icon_fade_anims[i][idx]);
2478 // one set of icons in FS1
2479 hud_anim_release(&Icon_highlight_anims[i][1]);
2480 hud_anim_release(&Icon_fade_anims[i][1]);
2485 void brief_common_close()
2488 brief_unload_anims();
2492 void brief_restart_text_wipe()
2494 Brief_stage_time = 0;
2495 Brief_voice_ended = 0;
2496 Brief_voice_started = 0;
2497 Brief_text_wipe_time_elapsed = 0.0f;
2500 // initialize the array of handles to the different voice streams
2501 void brief_voice_init()
2504 for ( i = 0; i < MAX_BRIEF_STAGES; i++ ) {
2505 Brief_voices[i] = -1;
2509 void brief_load_voice_file(int voice_num, char *name)
2511 int load_attempts = 0;
2514 if ( load_attempts++ > 5 ) {
2518 Brief_voices[voice_num] = audiostream_open( name, ASF_VOICE );
2519 if ( Brief_voices[voice_num] >= 0 ) {
2523 // Don't bother to ask for the CD in multiplayer
2524 if ( Game_mode & GM_MULTIPLAYER ) {
2528 // couldn't load animation, ask user to insert CD (if necessary)
2529 // if ( Brief_voice_ask_for_cd ) {
2530 // if ( game_do_cd_check() == 0 ) {
2531 // Brief_voice_ask_for_cd = 0;
2538 // open and pre-load the stream buffers for the different voice streams
2539 void brief_voice_load_all()
2544 // Brief_voice_ask_for_cd = 1;
2546 Assert( Briefing != NULL );
2547 for ( i = 0; i < Briefing->num_stages; i++ ) {
2548 bs = &Briefing->stages[i];
2549 if ( strnicmp(bs->voice, NOX("none"), 4) ) {
2550 brief_load_voice_file(i, bs->voice);
2551 // Brief_voices[i] = audiostream_open( bs->voice, ASF_VOICE );
2556 // close all the briefing voice streams
2557 void brief_voice_unload_all()
2561 for ( i = 0; i < MAX_BRIEF_STAGES; i++ ) {
2562 if ( Brief_voices[i] != -1 ) {
2563 audiostream_close_file(Brief_voices[i], 0);
2564 Brief_voices[i] = -1;
2569 // start playback of the voice for a particular briefing stage
2570 void brief_voice_play(int stage_num)
2572 if ( Brief_voices[stage_num] == -1 )
2573 return; // voice file doesn't exist
2575 if ( !Briefing_voice_enabled ) {
2579 if ( audiostream_is_playing( Brief_voices[stage_num]) )
2582 audiostream_play(Brief_voices[stage_num], Master_voice_volume, 0);
2583 Brief_voice_started = 1;
2586 // stop playback of the voice for a particular briefing stage
2587 void brief_voice_stop(int stage_num)
2589 if ( Brief_voices[stage_num] == -1 )
2592 audiostream_stop(Brief_voices[stage_num]); // stream is automatically rewound
2595 // pause playback of the voice for a particular briefing stage, to resume just
2596 // call brief_voice_unpause() again
2597 void brief_voice_pause(int stage_num)
2599 if ( Brief_voices[stage_num] == -1 )
2602 audiostream_pause(Brief_voices[stage_num]);
2605 void brief_voice_unpause(int stage_num)
2607 if ( Brief_voices[stage_num] == -1 )
2610 audiostream_unpause(Brief_voices[stage_num]);
2613 void brief_reset_last_new_stage()
2615 Last_new_stage = -1;
2618 // get the dimensions for a briefing icon
2619 void brief_common_get_icon_dimensions(int *w, int *h, int type, int ship_class)
2621 Assert(type >= 0 && type < MAX_BRIEF_ICONS);
2623 // in case anything goes wrong
2627 int species = ship_get_species_by_type(ship_class);
2632 if ( Icon_bitmaps[type][species].first_frame >= 0 ) {
2633 bm_get_info( Icon_bitmaps[type][species].first_frame, w, h, NULL);
2640 void cmd_brief_reset()
2643 static int inited = 0;
2646 for (i=0; i<MAX_TEAMS; i++) {
2647 for (j=0; j<Cmd_briefs[i].num_stages; j++) {
2648 if (Cmd_briefs[i].stage[j].text)
2649 free(Cmd_briefs[i].stage[j].text);
2655 for (i=0; i<MAX_TEAMS; i++)
2656 Cmd_briefs[i].num_stages = 0;
2659 #define STAGE_ADVANCE_DELAY 1000 // time in ms to wait after voice stops before advancing stage
2661 // should briefing advance to the next stage?
2662 int brief_time_to_advance(int stage_num, float frametime)
2664 int voice_active, advance = 0;
2665 brief_icon *closeup_icon;
2667 closeup_icon = brief_get_closeup_icon();
2669 if ( closeup_icon ) {
2673 if ( !Player->auto_advance ) {
2677 Brief_stage_time += fl2i(frametime*1000 + 0.5f);
2679 if ( (Brief_voices[stage_num] >= 0) && Briefing_voice_enabled ) {
2685 if ( voice_active && (Brief_voice_ended == 0) && Brief_voice_started) {
2686 if ( !audiostream_is_playing( Brief_voices[stage_num]) ) {
2687 Brief_voice_ended = 1;
2688 Brief_stage_time = 0;
2692 if ( Brief_voice_ended ) {
2693 if ( Brief_stage_time > STAGE_ADVANCE_DELAY ) {
2698 if ( !voice_active && (Brief_textdraw_finished > 0) ) {
2699 if ( Brief_stage_time > max(5000, Num_brief_text_lines[0] * 3500) ) {