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/Hud/HUDtargetbox.cpp $
15 * C module for drawing the target monitor box on the HUD
18 * Revision 1.7 2003/06/03 04:00:40 taylor
19 * Polish language support (Janusz Dziemidowicz)
21 * Revision 1.6 2003/05/25 02:30:42 taylor
24 * Revision 1.5 2002/06/18 08:58:53 relnev
25 * last few struct changes
27 * Revision 1.4 2002/06/17 06:33:09 relnev
28 * ryan's struct patch for gcc 2.95
30 * Revision 1.3 2002/06/09 04:41:21 relnev
31 * added copyright header
33 * Revision 1.2 2002/05/07 03:16:45 theoddone33
34 * The Great Newline Fix
36 * Revision 1.1.1.1 2002/05/03 03:28:09 root
40 * 31 11/02/99 3:22p Jefff
41 * translation of targetbox text
43 * 30 10/29/99 10:41p Jefff
44 * more subsystem fixes
46 * 29 10/28/99 11:17p Jefff
47 * used escape seqs for some special German chars
49 * 28 10/28/99 2:02a Jefff
50 * revised the subsystem localization
52 * 27 9/14/99 11:03p Jefff
53 * dont draw target names from # on (weapons case)
55 * 26 9/04/99 5:17p Andsager
56 * Make event log record name of destroyed subsytem, and use this name for
57 * different types of turrets
59 * 25 8/25/99 11:35a Andsager
60 * Move hud render ship subsystem target box for ships with Autocenter
62 * 24 8/17/99 7:32p Jefff
63 * models use autocenter in target view
65 * 23 8/01/99 12:39p Dave
66 * Added HUD contrast control key (for nebula).
68 * 22 7/31/99 4:15p Dave
69 * Fixed supernova particle velocities. Handle OBJ_NONE in target
70 * monitoring view. Properly use objectives notify gauge colors.
72 * 21 7/28/99 2:49p Andsager
73 * Make hud target speed use vm_vec_mag (not vm_vec_mag_quick)
75 * 20 7/15/99 9:20a Andsager
76 * FS2_DEMO initial checkin
78 * 19 7/02/99 10:56a Andsager
79 * Put in big ship - big ship attack mode. Modify stealth sweep ai.
81 * 18 6/29/99 3:16p Andsager
84 * 17 6/10/99 3:43p Dave
85 * Do a better job of syncing text colors to HUD gauges.
87 * 16 6/09/99 2:55p Andsager
88 * Allow multiple asteroid subtypes (of large, medium, small) and follow
91 * 15 6/07/99 4:20p Andsager
92 * Add HUD color for tagged object. Apply to target and radar.
94 * 14 6/03/99 11:43a Dave
95 * Added the ability to use a different model when rendering to the HUD
98 * 13 5/24/99 9:02a Andsager
99 * Remove Int3() in turret subsys name code when turret has no weapon.
101 * 12 5/21/99 1:42p Andsager
102 * Added error checking for HUD turret name
104 * 11 5/20/99 7:00p Dave
105 * Added alternate type names for ships. Changed swarm missile table
108 * 10 5/19/99 3:50p Andsager
109 * Show type of debris is debris field (species debris or asteroid). Show
110 * type of subsystem turret targeted (laser, missile, flak, beam).
112 * 9 5/14/99 4:22p Andsager
113 * Modify hud_render_target_ship to show damaged subsystems in their
114 * actual state. Now also shows rotation of subsystems.
116 * 8 4/16/99 5:54p Dave
117 * Support for on/off style "stream" weapons. Real early support for
118 * target-painting lasers.
120 * 7 1/07/99 9:08a Jasen
123 * 6 12/28/98 3:17p Dave
124 * Support for multiple hud bitmap filenames for hi-res mode.
126 * 5 12/21/98 5:03p Dave
127 * Modified all hud elements to be multi-resolution friendly.
129 * 4 11/05/98 4:18p Dave
130 * First run nebula support. Beefed up localization a bit. Removed all
131 * conditional compiles for foreign versions. Modified mission file
134 * 3 10/13/98 9:28a Dave
135 * Started neatening up freespace.h. Many variables renamed and
136 * reorganized. Added AlphaColors.[h,cpp]
138 * 2 10/07/98 10:53a Dave
141 * 1 10/07/98 10:49a Dave
143 * 108 8/28/98 3:28p Dave
144 * EMP effect done. AI effects may need some tweaking as required.
146 * 107 8/25/98 1:48p Dave
147 * First rev of EMP effect. Player side stuff basically done. Next comes
150 * 106 6/19/98 3:49p Lawrance
151 * localization tweaks
153 * 105 6/17/98 11:04a Lawrance
154 * localize subsystem names that appear on the HUD
156 * 104 6/09/98 5:18p Lawrance
157 * French/German localization
159 * 103 6/09/98 10:31a Hoffoss
160 * Created index numbers for all xstr() references. Any new xstr() stuff
161 * added from here on out should be added to the end if the list. The
162 * current list count can be found in FreeSpace.cpp (search for
165 * 102 6/01/98 11:43a John
166 * JAS & MK: Classified all strings for localization.
168 * 101 5/20/98 3:52p Allender
169 * fixed compiler warnings
171 * 100 5/20/98 12:59p John
172 * Turned optimizations on for debug builds. Also turning on automatic
173 * function inlining. Turned off the unreachable code warning.
175 * 99 5/15/98 8:36p Lawrance
176 * Add 'target ship that last sent transmission' target key
178 * 98 5/14/98 11:26a Lawrance
179 * ensure fighter bays are drawn with correct bracket color
181 * 97 5/08/98 5:32p Lawrance
182 * Allow cargo scanning even if target gauge is disabled
184 * 96 5/04/98 10:51p Lawrance
185 * remove unused local
187 * 95 5/04/98 9:17p Lawrance
188 * Truncate ship class names at # char when displaying debris on target
191 * 94 5/04/98 6:12p Lawrance
192 * Write generic function hud_end_string_at_first_hash_symbol(), to use in
193 * various spots on the HUD
195 * 93 4/15/98 12:55a Lawrance
196 * Show time to impact for bombs
198 * 92 4/02/98 6:31p Lawrance
199 * remove asteroid references if DEMO defined
201 * 91 3/31/98 5:18p John
202 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
203 * bunch of debug stuff out of player file. Made model code be able to
204 * unload models and malloc out only however many models are needed.
207 * 90 3/30/98 1:08a Lawrance
208 * Implement "blast" icon. Blink HUD icon when player ship is hit by a
216 #include "3dinternal.h"
219 #include "hudtarget.h"
220 #include "hudbrackets.h"
223 #include "missionparse.h"
228 #include "freespace.h"
231 #include "subsysdamage.h"
232 #include "hudtargetbox.h"
234 #include "asteroid.h"
235 #include "jumpnode.h"
238 #include "localize.h"
240 int Target_window_coords[GR_NUM_RESOLUTIONS][4] =
250 object *Enemy_attacker = NULL;
252 static int Target_static_next;
253 static int Target_static_playing;
254 int Target_static_looping;
257 extern int Show_target_debug_info;
258 extern int Show_target_weapons;
261 // used to print out + or - after target distance and speed
262 const char* modifiers[] = {
270 const char *Target_view_fname[GR_NUM_RESOLUTIONS] = {
274 const char *Target_integ_fname[GR_NUM_RESOLUTIONS] = {
278 const char *Target_extra_fname[GR_NUM_RESOLUTIONS] = {
283 // animation frames for the target view monitor
284 // frames: 0 => background of target monitor
285 // 1 => foreground of target monitor
286 hud_frames Target_view_gauge;
287 int Target_view_gauge_loaded = 0;
289 // animation frames for the extended target information
290 // frames: 0 => normal gague
291 hud_frames Target_view_extra;
292 int Target_view_extra_loaded = 0;
294 // animation frames for the target view monitor integrity bar
295 // frames: 0 => dark bar
297 hud_frames Target_view_integrity_gauge;
298 int Target_view_integrity_gauge_loaded = 0;
300 #define NUM_TBOX_COORDS 11 // keep up to date
301 #define TBOX_BACKGROUND 0
309 #define TBOX_EXTRA_ORDERS 8
310 #define TBOX_EXTRA_TIME 9
311 #define TBOX_EXTRA_DOCK 10
313 int Targetbox_coords[GR_NUM_RESOLUTIONS][NUM_TBOX_COORDS][2] =
343 int Integrity_bar_coords[GR_NUM_RESOLUTIONS][4] = {
351 int Integrity_string_coords[GR_NUM_RESOLUTIONS][2] = {
360 // cargo scanning extents
361 int Cargo_scan_coords[GR_NUM_RESOLUTIONS][4] = {
370 // first element is time flashing expires, second element is time of next flash
371 int Targetbox_flash_timers[NUM_TBOX_FLASH_TIMERS][2];
372 int Targetbox_flash_flags;
374 // flag to indicate whether to show the extra information about a target
375 // The HUD_config controls whether this can be shown... but the player can still toggle it on/off
377 int Targetbox_show_extra_info = 1;
379 // Different target states. This drives the text display right below the hull integrity on the targetbox.
385 static int Last_ts; // holds last target status.
387 void hud_blit_target_integrity(int disabled,int force_obj_num = -1);
389 // cut down long subsystem names to a more manageable length
390 char *hud_targetbox_truncate_subsys_name(char *outstr, const int max_len)
393 if ( strstr(outstr, "communication") ) {
394 SDL_strlcpy(outstr, "Komm", max_len);
395 } else if ( !SDL_strcasecmp(outstr, "weapons") ) {
396 SDL_strlcpy(outstr, "Waffen", max_len);
397 } else if ( strstr(outstr, "engine") || strstr(outstr, "Engine")) {
398 SDL_strlcpy(outstr, "Antrieb", max_len);
399 } else if ( !SDL_strcasecmp(outstr, "sensors") ) {
400 SDL_strlcpy(outstr, "Sensoren", max_len);
401 } else if ( strstr(outstr, "navigat") ) {
402 SDL_strlcpy(outstr, "Nav", max_len);
403 } else if ( strstr(outstr, "fighterbay") || strstr(outstr, "Fighterbay") ) {
404 SDL_strlcpy(outstr, "J\x84gerhangar", max_len);
405 } else if ( strstr(outstr, "missile") ) {
406 SDL_strlcpy(outstr, "Raketenwerfer", max_len);
407 } else if ( strstr(outstr, "laser") || strstr(outstr, "turret") ) {
408 SDL_strlcpy(outstr, "Gesch\x81tzturm", max_len);
409 } else if ( strstr(outstr, "Command Tower") || strstr(outstr, "Bridge") ) {
410 SDL_strlcpy(outstr, "Br\x81""cke", max_len);
411 } else if ( strstr(outstr, "Barracks") ) {
412 SDL_strlcpy(outstr, "Quartiere", max_len);
413 } else if ( strstr(outstr, "Reactor") ) {
414 SDL_strlcpy(outstr, "Reaktor", max_len);
415 } else if ( strstr(outstr, "RadarDish") ) {
416 SDL_strlcpy(outstr, "Radarantenne", max_len);
417 } else if (!SDL_strcasecmp(outstr, "Gas Collector")) {
418 SDL_strlcpy(outstr, "Sammler", max_len);
421 if ( strstr(outstr, "communication") ) {
422 SDL_strlcpy(outstr, "comm", max_len);
423 } else if ( !SDL_strcasecmp(outstr, "weapons") ) {
424 SDL_strlcpy(outstr, "armes", max_len);
425 } else if ( strstr(outstr, "engine") ) {
426 SDL_strlcpy(outstr, "moteur", max_len);
427 } else if ( !SDL_strcasecmp(outstr, "sensors") ) {
428 SDL_strlcpy(outstr, "detecteurs", max_len);
429 } else if ( strstr(outstr, "navi") ) {
430 SDL_strlcpy(outstr, "nav", max_len);
431 } else if ( strstr(outstr, "missile") ) {
432 SDL_strlcpy(outstr, "lanceur de missiles", max_len);
433 } else if ( strstr(outstr, "fighter") ) {
434 SDL_strlcpy(outstr, "baie de chasse", max_len);
435 } else if ( strstr(outstr, "laser") || strstr(outstr, "turret") || strstr(outstr, "missile") ) {
436 SDL_strlcpy(outstr, "tourelle", max_len);
439 if ( strstr(outstr, "communication") ) {
440 SDL_strlcpy(outstr, "komunikacja", max_len);
441 } else if ( !SDL_strcasecmp(outstr, "weapons") ) {
442 SDL_strlcpy(outstr, "uzbrojenie", max_len);
443 } else if ( strstr(outstr, "engine") || strstr(outstr, "Engine")) {
444 SDL_strlcpy(outstr, "silnik", max_len);
445 } else if ( !SDL_strcasecmp(outstr, "sensors") ) {
446 SDL_strlcpy(outstr, "sensory", max_len);
447 } else if ( strstr(outstr, "navigat") ) {
448 SDL_strlcpy(outstr, "nawigacja", max_len);
449 } else if ( strstr(outstr, "fighterbay") || strstr(outstr, "Fighterbay") ) {
450 SDL_strlcpy(outstr, "dok my\x9Cliw.", max_len);
451 } else if ( strstr(outstr, "missile") ) {
452 SDL_strlcpy(outstr, "wie\xBF. rakiet.", max_len);
453 } else if ( strstr(outstr, "laser") || strstr(outstr, "turret") ) {
454 SDL_strlcpy(outstr, "wie\xBFyczka", max_len);
455 } else if ( strstr(outstr, "Command Tower") || strstr(outstr, "Bridge") ) {
456 SDL_strlcpy(outstr, "mostek", max_len);
457 } else if ( strstr(outstr, "Barracks") ) {
458 SDL_strlcpy(outstr, "koszary", max_len);
459 } else if ( strstr(outstr, "Reactor") ) {
460 SDL_strlcpy(outstr, "reaktor", max_len);
461 } else if ( strstr(outstr, "RadarDish") ) {
462 SDL_strlcpy(outstr, "antena radaru", max_len);
463 } else if (!SDL_strcasecmp(outstr, "Gas Collector")) {
464 SDL_strlcpy(outstr, "zbieracz gazu", max_len);
467 if (!SDL_strncasecmp(outstr, XSTR( "communication", 333), 3)) {
468 SDL_strlcpy( outstr, XSTR( "comm", 334), max_len );
469 } else if (!SDL_strncasecmp(outstr, XSTR( "navigation", 335), 3)) {
470 SDL_strlcpy( outstr, XSTR( "nav", 336), max_len );
471 } else if (!SDL_strcasecmp(outstr, "Gas Collector")) {
472 SDL_strlcpy(outstr, "Collector", max_len);
479 // init a specific targetbox timer
480 void hud_targetbox_init_flash_timer(int index)
482 Targetbox_flash_timers[index][0] = 1;
483 Targetbox_flash_timers[index][1] = 1;
484 Targetbox_flash_flags &= ~(1<<index);
487 // init the timers used to flash different parts of the targetbox. This needs to get called whenever
488 // the current target changes.
489 void hud_targetbox_init_flash()
491 hud_targetbox_init_flash_timer(TBOX_FLASH_NAME);
492 hud_targetbox_init_flash_timer(TBOX_FLASH_CARGO);
493 hud_targetbox_init_flash_timer(TBOX_FLASH_HULL);
494 hud_targetbox_init_flash_timer(TBOX_FLASH_STATUS);
495 hud_targetbox_init_flash_timer(TBOX_FLASH_SUBSYS);
496 hud_targetbox_init_flash_timer(TBOX_FLASH_DOCKED);
501 // set the color for flashing text
502 // input: index => item to flash
503 // flash_fast => optional param (default value 0), flash twice as fast
504 // exit: 1 => set bright color
505 // 0 => set default color
506 int hud_targetbox_maybe_flash(int index, int flash_fast)
510 // hud_set_default_color();
511 hud_set_gauge_color(HUD_TARGET_MONITOR);
512 if ( !timestamp_elapsed(Targetbox_flash_timers[index][0]) ) {
513 if ( timestamp_elapsed(Targetbox_flash_timers[index][1]) ) {
515 Targetbox_flash_timers[index][1] = timestamp(fl2i(TBOX_FLASH_INTERVAL/2.0f));
517 Targetbox_flash_timers[index][1] = timestamp(TBOX_FLASH_INTERVAL);
519 Targetbox_flash_flags ^= (1<<index); // toggle between default and bright frames
522 if ( Targetbox_flash_flags & (1<<index) ) {
523 // hud_set_bright_color();
524 hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT);
527 // hud_set_dim_color();
528 hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_DIM);
535 // init all targetbox flash timers
536 void hud_targetbox_init_all_timers()
539 for ( i = 0; i < NUM_TBOX_FLASH_TIMERS; i++ ) {
540 hud_targetbox_init_flash_timer(i);
546 // Initialize the data needed for the target view. This is called from HUD_init() once per mission
547 void hud_targetbox_init()
549 if (!Target_view_gauge_loaded) {
550 Target_view_gauge.first_frame = bm_load_animation(Target_view_fname[gr_screen.res], &Target_view_gauge.num_frames);
551 if ( Target_view_gauge.first_frame < 0 ) {
552 Warning(LOCATION,"Cannot load hud ani: %s\n", Target_view_fname[gr_screen.res]);
554 Target_view_gauge_loaded = 1;
557 if (!Target_view_integrity_gauge_loaded) {
558 Target_view_integrity_gauge.first_frame = bm_load_animation(Target_integ_fname[gr_screen.res], &Target_view_integrity_gauge.num_frames);
559 if ( Target_view_integrity_gauge.first_frame < 0 ) {
560 Warning(LOCATION,"Cannot load hud ani: %s\n", Target_integ_fname[gr_screen.res]);
562 Target_view_integrity_gauge_loaded = 1;
565 if (!Target_view_extra_loaded) {
566 Target_view_extra.first_frame = bm_load_animation(Target_extra_fname[gr_screen.res], &Target_view_extra.num_frames);
567 if ( Target_view_extra.first_frame < 0 ) {
568 Warning(LOCATION,"Cannot load hud ani: %s\n", Target_extra_fname[gr_screen.res]);
570 Target_view_extra_loaded = 1;
573 hud_targetbox_init_all_timers();
576 // -------------------------------------------------------------------------------------
577 // hud_save_restore_camera_data()
579 // Called to save and restore the 3D camera settings.
581 void hud_save_restore_camera_data(int save)
583 static vector save_view_position;
584 static float save_view_zoom;
585 static matrix save_view_matrix;
586 static matrix save_eye_matrix;
587 static vector save_eye_position;
589 // save global view variables, so we can restore them
591 save_view_position = View_position;
592 save_view_zoom = View_zoom;
593 save_view_matrix = View_matrix;
594 save_eye_matrix = Eye_matrix;
595 save_eye_position = Eye_position;
598 // restore global view variables
599 View_position = save_view_position;
600 View_zoom = save_view_zoom;
601 View_matrix = save_view_matrix;
602 Eye_matrix = save_eye_matrix;
603 Eye_position = save_eye_position;
607 // -------------------------------------------------------------------------------------
608 // hud_render_target_background()
610 // Common set up for drawing the background of the target monitor, for ships/debris/missiles
612 void hud_render_target_background()
614 // blit the background frame
615 hud_set_gauge_color(HUD_TARGET_MONITOR);
617 GR_AABITMAP(Target_view_gauge.first_frame, Targetbox_coords[gr_screen.res][TBOX_BACKGROUND][0],Targetbox_coords[gr_screen.res][TBOX_BACKGROUND][1]);
619 // blit the extra targeting info frame
620 hud_set_gauge_color(HUD_TARGET_MONITOR_EXTRA_DATA);
624 // -------------------------------------------------------------------------------------
625 // hud_render_target_setup()
627 // Common set up for the 3d code for drawing the target monitor, for ships/debris/missiles
629 void hud_render_target_setup(vector *camera_eye, matrix *camera_orient, float zoom)
631 // JAS: g3_start_frame uses clip_width and clip_height to determine the
632 // size to render to. Normally, you would set this by using gr_set_clip,
633 // but because of the hacked in hud jittering, I couldn't. So come talk
634 // to me before modifying or reusing the following code. Thanks.
636 gr_screen.clip_width = Target_window_coords[gr_screen.res][2];
637 gr_screen.clip_height = Target_window_coords[gr_screen.res][3];
638 g3_start_frame(1); // Turn on zbuffering
639 hud_save_restore_camera_data(1);
640 g3_set_view_matrix( camera_eye, camera_orient, zoom);
641 model_set_detail_level(1); // use medium detail level
643 HUD_set_clip(Target_window_coords[gr_screen.res][0],Target_window_coords[gr_screen.res][1],Target_window_coords[gr_screen.res][2],Target_window_coords[gr_screen.res][3]);
647 // -------------------------------------------------------------------------------------
648 // hud_render_target_close()
650 // Common clean-up after drawing the target monitor, for ships/debris/missiles
652 void hud_render_target_close()
655 hud_save_restore_camera_data(0);
658 // -------------------------------------------------------------------------------------
659 // hud_blit_target_foreground()
661 void hud_blit_target_foreground()
663 hud_set_gauge_color(HUD_TARGET_MONITOR);
665 GR_AABITMAP(Target_view_gauge.first_frame+1, Targetbox_coords[gr_screen.res][TBOX_BACKGROUND][0],Targetbox_coords[gr_screen.res][TBOX_BACKGROUND][1]);
668 // -------------------------------------------------------------------------------------
669 // hud_get_target_strength()
671 // Get the shield and hull percentages for a given ship object
673 // input: *objp => pointer to ship object that you want strength values for
674 // shields => OUTPUT parameter: percentage value of shields (0->1.0)
675 // integrity => OUTPUT parameter: percentage value of integrity (0->1.0)
677 void hud_get_target_strength(object *objp, float *shields, float *integrity)
681 if ( objp->type != OBJ_SHIP ) {
686 sip = &Ship_info[Ships[objp->instance].ship_info_index];
688 if (!( sip->shields == 0.0f )){
689 *shields = get_shield_strength(objp) / sip->shields;
694 if (*shields < 0.0f){
698 if ( sip->initial_hull_strength == 0 ) {
699 Int3(); // illegal initial hull strength
704 *integrity = objp->hull_strength / sip->initial_hull_strength;
709 // maybe draw the extra targeted ship information above the target monitor
710 void hud_targetbox_show_extra_ship_info(ship *target_shipp, ai_info *target_aip)
712 char outstr[256], tmpbuf[256];
715 int extra_data_shown=0;
717 hud_set_gauge_color(HUD_TARGET_MONITOR_EXTRA_DATA);
719 not_training = !(The_mission.game_type & MISSION_TYPE_TRAINING);
720 if ( not_training && (hud_gauge_active(HUD_TARGET_MONITOR_EXTRA_DATA)) && (Targetbox_show_extra_info) ) {
721 // Print out current orders if the targeted ship is friendly
722 // AL 12-26-97: only show orders and time to target for friendly ships
723 if ( (Player_ship->team == target_shipp->team) && !(ship_get_SIF(target_shipp) & SIF_NOT_FLYABLE) ) {
725 if ( ship_return_orders(outstr, sizeof(outstr), target_shipp) ) {
726 gr_force_fit_string(outstr, 255, 162);
729 SDL_strlcpy(outstr, XSTR( "no orders", 337), sizeof(outstr));
732 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_EXTRA_ORDERS][0], Targetbox_coords[gr_screen.res][TBOX_EXTRA_ORDERS][1], EG_TBOX_EXTRA1, outstr);
736 SDL_strlcpy(outstr, XSTR( "time to: ", 338), sizeof(outstr));
737 if ( ship_return_time_to_goal(tmpbuf, sizeof(tmpbuf), target_shipp) ) {
738 SDL_strlcat(outstr, tmpbuf, sizeof(outstr));
740 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_EXTRA_TIME][0], Targetbox_coords[gr_screen.res][TBOX_EXTRA_TIME][1], EG_TBOX_EXTRA2, outstr);
745 // Print out dock status
746 if ( target_aip->ai_flags & AIF_DOCKED ) {
747 if ( target_aip->dock_objnum >= 0 ) {
748 SDL_snprintf(outstr, sizeof(outstr), XSTR( "Docked: %s", 339), Ships[Objects[target_aip->dock_objnum].instance].ship_name);
749 gr_force_fit_string(outstr, 255, 173);
750 hud_targetbox_maybe_flash(TBOX_FLASH_DOCKED);
752 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_EXTRA_DOCK][0], Targetbox_coords[gr_screen.res][TBOX_EXTRA_DOCK][1], EG_TBOX_EXTRA3, outstr);
757 if ( extra_data_shown ) {
758 // hud_set_default_color();
760 GR_AABITMAP(Target_view_extra.first_frame, Targetbox_coords[gr_screen.res][TBOX_EXTRA][0],Targetbox_coords[gr_screen.res][TBOX_EXTRA][1]);
764 // Render a jump node on the target monitor
765 void hud_render_target_jump_node(object *target_objp)
768 vector obj_pos = ZERO_VECTOR;
769 vector camera_eye = ZERO_VECTOR;
770 matrix camera_orient = IDENTITY_MATRIX;
771 vector orient_vec, up_vector;
775 if ( Detail.targetview_model ) {
776 // take the forward orientation to be the vector from the player to the current target
777 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
778 vm_vec_normalize(&orient_vec);
780 factor = target_objp->radius*4.0f;
782 // use the player's up vector, and construct the viewers orientation matrix
783 up_vector = Player_obj->orient.v.uvec;
784 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
786 // normalize the vector from the player to the current target, and scale by a factor to calculate
787 // the objects position
788 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
790 hud_render_target_setup(&camera_eye, &camera_orient, 0.5f);
791 jumpnode_render( target_objp, &obj_pos );
792 hud_render_target_close();
796 hud_blit_target_foreground();
797 hud_blit_target_integrity(1);
798 // hud_set_default_color();
799 hud_set_gauge_color(HUD_TARGET_MONITOR);
801 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, Jump_nodes[target_objp->instance].name);
803 dist = vm_vec_dist_quick(&target_objp->pos, &Player_obj->pos);
805 // account for hud shaking
806 hx = fl2i(HUD_offset_x);
807 hy = fl2i(HUD_offset_y);
809 SDL_snprintf(outstr, sizeof(outstr), XSTR( "d: %.0f", 340), dist);
810 hud_num_make_mono(outstr);
811 gr_get_string_size(&w,&h,outstr);
813 emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_DIST][0]+hx, Targetbox_coords[gr_screen.res][TBOX_DIST][1]+hy, EG_TBOX_DIST, outstr);
816 // -------------------------------------------------------------------------------------
817 // hud_render_target_asteroid()
819 // Render a piece of asteroid on the target monitor
821 void hud_render_target_asteroid(object *target_objp)
823 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
824 vector obj_pos = ZERO_VECTOR;
825 vector camera_eye = ZERO_VECTOR;
826 matrix camera_orient = IDENTITY_MATRIX;
828 vector orient_vec, up_vector;
829 float time_to_impact, factor;
832 asteroidp = &Asteroids[target_objp->instance];
834 subtype = asteroidp->asteroid_subtype;
836 if ( Detail.targetview_model ) {
837 // take the forward orientation to be the vector from the player to the current target
838 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
839 vm_vec_normalize(&orient_vec);
841 factor = 2*target_objp->radius;
843 // use the player's up vector, and construct the viewers orientation matrix
844 up_vector = Player_obj->orient.v.uvec;
845 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
847 // normalize the vector from the player to the current target, and scale by a factor to calculate
848 // the objects position
849 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
851 hud_render_target_setup(&camera_eye, &camera_orient, 0.5f);
852 model_clear_instance(Asteroid_info[asteroidp->type].model_num[subtype]);
853 model_render(Asteroid_info[asteroidp->type].model_num[subtype], &target_objp->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL );
854 hud_render_target_close();
858 hud_blit_target_foreground();
859 hud_blit_target_integrity(1);
860 // hud_set_default_color();
861 hud_set_gauge_color(HUD_TARGET_MONITOR);
863 // hud print type of Asteroid (debris)
865 switch (asteroidp->type) {
866 case ASTEROID_TYPE_SMALL:
867 case ASTEROID_TYPE_MEDIUM:
868 case ASTEROID_TYPE_BIG:
869 SDL_strlcpy(hud_name, NOX("asteroid"), sizeof(hud_name));
873 case DEBRIS_TERRAN_SMALL:
874 case DEBRIS_TERRAN_MEDIUM:
875 case DEBRIS_TERRAN_LARGE:
876 SDL_strlcpy(hud_name, NOX("terran debris"), sizeof(hud_name));
879 case DEBRIS_VASUDAN_SMALL:
880 case DEBRIS_VASUDAN_MEDIUM:
881 case DEBRIS_VASUDAN_LARGE:
882 SDL_strlcpy(hud_name, NOX("vasudan debris"), sizeof(hud_name));
885 case DEBRIS_SHIVAN_SMALL:
886 case DEBRIS_SHIVAN_MEDIUM:
887 case DEBRIS_SHIVAN_LARGE:
888 SDL_strlcpy(hud_name, NOX("shivan debris"), sizeof(hud_name));
896 emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, hud_name);
898 time_to_impact = asteroid_time_to_impact(target_objp);
899 if ( time_to_impact >= 0 ) {
900 emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, NOX("impact: %.1f sec"), time_to_impact);
905 void get_turret_subsys_name(model_subsystem *system_info, char *outstr, const int max_outlen)
907 SDL_assert(system_info->type == SUBSYSTEM_TURRET);
909 if (system_info->turret_weapon_type >= 0) {
910 // check if beam or flak using weapon flags
911 if (Weapon_info[system_info->turret_weapon_type].wi_flags & WIF_FLAK) {
912 SDL_snprintf(outstr, max_outlen, "%s", XSTR("Flak turret", 1566));
913 } else if (Weapon_info[system_info->turret_weapon_type].wi_flags & WIF_BEAM) {
914 SDL_snprintf(outstr, max_outlen, "%s", XSTR("Beam turret", 1567));
917 if (Weapon_info[system_info->turret_weapon_type].subtype == WP_LASER) {
918 SDL_snprintf(outstr, max_outlen, "%s", XSTR("Laser turret", 1568));
919 } else if (Weapon_info[system_info->turret_weapon_type].subtype == WP_MISSILE) {
920 SDL_snprintf(outstr, max_outlen, "%s", XSTR("Missile lnchr", 1569));
924 SDL_snprintf(outstr, max_outlen, "%s", NOX("Turret"));
928 // This should not happen
929 SDL_snprintf(outstr, max_outlen, "%s", NOX("Unused"));
933 // -------------------------------------------------------------------------------------
934 // hud_render_target_ship_info()
936 // Render the data for a ship on the target monitor. Called by hud_render_target_ship().
938 void hud_render_target_ship_info(object *target_objp)
941 ship_info *target_sip;
943 int w,h,screen_integrity=1, base_index;
945 float ship_integrity, shield_strength;
947 SDL_assert(target_objp->type == OBJ_SHIP);
948 target_shipp = &Ships[target_objp->instance];
949 target_sip = &Ship_info[target_shipp->ship_info_index];
950 target_aip = &Ai_info[target_shipp->ai_index];
952 SDL_strlcpy( outstr, target_shipp->ship_name, sizeof(outstr) );
954 if ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) {
955 hud_set_iff_color(target_objp, 1);
957 // Print out ship name, with wing name if it exists
958 if ( hud_targetbox_maybe_flash(TBOX_FLASH_NAME) ) {
959 hud_set_iff_color(target_objp, 1);
961 hud_set_iff_color(target_objp);
965 // take ship "copies" into account before printing ship class name.
966 base_index = target_shipp->ship_info_index;
967 if ( target_sip->flags & SIF_SHIP_COPY )
968 base_index = ship_info_base_lookup( target_shipp->ship_info_index );
970 // maybe do some translation
972 lcl_translate_targetbox_name(outstr, sizeof(outstr));
975 lcl_translate_targetbox_name_pl(outstr, sizeof(outstr));
977 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, outstr);
979 // print out ship class
980 char temp_name[NAME_LENGTH+2] = "";
982 // if this ship has an alternate type name
983 if(target_shipp->alt_type_index >= 0){
984 mission_parse_lookup_alt_index(target_shipp->alt_type_index, temp_name, sizeof(temp_name));
986 SDL_strlcpy(temp_name, Ship_info[base_index].name, sizeof(temp_name));
987 if ( strstr(Ship_info[base_index].name, NOX("#")) ) {
988 hud_end_string_at_first_hash_symbol(temp_name);
993 lcl_translate_targetbox_name(temp_name, sizeof(temp_name));
996 lcl_translate_targetbox_name_pl(temp_name, sizeof(temp_name));
998 emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, temp_name);
1000 ship_integrity = 1.0f;
1001 shield_strength = 1.0f;
1002 hud_get_target_strength(target_objp, &shield_strength, &ship_integrity);
1004 // convert to values of 0->100
1005 shield_strength *= 100.0f;
1006 ship_integrity *= 100.0f;
1008 screen_integrity = fl2i(ship_integrity+0.5f);
1009 if ( screen_integrity == 0 ) {
1010 if ( ship_integrity > 0 ) {
1011 screen_integrity = 1;
1014 // Print out right-justified integrity
1015 SDL_snprintf(outstr, sizeof(outstr), XSTR( "%d%%", 341), screen_integrity);
1016 gr_get_string_size(&w,&h,outstr);
1018 if ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) {
1019 // hud_set_bright_color();
1020 hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT);
1022 hud_targetbox_maybe_flash(TBOX_FLASH_HULL);
1025 emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_HULL][0]-w, Targetbox_coords[gr_screen.res][TBOX_HULL][1], EG_TBOX_HULL, "%s", outstr);
1026 hud_set_gauge_color(HUD_TARGET_MONITOR);
1028 // print out the targeted sub-system and % integrity
1029 if (Player_ai->targeted_subsys != NULL) {
1030 shield_strength = Player_ai->targeted_subsys->current_hits/Player_ai->targeted_subsys->system_info->max_hits *100.0f;
1031 screen_integrity = fl2i(shield_strength+0.5f);
1033 if ( screen_integrity < 0 ) {
1034 screen_integrity = 0;
1037 if ( screen_integrity == 0 ) {
1038 if ( shield_strength > 0 ) {
1039 screen_integrity = 1;
1043 if ( screen_integrity <= 0 ){
1044 hud_targetbox_start_flash(TBOX_FLASH_SUBSYS); // need to flash 0% continuously
1045 hud_targetbox_maybe_flash(TBOX_FLASH_SUBSYS);
1048 // PRINT SUBSYS NAME
1049 // hud_set_default_color();
1050 // get turret subsys name
1051 if (Player_ai->targeted_subsys->system_info->type == SUBSYSTEM_TURRET) {
1052 get_turret_subsys_name(Player_ai->targeted_subsys->system_info, outstr, sizeof(outstr));
1054 SDL_snprintf(outstr, sizeof(outstr), "%s", Player_ai->targeted_subsys->system_info->name);
1056 hud_targetbox_truncate_subsys_name(outstr, sizeof(outstr));
1057 gr_printf(Target_window_coords[gr_screen.res][0]+2, Target_window_coords[gr_screen.res][1]+Target_window_coords[gr_screen.res][3]-h, outstr);
1059 // AL 23-3-98: Fighter bays are a special case. Player cannot destroy them, so don't
1060 // show the subsystem strength
1061 if ( SDL_strncasecmp(NOX("fighter"), Player_ai->targeted_subsys->system_info->name, 7) ) {
1062 SDL_snprintf(outstr, sizeof(outstr), XSTR( "%d%%", 341),screen_integrity);
1063 gr_get_string_size(&w,&h,outstr);
1064 gr_printf(Target_window_coords[gr_screen.res][0]+Target_window_coords[gr_screen.res][2]-w-1, Target_window_coords[gr_screen.res][1]+Target_window_coords[gr_screen.res][3] - h, "%s", outstr);
1067 hud_set_gauge_color(HUD_TARGET_MONITOR);
1070 // print out 'disabled' on the monitor if the target is disabled
1071 if ( (target_shipp->flags & SF_DISABLED) || (ship_subsys_disrupted(target_shipp, SUBSYSTEM_ENGINE)) ) {
1072 if ( target_shipp->flags & SF_DISABLED ) {
1073 SDL_strlcpy(outstr, XSTR( "DISABLED", 342), sizeof(outstr));
1075 SDL_strlcpy(outstr, XSTR( "DISRUPTED", 343), sizeof(outstr));
1077 gr_get_string_size(&w,&h,outstr);
1078 gr_printf(Target_window_coords[gr_screen.res][0]+Target_window_coords[gr_screen.res][2]/2 - w/2 - 1, Target_window_coords[gr_screen.res][1]+Target_window_coords[gr_screen.res][3] - 2*h, "%s", outstr);
1081 hud_targetbox_show_extra_ship_info(target_shipp, target_aip);
1084 // call to draw the integrity bar that is on the right of the target monitor
1085 void hud_blit_target_integrity(int disabled,int force_obj_num)
1092 if ( Target_view_integrity_gauge.first_frame == -1 )
1096 GR_AABITMAP(Target_view_integrity_gauge.first_frame, Integrity_bar_coords[gr_screen.res][0], Integrity_bar_coords[gr_screen.res][1]);
1100 if(force_obj_num == -1){
1101 SDL_assert(Player_ai->target_objnum >= 0 );
1102 objp = &Objects[Player_ai->target_objnum];
1104 objp = &Objects[Player_ai->target_objnum];
1107 clip_h = fl2i( (1 - Pl_target_integrity) * Integrity_bar_coords[gr_screen.res][3] );
1109 // print out status of ship
1110 if ( (Ships[objp->instance].flags & SF_DISABLED) || (ship_subsys_disrupted(&Ships[objp->instance], SUBSYSTEM_ENGINE)) ) {
1111 SDL_strlcpy(buf,XSTR( "dis", 344), sizeof(buf));
1112 current_ts = TS_DIS;
1114 if ( Pl_target_integrity > 0.9 ) {
1115 SDL_strlcpy(buf, XSTR( "ok", 345), sizeof(buf));
1117 } else if ( Pl_target_integrity > 0.2 ) {
1118 SDL_strlcpy(buf, XSTR( "dmg", 346), sizeof(buf));
1119 current_ts = TS_DMG;
1121 SDL_strlcpy(buf, XSTR( "crt", 347), sizeof(buf));
1122 current_ts = TS_CRT;
1126 if ( Last_ts != -1 && current_ts != Last_ts ) {
1127 hud_targetbox_start_flash(TBOX_FLASH_STATUS);
1129 Last_ts = current_ts;
1131 hud_targetbox_maybe_flash(TBOX_FLASH_STATUS);
1133 emp_hud_string(Integrity_string_coords[gr_screen.res][0], Integrity_string_coords[gr_screen.res][1], EG_TBOX_INTEG, buf);
1135 hud_set_gauge_color(HUD_TARGET_MONITOR);
1137 bm_get_info(Target_view_integrity_gauge.first_frame,&w,&h);
1140 // draw the dark portion
1141 GR_AABITMAP_EX(Target_view_integrity_gauge.first_frame, Integrity_bar_coords[gr_screen.res][0], Integrity_bar_coords[gr_screen.res][1], w, clip_h,0,0);
1144 if ( clip_h <= Integrity_bar_coords[gr_screen.res][3] ) {
1145 // draw the bright portion
1146 GR_AABITMAP_EX(Target_view_integrity_gauge.first_frame+1, Integrity_bar_coords[gr_screen.res][0], Integrity_bar_coords[gr_screen.res][1]+clip_h,w,h-clip_h,0,clip_h);
1150 // determine if the subsystem is in line-of sight, without taking into accout whether the player ship is
1151 // facing the subsystem
1152 int hud_targetbox_subsystem_in_view(object *target_objp, int *sx, int *sy)
1154 ship_subsys *subsys;
1156 vertex subobj_vertex;
1160 subsys = Player_ai->targeted_subsys;
1161 if (subsys != NULL ) {
1162 vm_vec_unrotate(&subobj_pos, &subsys->system_info->pnt, &target_objp->orient);
1163 vm_vec_add2(&subobj_pos, &target_objp->pos);
1165 // is it subsystem in view
1166 if ( Player->subsys_in_view == -1 ) {
1167 rval = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos, 0);
1169 rval = Player->subsys_in_view;
1172 // get screen coords, adjusting for autocenter
1173 SDL_assert(target_objp->type == OBJ_SHIP);
1174 if (target_objp->type == OBJ_SHIP) {
1175 pm = model_get(Ships[target_objp->instance].modelnum);
1176 if (pm->flags & PM_FLAG_AUTOCEN) {
1178 vm_vec_copy_scale(&temp, &pm->autocenter, -1.0f);
1179 vm_vec_unrotate(&delta, &temp, &target_objp->orient);
1180 vm_vec_add2(&subobj_pos, &delta);
1184 g3_rotate_vertex(&subobj_vertex, &subobj_pos);
1185 g3_project_vertex(&subobj_vertex);
1186 *sx = (int) subobj_vertex.sx;
1187 *sy = (int) subobj_vertex.sy;
1193 void hud_update_cargo_scan_sound()
1195 if ( Player->cargo_inspect_time <= 0 ) {
1196 player_stop_cargo_scan_sound();
1199 player_maybe_start_cargo_scan_sound();
1203 // If the player is scanning for cargo, draw some cool scanning lines on the target monitor
1204 void hud_maybe_render_cargo_scan(ship_info *target_sip)
1207 int scan_time; // time required to scan ship
1209 if ( Player->cargo_inspect_time <= 0 ) {
1213 scan_time = target_sip->scan_time;
1214 // hud_set_default_color();
1215 hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT);
1217 // draw horizontal scan line
1218 x1 = Cargo_scan_coords[gr_screen.res][0];
1219 y1 = fl2i(0.5f + Cargo_scan_coords[gr_screen.res][1] + ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_coords[gr_screen.res][3] ));
1220 x2 = x1 + Cargo_scan_coords[gr_screen.res][2];
1222 gr_line(x1, y1, x2, y1);
1224 // draw vertical scan line
1225 x1 = fl2i(0.5f + Cargo_scan_coords[gr_screen.res][0] + ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_coords[gr_screen.res][2] ));
1226 y1 = Cargo_scan_coords[gr_screen.res][1];
1227 y2 = y1 + Cargo_scan_coords[gr_screen.res][3];
1229 gr_line(x1, y1-3, x1, y2-1);
1232 // Get the eye position for an object at the origin, called from hud_render_target_ship()
1233 // input: eye_pos => Global pos for eye (output parameter)
1234 // orient => Orientation of object at the origin
1235 void hud_targetbox_get_eye(vector *eye_pos, matrix *orient, int ship_num)
1240 vector origin = ZERO_VECTOR;
1242 shipp = &Ships[ship_num];
1243 pm = model_get( shipp->modelnum );
1245 // If there is no eye, don't do anything
1246 if ( pm->n_view_positions == 0 ) {
1250 ep = &(pm->view_positions[0] );
1252 model_find_world_point( eye_pos, &ep->pnt, shipp->modelnum, ep->parent, orient, &origin );
1255 // -------------------------------------------------------------------------------------
1256 // hud_render_target_ship()
1258 // Render a ship to the target monitor
1260 void hud_render_target_ship(object *target_objp)
1262 vector obj_pos = ZERO_VECTOR;
1263 vector camera_eye = ZERO_VECTOR;
1264 matrix camera_orient = IDENTITY_MATRIX;
1266 ship_info *target_sip;
1267 vector orient_vec, up_vector;
1272 target_shipp = &Ships[target_objp->instance];
1273 target_sip = &Ship_info[target_shipp->ship_info_index];
1275 if ( Detail.targetview_model ) {
1276 // take the forward orientation to be the vector from the player to the current target
1277 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
1278 vm_vec_normalize(&orient_vec);
1280 factor = -target_sip->closeup_pos.xyz.z;
1282 // use the player's up vector, and construct the viewers orientation matrix
1283 up_vector = Player_obj->orient.v.uvec;
1284 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
1286 // normalize the vector from the player to the current target, and scale by a factor to calculate
1287 // the objects position
1288 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
1290 // set camera eye to eye of ship relative to origin
1291 // hud_targetbox_get_eye(&camera_eye, &camera_orient, Player_obj->instance);
1293 hud_render_target_setup(&camera_eye, &camera_orient, target_sip->closeup_zoom);
1294 // model_clear_instance(target_sip->modelnum);
1295 ship_model_start( target_objp );
1297 // maybe render a special hud-target-only model
1298 if(target_sip->modelnum_hud >= 0){
1299 model_render( target_sip->modelnum_hud, &target_objp->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_AUTOCENTER);
1301 model_render( target_sip->modelnum, &target_objp->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_AUTOCENTER);
1303 ship_model_stop( target_objp );
1307 // check if subsystem target has changed
1308 if ( Player_ai->targeted_subsys == Player_ai->last_subsys_target ) {
1310 save_pos = target_objp->pos;
1311 target_objp->pos = obj_pos;
1312 subsys_in_view = hud_targetbox_subsystem_in_view(target_objp, &sx, &sy);
1313 target_objp->pos = save_pos;
1315 if ( subsys_in_view != -1 ) {
1317 // AL 29-3-98: If subsystem is destroyed, draw gray brackets
1318 if ( (Player_ai->targeted_subsys->current_hits <= 0) && (SDL_strncasecmp(NOX("fighter"), Player_ai->targeted_subsys->system_info->name, 7)) ) {
1319 gr_set_color_fast(&IFF_colors[IFF_COLOR_MESSAGE][1]);
1321 hud_set_iff_color( target_objp, 1 );
1324 if ( subsys_in_view ) {
1325 draw_brackets_square_quick(sx - 10, sy - 10, sx + 10, sy + 10);
1327 draw_brackets_diamond_quick(sx - 10, sy - 10, sx + 10, sy + 10);
1331 hud_render_target_close();
1334 hud_blit_target_foreground();
1335 hud_blit_target_integrity(0,OBJ_INDEX(target_objp));
1337 hud_render_target_ship_info(target_objp);
1338 hud_maybe_render_cargo_scan(target_sip);
1341 // -------------------------------------------------------------------------------------
1342 // hud_render_target_debris()
1344 // Render a piece of debris on the target monitor
1346 void hud_render_target_debris(object *target_objp)
1348 vector obj_pos = ZERO_VECTOR;
1349 vector camera_eye = ZERO_VECTOR;
1350 matrix camera_orient = IDENTITY_MATRIX;
1352 vector orient_vec, up_vector;
1356 debrisp = &Debris[target_objp->instance];
1359 if ( Detail.targetview_model ) {
1360 // take the forward orientation to be the vector from the player to the current target
1361 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
1362 vm_vec_normalize(&orient_vec);
1364 factor = 2*target_objp->radius;
1366 // use the player's up vector, and construct the viewers orientation matrix
1367 up_vector = Player_obj->orient.v.uvec;
1368 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
1370 // normalize the vector from the player to the current target, and scale by a factor to calculate
1371 // the objects position
1372 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
1374 hud_render_target_setup(&camera_eye, &camera_orient, 0.5f);
1375 model_clear_instance(debrisp->model_num);
1376 submodel_render( debrisp->model_num, debrisp->submodel_num, &target_objp->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL );
1377 hud_render_target_close();
1381 hud_blit_target_foreground();
1382 hud_blit_target_integrity(1);
1383 // hud_set_default_color();
1384 hud_set_gauge_color(HUD_TARGET_MONITOR);
1386 // take ship "copies" into account before printing out ship class information
1387 base_index = debrisp->ship_info_index;
1388 if ( Ship_info[base_index].flags & SIF_SHIP_COPY )
1389 base_index = ship_info_base_lookup( debrisp->ship_info_index );
1391 // print out ship class that debris came from
1392 char *printable_ship_class = Ship_info[base_index].name;
1393 if ( strstr(Ship_info[base_index].name, NOX("#")) ) {
1394 char temp_name[NAME_LENGTH];
1395 SDL_strlcpy(temp_name, Ship_info[base_index].name, sizeof(temp_name));
1396 hud_end_string_at_first_hash_symbol(temp_name);
1397 printable_ship_class = temp_name;
1400 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, printable_ship_class);
1401 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, XSTR( "debris", 348));
1404 // -------------------------------------------------------------------------------------
1405 // hud_render_target_weapon()
1407 // Render a missile or a missile view to the target monitor
1409 void hud_render_target_weapon(object *target_objp)
1411 vector obj_pos = ZERO_VECTOR;
1412 vector camera_eye = ZERO_VECTOR;
1413 matrix camera_orient = IDENTITY_MATRIX;
1414 vector orient_vec, up_vector;
1415 weapon_info *target_wip = NULL;
1417 object *viewer_obj, *viewed_obj;
1418 int is_homing, is_player_missile, missile_view, viewed_model_num, w, h;
1420 char outstr[100]; // temp buffer
1422 wp = &Weapons[target_objp->instance];
1423 target_wip = &Weapon_info[wp->weapon_info_index];
1426 if ( target_wip->wi_flags & WIF_HOMING && wp->homing_object != &obj_used_list )
1429 is_player_missile = FALSE;
1430 if ( target_objp->parent_sig == Player_obj->signature ) {
1431 is_player_missile = TRUE;
1434 if ( Detail.targetview_model ) {
1436 viewer_obj = Player_obj;
1437 viewed_obj = target_objp;
1438 missile_view = FALSE;
1439 viewed_model_num = target_wip->model_num;
1440 if ( is_homing && is_player_missile ) {
1441 viewer_obj = target_objp;
1442 viewed_obj = wp->homing_object;
1443 missile_view = TRUE;
1444 viewed_model_num = Ships[wp->homing_object->instance].modelnum;
1447 // take the forward orientation to be the vector from the player to the current target
1448 vm_vec_sub(&orient_vec, &viewed_obj->pos, &viewer_obj->pos);
1449 vm_vec_normalize(&orient_vec);
1451 if ( missile_view == FALSE )
1452 factor = 2*target_objp->radius;
1454 factor = vm_vec_dist_quick(&viewer_obj->pos, &viewed_obj->pos);
1456 // use the viewer's up vector, and construct the viewers orientation matrix
1457 up_vector = viewer_obj->orient.v.uvec;
1458 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
1460 // normalize the vector from the viewer to the viwed target, and scale by a factor to calculate
1461 // the objects position
1462 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
1464 hud_render_target_setup(&camera_eye, &camera_orient, View_zoom/3);
1465 model_clear_instance(viewed_model_num);
1466 model_render( viewed_model_num, &viewed_obj->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL );
1467 hud_render_target_close();
1471 if ( is_homing == TRUE ) {
1472 hud_blit_target_foreground();
1474 hud_blit_target_foreground();
1477 hud_blit_target_integrity(1);
1478 // hud_set_default_color();
1479 hud_set_gauge_color(HUD_TARGET_MONITOR);
1481 // print out the weapon class name
1482 SDL_snprintf( outstr, sizeof(outstr), "%s", target_wip->name );
1483 gr_get_string_size(&w,&h,outstr);
1485 // drop name past the # sign
1486 if ( strstr(outstr, NOX("#")) ) {
1487 hud_end_string_at_first_hash_symbol(outstr);
1489 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, outstr);
1491 // If a homing weapon, show time to impact
1495 dist = vm_vec_dist(&target_objp->pos, &wp->homing_object->pos);
1496 speed = vm_vec_mag(&target_objp->phys_info.vel);
1498 SDL_snprintf(outstr, sizeof(outstr), NOX("impact: %.1f sec"), dist/speed);
1500 SDL_strlcpy(outstr, XSTR( "unknown", 349), sizeof(outstr));
1503 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, outstr);
1507 // -------------------------------------------------------------------------------------
1508 // hud_render_target_model() will render the target in the small targetting box. The box
1509 // is then shaded to give a monochrome effect
1511 void hud_render_target_model()
1513 object *target_objp;
1515 if ( !hud_gauge_active(HUD_TARGET_MONITOR) )
1518 if ( Player_ai->target_objnum == -1)
1521 if ( Target_static_playing )
1524 target_objp = &Objects[Player_ai->target_objnum];
1526 // Draw the background frame
1527 hud_render_target_background();
1529 switch ( target_objp->type ) {
1531 hud_render_target_ship(target_objp);
1535 hud_render_target_debris(target_objp);
1539 hud_render_target_weapon(target_objp);
1543 hud_render_target_asteroid(target_objp);
1547 hud_render_target_jump_node(target_objp);
1551 // Error(LOCATION, "Trying to show object type %d on target monitor\n", target_objp->type);
1552 hud_cease_targeting();
1557 void hud_cargo_scan_update(object *targetp, float frametime)
1559 char outstr[256]; // temp buffer for sprintf'ing hud output
1562 // Account for HUD shaking
1563 hx = fl2i(HUD_offset_x);
1564 hy = fl2i(HUD_offset_y);
1566 // display cargo inspection status
1567 if ( targetp->type == OBJ_SHIP ) {
1568 if ( player_inspect_cargo(frametime, outstr, sizeof(outstr)) ) {
1569 if ( hud_gauge_active(HUD_TARGET_MONITOR) ) {
1570 if ( Player->cargo_inspect_time > 0 ) {
1571 hud_targetbox_start_flash(TBOX_FLASH_CARGO);
1574 // Print out what the cargo is
1575 if ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) {
1576 // hud_set_bright_color();
1577 hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT);
1579 hud_targetbox_maybe_flash(TBOX_FLASH_CARGO);
1582 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_CARGO][0]+hx, Targetbox_coords[gr_screen.res][TBOX_CARGO][1]+hy, EG_TBOX_CARGO, outstr);
1583 hud_set_gauge_color(HUD_TARGET_MONITOR);
1586 } // end if (is_ship)
1590 // -----------------------------------------------------------------------------------
1591 // hud_show_target_data() will display the data about the target in and
1592 // around the targetting window
1594 void hud_show_target_data(float frametime)
1596 char outstr[256]; // temp buffer for sprintf'ing hud output
1597 int w,h; // width and height of string about to print
1598 object *target_objp;
1602 hud_set_gauge_color(HUD_TARGET_MONITOR);
1604 target_objp = &Objects[Player_ai->target_objnum];
1606 switch( Objects[Player_ai->target_objnum].type ) {
1608 shipp = &Ships[target_objp->instance];
1625 Int3(); // can't happen
1631 // Account for HUD shaking
1632 hx = fl2i(HUD_offset_x);
1633 hy = fl2i(HUD_offset_y);
1635 // print out the target distance and speed
1636 SDL_snprintf(outstr, sizeof(outstr), XSTR( "d: %.0f%s", 350), Player_ai->current_target_distance, modifiers[Player_ai->current_target_dist_trend]);
1638 hud_num_make_mono(outstr);
1639 gr_get_string_size(&w,&h,outstr);
1641 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_DIST][0]+hx, Targetbox_coords[gr_screen.res][TBOX_DIST][1]+hy, EG_TBOX_DIST, outstr);
1645 spd = vm_vec_dist(&target_objp->pos, &target_objp->last_pos) / frametime;
1647 // 7/28/99 DKA: Do not use vec_mag_quick -- the error is too big
1648 spd = vm_vec_mag(&target_objp->phys_info.vel);
1649 // spd = target_objp->phys_info.fspeed;
1653 // if the speed is 0, determine if we are docked with something -- if so, get the velocity from
1654 // our docked object instead
1655 if ( (spd == 0.0f) && is_ship ) {
1659 aip = &Ai_info[shipp->ai_index];
1660 if ( aip->ai_flags & AIF_DOCKED ) {
1661 SDL_assert( aip->dock_objnum != -1 );
1662 other_objp = &Objects[aip->dock_objnum];
1663 spd = other_objp->phys_info.fspeed;
1669 SDL_snprintf(outstr, sizeof(outstr), XSTR( "s: %.0f%s", 351), spd, (spd>1)?modifiers[Player_ai->current_target_speed_trend]:"");
1670 hud_num_make_mono(outstr);
1672 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_SPEED][0]+hx, Targetbox_coords[gr_screen.res][TBOX_SPEED][1]+hy, EG_TBOX_SPEED, outstr);
1675 // output target info for debug purposes only, this will be removed later
1681 if ( Show_target_debug_info && (is_ship == 1) ) {
1684 dy = gr_get_font_height() + 1;
1687 gr_set_color_fast(&HUD_color_debug);
1689 if ( shipp->ai_index >= 0 ) {
1690 ai_info *aip = &Ai_info[shipp->ai_index];
1692 SDL_snprintf(outstr, sizeof(outstr), "AI: %s", Ai_behavior_names[aip->mode]);
1694 switch (aip->mode) {
1696 SDL_assert(aip->submode <= SM_BIG_PARALLEL); // Must be <= largest chase submode value.
1697 // sprintf(outstr,"AI: %s",Submode_text[aip->submode]);
1698 SDL_snprintf(outstr2,sizeof(outstr2)," / %s",Submode_text[aip->submode]);
1699 SDL_strlcat(outstr, outstr2, sizeof(outstr));
1702 SDL_assert(aip->submode <= AIS_STRAFE_POSITION); // Must be <= largest chase submode value.
1703 // sprintf(outstr,"AI: %s",Strafe_submode_text[aip->submode-AIS_STRAFE_ATTACK]);
1704 SDL_snprintf(outstr2,sizeof(outstr2)," / %s",Strafe_submode_text[aip->submode-AIS_STRAFE_ATTACK]);
1705 SDL_strlcat(outstr, outstr2, sizeof(outstr));
1708 // gr_printf(sx, sy, "Wpnum: %i",aip->wp_index);
1709 SDL_snprintf(outstr2,sizeof(outstr2)," / Wpnum: %i",aip->wp_index);
1710 SDL_strlcat(outstr, outstr2, sizeof(outstr));
1716 gr_printf(sx, sy, outstr);
1719 gr_printf(sx, sy, "Max speed = %d, (%d%%)", (int) shipp->current_max_speed, (int) (100.0f * vm_vec_mag(&target_objp->phys_info.vel)/shipp->current_max_speed));
1722 // data can be found in target montior
1723 // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+3, TARGET_WINDOW_Y1+5*h, "Shields: %d", (int) Players[Player_num].current_target->shields);
1724 if (aip->target_objnum != -1) {
1725 char target_str[32];
1729 if (aip->target_objnum == Player_obj-Objects)
1730 SDL_strlcpy(target_str, "Player!", sizeof(target_str));
1732 SDL_snprintf(target_str, sizeof(target_str), "%s", Ships[Objects[aip->target_objnum].instance].ship_name);
1734 // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+4*h, "Target: %s", target_str);
1735 gr_printf(sx, sy, "Targ: %s", target_str);
1738 dist = vm_vec_dist_quick(&Objects[Player_ai->target_objnum].pos, &Objects[aip->target_objnum].pos);
1739 vm_vec_normalized_dir(&v2t,&Objects[aip->target_objnum].pos, &Objects[Player_ai->target_objnum].pos);
1741 dot = vm_vec_dot(&v2t, &Objects[Player_ai->target_objnum].orient.v.fvec);
1743 // data can be found in target montior
1744 // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+3, TARGET_WINDOW_Y1+6*h, "Targ dist: %5.1f", dist);
1745 // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+5*h, "Targ dot: %3.2f", dot);
1746 gr_printf(sx, sy, "Targ dot: %3.2f", dot);
1748 // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+6*h, "Targ dst: %3.2f", dist);
1749 gr_printf(sx, sy, "Targ dst: %3.2f", dist);
1752 if ( aip->targeted_subsys != NULL ) {
1753 SDL_snprintf(outstr, sizeof(outstr), "Subsys: %s", aip->targeted_subsys->system_info->name);
1754 gr_printf(sx, sy, outstr);
1758 // print out energy transfer information on the ship
1761 SDL_snprintf(outstr,sizeof(outstr),"MAX G/E: %.0f/%.0f",shipp->weapon_energy,shipp->current_max_speed);
1762 gr_printf(sx, sy, outstr);
1765 SDL_snprintf(outstr,sizeof(outstr),"G/S/E: %.2f/%.2f/%.2f",Energy_levels[shipp->weapon_recharge_index],Energy_levels[shipp->shield_recharge_index],Energy_levels[shipp->engine_recharge_index]);
1766 gr_printf(sx, sy, outstr);
1769 // Show information about attacker.
1773 if (Enemy_attacker != NULL)
1774 if (Enemy_attacker->type == OBJ_SHIP) {
1780 eshipp = &Ships[Enemy_attacker->instance];
1781 eaip = &Ai_info[eshipp->ai_index];
1783 if (eaip->target_objnum == Player_obj-Objects) {
1785 dist = vm_vec_dist_quick(&Enemy_attacker->pos, &Player_obj->pos);
1786 vm_vec_normalized_dir(&v2t,&Objects[eaip->target_objnum].pos, &Enemy_attacker->pos);
1788 dot = vm_vec_dot(&v2t, &Enemy_attacker->orient.v.fvec);
1790 gr_printf(sx, sy, "#%i: %s", Enemy_attacker-Objects, Ships[Enemy_attacker->instance].ship_name);
1792 gr_printf(sx, sy, "Targ dist: %5.1f", dist);
1794 gr_printf(sx, sy, "Targ dot: %3.2f", dot);
1799 if (Player_ai->target_objnum == Enemy_attacker - Objects)
1805 Enemy_attacker = NULL;
1806 for (i=0; i<MAX_OBJECTS; i++)
1807 if (Objects[i].type == OBJ_SHIP) {
1810 if (i != Player_ai->target_objnum) {
1811 enemy = Ai_info[Ships[Objects[i].instance].ai_index].target_objnum;
1813 if (enemy == Player_obj-Objects) {
1814 Enemy_attacker = &Objects[i];
1824 gr_printf(sx, sy, "Targ size: %dx%d", Hud_target_w, Hud_target_h );
1827 polymodel *pm = model_get( shipp->modelnum );
1828 gr_printf(sx, sy, "POF:%s", pm->filename );
1831 gr_printf(sx, sy, "Mass: %.2f\n", pm->mass);
1835 // display the weapons for the target on the HUD. Include ammo counts.
1836 if ( Show_target_weapons && (is_ship == 1) ) {
1840 swp = &shipp->weapons;
1843 dy = gr_get_font_height();
1845 SDL_snprintf(outstr,sizeof(outstr),"Num primaries: %d", swp->num_primary_banks);
1846 gr_printf(sx,sy,outstr);
1848 for ( i = 0; i < swp->num_primary_banks; i++ ) {
1849 SDL_snprintf(outstr,sizeof(outstr),"%d. %s", i+1, Weapon_info[swp->primary_bank_weapons[i]].name);
1850 gr_printf(sx,sy,outstr);
1855 SDL_snprintf(outstr,sizeof(outstr),"Num secondaries: %d", swp->num_secondary_banks);
1856 gr_printf(sx,sy,outstr);
1858 for ( i = 0; i < swp->num_secondary_banks; i++ ) {
1859 SDL_snprintf(outstr,sizeof(outstr),"%d. %s", i+1, Weapon_info[swp->secondary_bank_weapons[i]].name);
1860 gr_printf(sx,sy,outstr);
1869 // called at the start of each level
1870 void hud_targetbox_static_init()
1872 Target_static_next = 0;;
1873 Target_static_playing = 0;
1876 // determine if we should draw static on top of the target box
1877 int hud_targetbox_static_maybe_blit(float frametime)
1881 // on lowest skill level, don't show static on target monitor
1882 if ( Game_skill_level == 0 )
1885 // if multiplayer observer, don't show static
1886 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
1890 sensors_str = ship_get_subsystem_strength( Player_ship, SUBSYSTEM_SENSORS );
1892 if ( ship_subsys_disrupted(Player_ship, SUBSYSTEM_SENSORS) ) {
1893 sensors_str = SENSOR_STR_TARGET_NO_EFFECTS-1;
1896 if ( sensors_str > SENSOR_STR_TARGET_NO_EFFECTS ) {
1897 Target_static_playing = 0;
1898 Target_static_next = 0;
1900 if ( Target_static_next == 0 )
1901 Target_static_next = 1;
1904 if ( timestamp_elapsed(Target_static_next) ) {
1905 Target_static_playing ^= 1;
1906 Target_static_next = timestamp_rand(50, 750);
1909 if ( Target_static_playing ) {
1910 // hud_set_default_color();
1911 hud_set_gauge_color(HUD_TARGET_MONITOR);
1912 hud_anim_render(&Target_static, frametime, 1);
1913 if ( Target_static_looping == -1 ) {
1914 Target_static_looping = snd_play_looping(&Snds[SND_STATIC]);
1917 if ( Target_static_looping != -1 ) {
1918 snd_stop(Target_static_looping);
1919 Target_static_looping = -1;
1923 return Target_static_playing;
1926 // start the targetbox item flashing for duration ms
1927 // input: index => TBOX_FLASH_ #define
1928 // duration => optional param (default value TBOX_FLASH_DURATION), how long to flash in ms
1929 void hud_targetbox_start_flash(int index, int duration)
1931 Targetbox_flash_timers[index][0] = timestamp(duration);
1934 // stop flashing a specific targetbox item
1935 void hud_targetbox_end_flash(int index)
1937 Targetbox_flash_timers[index][0] = 1;
1940 // determine if a given flashing index is bright or not
1941 int hud_targetbox_is_bright(int index)
1943 return (Targetbox_flash_flags & (1<<index));
1946 // determine if the flashing has expired
1947 int hud_targetbox_flash_expired(int index)
1949 if ( timestamp_elapsed(Targetbox_flash_timers[index][0]) ) {
1957 void hudtargetbox_page_in()
1959 bm_page_in_aabitmap( Target_view_gauge.first_frame, Target_view_gauge.num_frames);
1961 bm_page_in_aabitmap( Target_view_integrity_gauge.first_frame, Target_view_integrity_gauge.num_frames );
1963 bm_page_in_aabitmap( Target_view_extra.first_frame, Target_view_extra.num_frames );