]> icculus.org git repositories - taylor/freespace2.git/blob - src/hud/hudtargetbox.cpp
Freespace 1 support
[taylor/freespace2.git] / src / hud / hudtargetbox.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Hud/HUDtargetbox.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module for drawing the target monitor box on the HUD
16  *
17  * $Log$
18  * Revision 1.6  2003/05/25 02:30:42  taylor
19  * Freespace 1 support
20  *
21  * Revision 1.5  2002/06/18 08:58:53  relnev
22  * last few struct changes
23  *
24  * Revision 1.4  2002/06/17 06:33:09  relnev
25  * ryan's struct patch for gcc 2.95
26  *
27  * Revision 1.3  2002/06/09 04:41:21  relnev
28  * added copyright header
29  *
30  * Revision 1.2  2002/05/07 03:16:45  theoddone33
31  * The Great Newline Fix
32  *
33  * Revision 1.1.1.1  2002/05/03 03:28:09  root
34  * Initial import.
35  *
36  * 
37  * 31    11/02/99 3:22p Jefff
38  * translation of targetbox text
39  * 
40  * 30    10/29/99 10:41p Jefff
41  * more subsystem fixes
42  * 
43  * 29    10/28/99 11:17p Jefff
44  * used escape seqs for some special German chars
45  * 
46  * 28    10/28/99 2:02a Jefff
47  * revised the subsystem localization
48  * 
49  * 27    9/14/99 11:03p Jefff
50  * dont draw target names from # on (weapons case)
51  * 
52  * 26    9/04/99 5:17p Andsager
53  * Make event log record name of destroyed subsytem, and use this name for
54  * different types of turrets
55  * 
56  * 25    8/25/99 11:35a Andsager
57  * Move hud render ship subsystem target box for ships with Autocenter
58  * 
59  * 24    8/17/99 7:32p Jefff
60  * models use autocenter in target view
61  * 
62  * 23    8/01/99 12:39p Dave
63  * Added HUD contrast control key (for nebula).
64  * 
65  * 22    7/31/99 4:15p Dave
66  * Fixed supernova particle velocities. Handle OBJ_NONE in target
67  * monitoring view. Properly use objectives notify gauge colors.
68  * 
69  * 21    7/28/99 2:49p Andsager
70  * Make hud target speed use vm_vec_mag (not vm_vec_mag_quick)
71  * 
72  * 20    7/15/99 9:20a Andsager
73  * FS2_DEMO initial checkin
74  * 
75  * 19    7/02/99 10:56a Andsager
76  * Put in big ship - big ship attack mode.  Modify stealth sweep ai.
77  * 
78  * 18    6/29/99 3:16p Andsager
79  * Debug stuff.
80  * 
81  * 17    6/10/99 3:43p Dave
82  * Do a better job of syncing text colors to HUD gauges.
83  * 
84  * 16    6/09/99 2:55p Andsager
85  * Allow multiple asteroid subtypes (of large, medium, small) and follow
86  * family.
87  * 
88  * 15    6/07/99 4:20p Andsager
89  * Add HUD color for tagged object.  Apply to target and radar.
90  * 
91  * 14    6/03/99 11:43a Dave
92  * Added the ability to use a different model when rendering to the HUD
93  * target box.
94  * 
95  * 13    5/24/99 9:02a Andsager
96  * Remove Int3() in turret subsys name code when turret has no weapon.
97  * 
98  * 12    5/21/99 1:42p Andsager
99  * Added error checking for HUD turret name
100  * 
101  * 11    5/20/99 7:00p Dave
102  * Added alternate type names for ships. Changed swarm missile table
103  * entries.
104  * 
105  * 10    5/19/99 3:50p Andsager
106  * Show type of debris is debris field (species debris or asteroid).  Show
107  * type of subsystem turret targeted (laser, missile, flak, beam).
108  * 
109  * 9     5/14/99 4:22p Andsager
110  * Modify hud_render_target_ship to show damaged subsystems in their
111  * actual state.  Now also shows rotation of subsystems.
112  * 
113  * 8     4/16/99 5:54p Dave
114  * Support for on/off style "stream" weapons. Real early support for
115  * target-painting lasers.
116  * 
117  * 7     1/07/99 9:08a Jasen
118  * HUD coords
119  * 
120  * 6     12/28/98 3:17p Dave
121  * Support for multiple hud bitmap filenames for hi-res mode.
122  * 
123  * 5     12/21/98 5:03p Dave
124  * Modified all hud elements to be multi-resolution friendly.
125  * 
126  * 4     11/05/98 4:18p Dave
127  * First run nebula support. Beefed up localization a bit. Removed all
128  * conditional compiles for foreign versions. Modified mission file
129  * format.
130  * 
131  * 3     10/13/98 9:28a Dave
132  * Started neatening up freespace.h. Many variables renamed and
133  * reorganized. Added AlphaColors.[h,cpp]
134  * 
135  * 2     10/07/98 10:53a Dave
136  * Initial checkin.
137  * 
138  * 1     10/07/98 10:49a Dave
139  * 
140  * 108   8/28/98 3:28p Dave
141  * EMP effect done. AI effects may need some tweaking as required.
142  * 
143  * 107   8/25/98 1:48p Dave
144  * First rev of EMP effect. Player side stuff basically done. Next comes
145  * AI code.
146  * 
147  * 106   6/19/98 3:49p Lawrance
148  * localization tweaks
149  * 
150  * 105   6/17/98 11:04a Lawrance
151  * localize subsystem names that appear on the HUD
152  * 
153  * 104   6/09/98 5:18p Lawrance
154  * French/German localization
155  * 
156  * 103   6/09/98 10:31a Hoffoss
157  * Created index numbers for all xstr() references.  Any new xstr() stuff
158  * added from here on out should be added to the end if the list.  The
159  * current list count can be found in FreeSpace.cpp (search for
160  * XSTR_SIZE).
161  * 
162  * 102   6/01/98 11:43a John
163  * JAS & MK:  Classified all strings for localization.
164  * 
165  * 101   5/20/98 3:52p Allender
166  * fixed compiler warnings
167  * 
168  * 100   5/20/98 12:59p John
169  * Turned optimizations on for debug builds.   Also turning on automatic
170  * function inlining.  Turned off the unreachable code warning.
171  * 
172  * 99    5/15/98 8:36p Lawrance
173  * Add 'target ship that last sent transmission' target key
174  * 
175  * 98    5/14/98 11:26a Lawrance
176  * ensure fighter bays are drawn with correct bracket color
177  * 
178  * 97    5/08/98 5:32p Lawrance
179  * Allow cargo scanning even if target gauge is disabled
180  * 
181  * 96    5/04/98 10:51p Lawrance
182  * remove unused local 
183  * 
184  * 95    5/04/98 9:17p Lawrance
185  * Truncate ship class names at # char when displaying debris on target
186  * moniter
187  * 
188  * 94    5/04/98 6:12p Lawrance
189  * Write generic function hud_end_string_at_first_hash_symbol(), to use in
190  * various spots on the HUD
191  * 
192  * 93    4/15/98 12:55a Lawrance
193  * Show time to impact for bombs
194  * 
195  * 92    4/02/98 6:31p Lawrance
196  * remove asteroid references if DEMO defined
197  * 
198  * 91    3/31/98 5:18p John
199  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
200  * bunch of debug stuff out of player file.  Made model code be able to
201  * unload models and malloc out only however many models are needed.
202  *  
203  * 
204  * 90    3/30/98 1:08a Lawrance
205  * Implement "blast" icon.  Blink HUD icon when player ship is hit by a
206  * blast.
207  *
208  * $NoKeywords: $
209  */
210
211 #include "2d.h"
212 #include "3d.h"
213 #include "3dinternal.h"
214 #include "object.h"
215 #include "hud.h"
216 #include "hudtarget.h"
217 #include "hudbrackets.h"
218 #include "hudets.h"
219 #include "model.h"
220 #include "missionparse.h"
221 #include "debris.h"
222 #include "weapon.h"
223 #include "player.h"
224 #include "gamesnd.h"
225 #include "freespace.h"
226 #include "bmpman.h"
227 #include "timer.h"
228 #include "subsysdamage.h"
229 #include "hudtargetbox.h"
230 #include "font.h"
231 #include "asteroid.h"
232 #include "jumpnode.h"
233 #include "multi.h"
234 #include "emp.h"
235 #include "localize.h"
236
237 int Target_window_coords[GR_NUM_RESOLUTIONS][4] =
238 {
239         { // GR_640
240                 8, 362, 131, 112
241         },
242         { // GR_1024
243                 8, 629, 131, 112
244         }
245 };
246
247 object *Enemy_attacker = NULL;
248
249 static int Target_static_next;
250 static int Target_static_playing;
251 int Target_static_looping;
252
253 #ifndef NDEBUG
254 extern int Show_target_debug_info;
255 extern int Show_target_weapons;
256 #endif
257
258 // used to print out + or - after target distance and speed
259 char* modifiers[] = {
260 //XSTR:OFF
261 "+",
262 "-",
263 ""
264 //XSTR:ON
265 };
266
267 char Target_view_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
268         "targetview1",
269         "targetview1"
270 };
271 char Target_integ_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
272         "targetview2",
273         "targetview2"
274 };
275 char Target_extra_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
276         "targetview3",
277         "targetview3"
278 };
279
280 // animation frames for the target view monitor
281 // frames:      0       =>              background of target monitor
282 //                              1       =>              foreground of target monitor
283 hud_frames Target_view_gauge;
284 int Target_view_gauge_loaded = 0;
285
286 // animation frames for the extended target information
287 // frames:      0       =>              normal gague
288 hud_frames Target_view_extra;
289 int Target_view_extra_loaded = 0;
290
291 // animation frames for the target view monitor integrity bar
292 // frames:      0       =>              dark bar
293 //                              1       =>              bright bar
294 hud_frames Target_view_integrity_gauge;
295 int Target_view_integrity_gauge_loaded = 0;
296
297 #define NUM_TBOX_COORDS                 11      // keep up to date
298 #define TBOX_BACKGROUND                 0
299 #define TBOX_NAME                                       1
300 #define TBOX_CLASS                              2
301 #define TBOX_DIST                                       3
302 #define TBOX_SPEED                              4
303 #define TBOX_CARGO                              5
304 #define TBOX_HULL                                       6
305 #define TBOX_EXTRA                              7
306 #define TBOX_EXTRA_ORDERS               8
307 #define TBOX_EXTRA_TIME                 9
308 #define TBOX_EXTRA_DOCK                 10
309
310 int Targetbox_coords[GR_NUM_RESOLUTIONS][NUM_TBOX_COORDS][2] = 
311 {
312         { // GR_640
313                 {5,319},
314                 {13,316},
315                 {13,325},
316                 {13,337},
317                 {90,337},
318                 {13,349},
319                 {139,361},
320                 {5,283},
321                 {13,280},
322                 {13,290},
323                 {13,299}
324         }, 
325         { // GR_1024
326                 {5,590},
327                 {13,587},
328                 {13,597},
329                 {13,608},
330                 {90,608},
331                 {13,620},
332                 {139,632},
333                 {5,555},
334                 {13,552},
335                 {13,561},
336                 {13,570}
337         }
338 };
339
340 int Integrity_bar_coords[GR_NUM_RESOLUTIONS][4] = {
341         { // GR_640
342                 138, 371, 4, 88
343         },
344         { // GR_1024
345                 138, 642, 4, 88
346         }
347 };
348 int Integrity_string_coords[GR_NUM_RESOLUTIONS][2] = {
349         { // GR_640
350                 112, 372
351         },
352         { // GR_1024
353                 112, 643
354         }
355 };
356
357 // cargo scanning extents
358 int Cargo_scan_coords[GR_NUM_RESOLUTIONS][4] = {
359         { // GR_640
360                 7, 364, 130, 109
361         },
362         { // GR_1024
363                 7, 635, 130, 109
364         }
365 };
366
367 // first element is time flashing expires, second element is time of next flash
368 int Targetbox_flash_timers[NUM_TBOX_FLASH_TIMERS][2];
369 int Targetbox_flash_flags;
370
371 // flag to indicate whether to show the extra information about a target 
372 // The HUD_config controls whether this can be shown... but the player can still toggle it on/off
373 // during the game.
374 int Targetbox_show_extra_info = 1;
375
376 // Different target states.  This drives the text display right below the hull integrity on the targetbox.
377 #define TS_DIS          0
378 #define TS_OK           1
379 #define TS_DMG          2
380 #define TS_CRT          3
381
382 static int Last_ts;     // holds last target status.
383
384 void hud_blit_target_integrity(int disabled,int force_obj_num = -1);
385
386 // cut down long subsystem names to a more manageable length
387 char *hud_targetbox_truncate_subsys_name(char *outstr)
388 {       
389         if(Lcl_gr){
390                 if ( strstr(outstr, "communication") )  {
391                         strcpy(outstr, "Komm");
392                 } else if ( !stricmp(outstr, "weapons") ) {
393                         strcpy(outstr, "Waffen");
394                 } else if ( strstr(outstr, "engine") || strstr(outstr, "Engine")) {
395                         strcpy(outstr, "Antrieb");
396                 } else if ( !stricmp(outstr, "sensors") ) {
397                         strcpy(outstr, "Sensoren");
398                 } else if ( strstr(outstr, "navigat") ) {
399                         strcpy(outstr, "Nav");
400                 } else if ( strstr(outstr, "fighterbay") || strstr(outstr, "Fighterbay") ) {
401                         strcpy(outstr, "J\x84gerhangar");
402                 } else if ( strstr(outstr, "missile") ) {
403                         strcpy(outstr, "Raketenwerfer");
404                 } else if ( strstr(outstr, "laser") || strstr(outstr, "turret") ) {
405                         strcpy(outstr, "Gesch\x81tzturm");
406                 } else if ( strstr(outstr, "Command Tower") || strstr(outstr, "Bridge") ) {
407                         strcpy(outstr, "Br\x81""cke");
408                 } else if ( strstr(outstr, "Barracks") ) {
409                         strcpy(outstr, "Quartiere");
410                 } else if ( strstr(outstr, "Reactor") ) {
411                         strcpy(outstr, "Reaktor");
412                 } else if ( strstr(outstr, "RadarDish") ) {
413                         strcpy(outstr, "Radarantenne");
414                 } else if (!stricmp(outstr, "Gas Collector")) {
415                         strcpy(outstr, "Sammler");
416                 } 
417         } else if(Lcl_fr){      
418                 if ( strstr(outstr, "communication") )  {
419                         strcpy(outstr, "comm");
420                 } else if ( !stricmp(outstr, "weapons") ) {
421                         strcpy(outstr, "armes");
422                 } else if ( strstr(outstr, "engine") ) {
423                         strcpy(outstr, "moteur");
424                 } else if ( !stricmp(outstr, "sensors") ) {
425                         strcpy(outstr, "detecteurs");
426                 } else if ( strstr(outstr, "navi") ) {
427                         strcpy(outstr, "nav");
428                 } else if ( strstr(outstr, "missile") ) {
429                         strcpy(outstr, "lanceur de missiles");
430                 } else if ( strstr(outstr, "fighter") ) {
431                         strcpy(outstr, "baie de chasse");
432                 } else if ( strstr(outstr, "laser") || strstr(outstr, "turret") || strstr(outstr, "missile") ) {
433                         strcpy(outstr, "tourelle");
434                 } 
435         } else {        
436                 if (!strnicmp(outstr, XSTR( "communication", 333), 3))  {
437                         strcpy( outstr, XSTR( "comm", 334) );
438                 } else if (!strnicmp(outstr, XSTR( "navigation", 335), 3))      {
439                         strcpy( outstr, XSTR( "nav", 336) );
440                 } else if (!stricmp(outstr, "Gas Collector")) {
441                         strcpy(outstr, "Collector");
442                 }
443         }
444
445         return outstr;
446 }
447
448 // init a specific targetbox timer
449 void hud_targetbox_init_flash_timer(int index)
450 {
451         Targetbox_flash_timers[index][0] = 1;
452         Targetbox_flash_timers[index][1] = 1;
453         Targetbox_flash_flags &= ~(1<<index);
454 }
455
456 // init the timers used to flash different parts of the targetbox.  This needs to get called whenever
457 // the current target changes.
458 void hud_targetbox_init_flash()
459 {
460         hud_targetbox_init_flash_timer(TBOX_FLASH_NAME);
461         hud_targetbox_init_flash_timer(TBOX_FLASH_CARGO);
462         hud_targetbox_init_flash_timer(TBOX_FLASH_HULL);
463         hud_targetbox_init_flash_timer(TBOX_FLASH_STATUS);
464         hud_targetbox_init_flash_timer(TBOX_FLASH_SUBSYS);
465         hud_targetbox_init_flash_timer(TBOX_FLASH_DOCKED);
466
467         Last_ts = -1;
468 }
469
470 // set the color for flashing text
471 // input:       index   =>      item to flash
472 //                              flash_fast      =>      optional param (default value 0), flash twice as fast
473 // exit:        1 =>    set bright color
474 //                      0 =>    set default color
475 int hud_targetbox_maybe_flash(int index, int flash_fast)
476 {
477         int draw_bright=0;
478
479         // hud_set_default_color();
480         hud_set_gauge_color(HUD_TARGET_MONITOR);
481         if ( !timestamp_elapsed(Targetbox_flash_timers[index][0]) ) {
482                 if ( timestamp_elapsed(Targetbox_flash_timers[index][1]) ) {
483                         if ( flash_fast ) {
484                                 Targetbox_flash_timers[index][1] = timestamp(fl2i(TBOX_FLASH_INTERVAL/2.0f));
485                         } else {
486                                 Targetbox_flash_timers[index][1] = timestamp(TBOX_FLASH_INTERVAL);
487                         }
488                         Targetbox_flash_flags ^= (1<<index);    // toggle between default and bright frames
489                 }
490
491                 if ( Targetbox_flash_flags & (1<<index) ) {
492                         // hud_set_bright_color();
493                         hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT);
494                         draw_bright=1;
495                 } else {                        
496                         // hud_set_dim_color();
497                         hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_DIM);
498                 }
499         }
500
501         return draw_bright;
502 }
503
504 // init all targetbox flash timers
505 void hud_targetbox_init_all_timers()
506 {
507         int i;
508         for ( i = 0; i < NUM_TBOX_FLASH_TIMERS; i++ ) {
509                 hud_targetbox_init_flash_timer(i);
510         }
511
512         Last_ts = -1;
513 }
514
515 // Initialize the data needed for the target view.  This is called from HUD_init() once per mission
516 void hud_targetbox_init()
517 {
518         if (!Target_view_gauge_loaded) {
519                 Target_view_gauge.first_frame = bm_load_animation(Target_view_fname[gr_screen.res], &Target_view_gauge.num_frames);
520                 if ( Target_view_gauge.first_frame < 0 ) {
521                         Warning(LOCATION,"Cannot load hud ani: %s\n", Target_view_fname[gr_screen.res]);
522                 }
523                 Target_view_gauge_loaded = 1;
524         }
525
526         if (!Target_view_integrity_gauge_loaded) {
527                 Target_view_integrity_gauge.first_frame = bm_load_animation(Target_integ_fname[gr_screen.res], &Target_view_integrity_gauge.num_frames);
528                 if ( Target_view_integrity_gauge.first_frame < 0 ) {
529                         Warning(LOCATION,"Cannot load hud ani: %s\n", Target_integ_fname[gr_screen.res]);
530                 }
531                 Target_view_integrity_gauge_loaded = 1;
532         }
533
534         if (!Target_view_extra_loaded) {
535                 Target_view_extra.first_frame = bm_load_animation(Target_extra_fname[gr_screen.res], &Target_view_extra.num_frames);
536                 if ( Target_view_extra.first_frame < 0 ) {
537                         Warning(LOCATION,"Cannot load hud ani: %s\n", Target_extra_fname[gr_screen.res]);
538                 }
539                 Target_view_extra_loaded = 1;
540         }
541
542         hud_targetbox_init_all_timers();
543 }
544
545 // -------------------------------------------------------------------------------------
546 // hud_save_restore_camera_data()
547 //
548 //      Called to save and restore the 3D camera settings.
549 //
550 void hud_save_restore_camera_data(int save)
551 {
552         static vector   save_view_position;
553         static float    save_view_zoom;
554         static matrix   save_view_matrix;
555         static matrix   save_eye_matrix;
556         static vector   save_eye_position;
557
558         // save global view variables, so we can restore them
559         if ( save ) {
560                 save_view_position      = View_position;
561                 save_view_zoom                  = View_zoom;
562                 save_view_matrix                = View_matrix;
563                 save_eye_matrix         = Eye_matrix;
564                 save_eye_position               = Eye_position;
565         }
566         else {
567                 // restore global view variables
568                 View_position   = save_view_position;
569                 View_zoom               = save_view_zoom;
570                 View_matrix             = save_view_matrix;
571                 Eye_matrix              = save_eye_matrix;
572                 Eye_position    = save_eye_position;
573         }
574 }
575
576 // -------------------------------------------------------------------------------------
577 // hud_render_target_background()
578 //
579 // Common set up for drawing the background of the target monitor, for ships/debris/missiles
580 //
581 void hud_render_target_background()
582 {
583         // blit the background frame
584         hud_set_gauge_color(HUD_TARGET_MONITOR);
585
586         GR_AABITMAP(Target_view_gauge.first_frame, Targetbox_coords[gr_screen.res][TBOX_BACKGROUND][0],Targetbox_coords[gr_screen.res][TBOX_BACKGROUND][1]);
587
588         // blit the extra targeting info frame
589         hud_set_gauge_color(HUD_TARGET_MONITOR_EXTRA_DATA);
590 }
591
592
593 // -------------------------------------------------------------------------------------
594 // hud_render_target_setup()
595 //
596 // Common set up for the 3d code for drawing the target monitor, for ships/debris/missiles
597 //
598 void hud_render_target_setup(vector *camera_eye, matrix *camera_orient, float zoom)
599 {
600         // JAS: g3_start_frame uses clip_width and clip_height to determine the
601         // size to render to.  Normally, you would set this by using gr_set_clip,
602         // but because of the hacked in hud jittering, I couldn't.  So come talk
603         // to me before modifying or reusing the following code. Thanks.
604         
605         gr_screen.clip_width = Target_window_coords[gr_screen.res][2];
606         gr_screen.clip_height = Target_window_coords[gr_screen.res][3];
607         g3_start_frame(1);              // Turn on zbuffering
608         hud_save_restore_camera_data(1);
609         g3_set_view_matrix( camera_eye, camera_orient, zoom);   
610         model_set_detail_level(1);              // use medium detail level
611
612         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]);
613
614 }
615
616 // -------------------------------------------------------------------------------------
617 // hud_render_target_close()
618 //
619 // Common clean-up after drawing the target monitor, for ships/debris/missiles
620 //
621 void hud_render_target_close()
622 {
623         g3_end_frame();
624         hud_save_restore_camera_data(0);
625 }
626
627 // -------------------------------------------------------------------------------------
628 // hud_blit_target_foreground()
629 //
630 void hud_blit_target_foreground()
631 {
632         hud_set_gauge_color(HUD_TARGET_MONITOR);
633
634         GR_AABITMAP(Target_view_gauge.first_frame+1, Targetbox_coords[gr_screen.res][TBOX_BACKGROUND][0],Targetbox_coords[gr_screen.res][TBOX_BACKGROUND][1]);  
635 }
636
637 // -------------------------------------------------------------------------------------
638 // hud_get_target_strength()
639 //
640 // Get the shield and hull percentages for a given ship object
641 //
642 // input:       *objp           =>              pointer to ship object that you want strength values for
643 //                              shields =>              OUTPUT parameter:       percentage value of shields (0->1.0)
644 //                              integrity =>    OUTPUT parameter: percentage value of integrity (0->1.0)
645 //
646 void hud_get_target_strength(object *objp, float *shields, float *integrity)
647 {
648         ship_info       *sip;
649         
650         if ( objp->type != OBJ_SHIP ) {
651                 Int3();
652                 return;
653         }
654
655         sip = &Ship_info[Ships[objp->instance].ship_info_index];
656
657         if (!( sip->shields == 0.0f )){
658                 *shields = get_shield_strength(objp) / sip->shields;
659         } else {
660                 *shields = 0.0f;
661         }
662
663         if (*shields < 0.0f){
664                 *shields = 0.0f;
665         }
666
667         if ( sip->initial_hull_strength == 0 ) {
668                 Int3(); // illegal initial hull strength
669                 *integrity = 0.0f;
670                 return;
671         }
672
673         *integrity = objp->hull_strength / sip->initial_hull_strength;
674         if (*integrity < 0)
675                 *integrity = 0.0f;
676 }
677
678 // maybe draw the extra targeted ship information above the target monitor
679 void hud_targetbox_show_extra_ship_info(ship *target_shipp, ai_info *target_aip)
680 {
681         char outstr[256], tmpbuf[256];
682         int has_orders = 0;
683         int not_training;
684         int extra_data_shown=0;
685
686         hud_set_gauge_color(HUD_TARGET_MONITOR_EXTRA_DATA);
687
688         not_training = !(The_mission.game_type & MISSION_TYPE_TRAINING);
689         if ( not_training && (hud_gauge_active(HUD_TARGET_MONITOR_EXTRA_DATA)) && (Targetbox_show_extra_info) ) {
690                 // Print out current orders if the targeted ship is friendly
691                 // AL 12-26-97: only show orders and time to target for friendly ships
692                 if ( (Player_ship->team == target_shipp->team) && !(ship_get_SIF(target_shipp) & SIF_NOT_FLYABLE) ) {
693                         extra_data_shown=1;
694                         if ( ship_return_orders(outstr, target_shipp) ) {
695                                 gr_force_fit_string(outstr, 255, 162);
696                                 has_orders = 1;
697                         } else {
698                                 strcpy(outstr, XSTR( "no orders", 337));
699                         }
700                         
701                         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);                   
702                 }
703
704                 if ( has_orders ) {
705                         sprintf(outstr, XSTR( "time to: ", 338));
706                         if ( ship_return_time_to_goal(tmpbuf, target_shipp) ) {
707                                 strcat(outstr, tmpbuf);
708                                 
709                                 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);                               
710                         }
711                 }
712         }
713
714         // Print out dock status
715         if ( target_aip->ai_flags & AIF_DOCKED ) {
716                 if ( target_aip->dock_objnum >= 0 ) {
717                         sprintf(outstr, XSTR( "Docked: %s", 339), Ships[Objects[target_aip->dock_objnum].instance].ship_name);
718                         gr_force_fit_string(outstr, 255, 173);
719                         hud_targetbox_maybe_flash(TBOX_FLASH_DOCKED);
720                         
721                         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);                       
722                         extra_data_shown=1;
723                 }
724         }
725
726         if ( extra_data_shown ) {
727                 // hud_set_default_color();             
728
729                 GR_AABITMAP(Target_view_extra.first_frame, Targetbox_coords[gr_screen.res][TBOX_EXTRA][0],Targetbox_coords[gr_screen.res][TBOX_EXTRA][1]);              
730         }
731 }
732
733 // Render a jump node on the target monitor
734 void hud_render_target_jump_node(object *target_objp)
735 {
736         char                    outstr[256];
737         vector          obj_pos = {0.0f,0.0f,0.0f};
738         vector          camera_eye = {0.0f,0.0f,0.0f};
739         matrix          camera_orient = IDENTITY_MATRIX;
740         vector          orient_vec, up_vector;
741         float                   factor, dist;
742         int                     hx, hy, w, h;
743
744         if ( Detail.targetview_model )  {
745                 // take the forward orientation to be the vector from the player to the current target
746                 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
747                 vm_vec_normalize(&orient_vec);
748
749                 factor = target_objp->radius*4.0f;
750
751                 // use the player's up vector, and construct the viewers orientation matrix
752                 up_vector = Player_obj->orient.v.uvec;
753                 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
754
755                 // normalize the vector from the player to the current target, and scale by a factor to calculate
756                 // the objects position
757                 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
758
759                 hud_render_target_setup(&camera_eye, &camera_orient, 0.5f);
760                 jumpnode_render( target_objp, &obj_pos );
761                 hud_render_target_close();
762         }
763         
764         HUD_reset_clip();
765         hud_blit_target_foreground();
766         hud_blit_target_integrity(1);
767         // hud_set_default_color();
768         hud_set_gauge_color(HUD_TARGET_MONITOR);
769
770         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);     
771
772         dist = vm_vec_dist_quick(&target_objp->pos, &Player_obj->pos);
773
774         // account for hud shaking
775         hx = fl2i(HUD_offset_x);
776         hy = fl2i(HUD_offset_y);
777
778         sprintf(outstr,XSTR( "d: %.0f", 340), dist);
779         hud_num_make_mono(outstr);
780         gr_get_string_size(&w,&h,outstr);
781         
782         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);       
783 }
784
785 // -------------------------------------------------------------------------------------
786 // hud_render_target_asteroid()
787 //
788 // Render a piece of asteroid on the target monitor
789 //
790 void hud_render_target_asteroid(object *target_objp)
791 {
792 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
793         vector          obj_pos = {0.0f,0.0f,0.0f};
794         vector          camera_eye = {0.0f,0.0f,0.0f};
795         matrix          camera_orient = IDENTITY_MATRIX;
796         asteroid                *asteroidp;
797         vector          orient_vec, up_vector;
798         int                     target_team;
799         float                   time_to_impact, factor; 
800         int                     subtype;
801
802         asteroidp = &Asteroids[target_objp->instance];
803
804         target_team = obj_team(target_objp);
805
806         subtype = asteroidp->asteroid_subtype;
807
808         if ( Detail.targetview_model )  {
809                 // take the forward orientation to be the vector from the player to the current target
810                 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
811                 vm_vec_normalize(&orient_vec);
812
813                 factor = 2*target_objp->radius;
814
815                 // use the player's up vector, and construct the viewers orientation matrix
816                 up_vector = Player_obj->orient.v.uvec;
817                 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
818
819                 // normalize the vector from the player to the current target, and scale by a factor to calculate
820                 // the objects position
821                 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
822
823                 hud_render_target_setup(&camera_eye, &camera_orient, 0.5f);
824                 model_clear_instance(Asteroid_info[asteroidp->type].model_num[subtype]);
825                 model_render(Asteroid_info[asteroidp->type].model_num[subtype], &target_objp->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL );
826                 hud_render_target_close();
827         }
828
829         HUD_reset_clip();
830         hud_blit_target_foreground();
831         hud_blit_target_integrity(1);
832         // hud_set_default_color();
833         hud_set_gauge_color(HUD_TARGET_MONITOR);
834
835         // hud print type of Asteroid (debris)
836         char hud_name[64];
837         switch (asteroidp->type) {
838         case ASTEROID_TYPE_SMALL:
839         case ASTEROID_TYPE_MEDIUM:
840         case ASTEROID_TYPE_BIG:
841                 strcpy(hud_name, NOX("asteroid"));
842                 break;
843
844 #ifndef MAKE_FS1
845         case DEBRIS_TERRAN_SMALL:
846         case DEBRIS_TERRAN_MEDIUM:
847         case DEBRIS_TERRAN_LARGE:
848                 strcpy(hud_name, NOX("terran debris"));
849                 break;
850
851         case DEBRIS_VASUDAN_SMALL:
852         case DEBRIS_VASUDAN_MEDIUM:
853         case DEBRIS_VASUDAN_LARGE:
854                 strcpy(hud_name, NOX("vasudan debris"));
855                 break;
856
857         case DEBRIS_SHIVAN_SMALL:
858         case DEBRIS_SHIVAN_MEDIUM:
859         case DEBRIS_SHIVAN_LARGE:
860                 strcpy(hud_name, NOX("shivan debris"));
861                 break;
862 #endif
863
864         default:
865                 Int3();
866         }
867
868         emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, hud_name);   
869         
870         time_to_impact = asteroid_time_to_impact(target_objp);
871         if ( time_to_impact >= 0 ) {
872                 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); 
873         }
874 #endif
875 }
876
877 void get_turret_subsys_name(model_subsystem *system_info, char *outstr)
878 {
879         Assert(system_info->type == SUBSYSTEM_TURRET);
880
881         if (system_info->turret_weapon_type >= 0) {
882                 // check if beam or flak using weapon flags
883                 if (Weapon_info[system_info->turret_weapon_type].wi_flags & WIF_FLAK) {
884                         sprintf(outstr, "%s", XSTR("Flak turret", 1566));
885                 } else if (Weapon_info[system_info->turret_weapon_type].wi_flags & WIF_BEAM) {
886                         sprintf(outstr, "%s", XSTR("Beam turret", 1567));
887                 } else {
888
889                         if (Weapon_info[system_info->turret_weapon_type].subtype == WP_LASER) {
890                                 sprintf(outstr, "%s", XSTR("Laser turret", 1568));
891                         } else if (Weapon_info[system_info->turret_weapon_type].subtype == WP_MISSILE) {
892                                 sprintf(outstr, "%s", XSTR("Missile lnchr", 1569));
893                         } else {
894                                 // Illegal subtype
895                                 Int3();
896                                 sprintf(outstr, "%s", NOX("Turret"));
897                         }
898                 }
899         } else {
900                 // This should not happen
901                 sprintf(outstr, "%s", NOX("Unused"));
902         }
903 }
904
905 // -------------------------------------------------------------------------------------
906 // hud_render_target_ship_info()
907 //
908 // Render the data for a ship on the target monitor.  Called by hud_render_target_ship().
909 //
910 void hud_render_target_ship_info(object *target_objp)
911 {
912         ship                    *target_shipp;
913         ship_info       *target_sip;
914         ai_info         *target_aip;
915         int                     w,h,screen_integrity=1, base_index;
916         char                    outstr[256];
917         float                   ship_integrity, shield_strength;
918
919         Assert(target_objp->type == OBJ_SHIP);
920         target_shipp = &Ships[target_objp->instance];
921         target_sip = &Ship_info[target_shipp->ship_info_index];
922         target_aip = &Ai_info[target_shipp->ai_index];
923
924         strcpy( outstr, target_shipp->ship_name );
925
926         if ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) {
927                 hud_set_iff_color(target_objp, 1);
928         } else {
929                 // Print out ship name, with wing name if it exists
930                 if ( hud_targetbox_maybe_flash(TBOX_FLASH_NAME) ) {
931                         hud_set_iff_color(target_objp, 1);
932                 } else {
933                         hud_set_iff_color(target_objp);
934                 }
935         }
936
937         // take ship "copies" into account before printing ship class name.
938         base_index = target_shipp->ship_info_index;
939         if ( target_sip->flags & SIF_SHIP_COPY )
940                 base_index = ship_info_base_lookup( target_shipp->ship_info_index );
941
942         // maybe do some translation
943         if (Lcl_gr) {
944                 lcl_translate_targetbox_name(outstr);
945         }
946         emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, outstr);     
947
948         // print out ship class
949         char temp_name[NAME_LENGTH+2] = "";
950
951         // if this ship has an alternate type name
952         if(target_shipp->alt_type_index >= 0){
953                 mission_parse_lookup_alt_index(target_shipp->alt_type_index, temp_name);
954         } else {
955                 strcpy(temp_name, Ship_info[base_index].name);  
956                 if ( strstr(Ship_info[base_index].name, NOX("#")) ) {                   
957                         strcpy(temp_name, Ship_info[base_index].name);
958                         hud_end_string_at_first_hash_symbol(temp_name);                 
959                 }       
960         }
961
962         if (Lcl_gr) {
963                 lcl_translate_targetbox_name(temp_name);
964         }
965         emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, temp_name);
966
967         ship_integrity = 1.0f;
968         hud_get_target_strength(target_objp, &shield_strength, &ship_integrity);
969
970         // convert to values of 0->100
971         shield_strength *= 100.0f;
972         ship_integrity *= 100.0f;
973
974         screen_integrity = fl2i(ship_integrity+0.5f);
975         if ( screen_integrity == 0 ) {
976                 if ( ship_integrity > 0 ) {
977                         screen_integrity = 1;
978                 }
979         }
980         // Print out right-justified integrity
981         sprintf(outstr,XSTR( "%d%%", 341), screen_integrity);
982         gr_get_string_size(&w,&h,outstr);
983
984         if ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) {
985                 // hud_set_bright_color();
986                 hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT);
987         } else {
988                 hud_targetbox_maybe_flash(TBOX_FLASH_HULL);
989         }
990
991         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);     
992         hud_set_gauge_color(HUD_TARGET_MONITOR);
993
994         // print out the targeted sub-system and % integrity
995         if (Player_ai->targeted_subsys != NULL) {
996                 shield_strength = Player_ai->targeted_subsys->current_hits/Player_ai->targeted_subsys->system_info->max_hits *100.0f;
997                 screen_integrity = fl2i(shield_strength+0.5f);
998
999                 if ( screen_integrity < 0 ) {
1000                         screen_integrity = 0;
1001                 }
1002
1003                 if ( screen_integrity == 0 ) {
1004                         if ( shield_strength > 0 ) {
1005                                 screen_integrity = 1;
1006                         }
1007                 }
1008
1009                 if ( screen_integrity <= 0 ){
1010                         hud_targetbox_start_flash(TBOX_FLASH_SUBSYS);   // need to flash 0% continuously
1011                         hud_targetbox_maybe_flash(TBOX_FLASH_SUBSYS);
1012                 }
1013
1014                 // PRINT SUBSYS NAME
1015                 // hud_set_default_color();
1016                 // get turret subsys name
1017                 if (Player_ai->targeted_subsys->system_info->type == SUBSYSTEM_TURRET) {
1018                         get_turret_subsys_name(Player_ai->targeted_subsys->system_info, outstr);
1019                 } else {
1020                         sprintf(outstr, "%s", Player_ai->targeted_subsys->system_info->name);
1021                 }
1022                 hud_targetbox_truncate_subsys_name(outstr);
1023                 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);
1024
1025                 // AL 23-3-98: Fighter bays are a special case.  Player cannot destroy them, so don't
1026                 //                                      show the subsystem strength
1027                 if ( strnicmp(NOX("fighter"), Player_ai->targeted_subsys->system_info->name, 7) ) {
1028                         sprintf(outstr,XSTR( "%d%%", 341),screen_integrity);
1029                         gr_get_string_size(&w,&h,outstr);
1030                         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);
1031                 }
1032
1033                 hud_set_gauge_color(HUD_TARGET_MONITOR);
1034         }
1035
1036         // print out 'disabled' on the monitor if the target is disabled
1037         if ( (target_shipp->flags & SF_DISABLED) || (ship_subsys_disrupted(target_shipp, SUBSYSTEM_ENGINE)) ) {
1038                 if ( target_shipp->flags & SF_DISABLED ) {
1039                         sprintf(outstr, XSTR( "DISABLED", 342));
1040                 } else {
1041                         sprintf(outstr, XSTR( "DISRUPTED", 343));
1042                 }
1043                 gr_get_string_size(&w,&h,outstr);
1044                 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);
1045         }
1046
1047         hud_targetbox_show_extra_ship_info(target_shipp, target_aip);
1048 }
1049
1050 // call to draw the integrity bar that is on the right of the target monitor
1051 void hud_blit_target_integrity(int disabled,int force_obj_num)
1052 {
1053         object  *objp;
1054         int             clip_h,w,h;
1055         char            buf[16];
1056         int             current_ts;
1057
1058         if ( Target_view_integrity_gauge.first_frame == -1 ) 
1059                 return;
1060
1061         if ( disabled ) {
1062                 GR_AABITMAP(Target_view_integrity_gauge.first_frame, Integrity_bar_coords[gr_screen.res][0], Integrity_bar_coords[gr_screen.res][1]);
1063                 return;
1064         }
1065
1066         if(force_obj_num == -1){
1067                 Assert(Player_ai->target_objnum >= 0 );
1068                 objp = &Objects[Player_ai->target_objnum];
1069         } else {
1070                 objp = &Objects[Player_ai->target_objnum];
1071         }
1072
1073         clip_h = fl2i( (1 - Pl_target_integrity) * Integrity_bar_coords[gr_screen.res][3] );
1074
1075         // print out status of ship
1076         if ( (Ships[objp->instance].flags & SF_DISABLED) || (ship_subsys_disrupted(&Ships[objp->instance], SUBSYSTEM_ENGINE)) ) {
1077                 sprintf(buf,XSTR( "dis", 344));
1078                 current_ts = TS_DIS;
1079         } else {
1080                 if ( Pl_target_integrity > 0.9 ) {
1081                         sprintf(buf,XSTR( "ok", 345));
1082                         current_ts = TS_OK;
1083                 } else if ( Pl_target_integrity > 0.2 ) {
1084                         sprintf(buf,XSTR( "dmg", 346));
1085                         current_ts = TS_DMG;
1086                 } else {
1087                         sprintf(buf,XSTR( "crt", 347));
1088                         current_ts = TS_CRT;
1089                 }
1090         }
1091
1092         if ( Last_ts != -1 && current_ts != Last_ts ) {
1093                 hud_targetbox_start_flash(TBOX_FLASH_STATUS);
1094         }
1095         Last_ts = current_ts;
1096
1097         hud_targetbox_maybe_flash(TBOX_FLASH_STATUS);
1098         
1099         emp_hud_string(Integrity_string_coords[gr_screen.res][0], Integrity_string_coords[gr_screen.res][1], EG_TBOX_INTEG, buf);       
1100
1101         hud_set_gauge_color(HUD_TARGET_MONITOR);
1102
1103         bm_get_info(Target_view_integrity_gauge.first_frame,&w,&h);
1104         
1105         if ( clip_h > 0 ) {
1106                 // draw the dark portion
1107                 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);         
1108         }
1109
1110         if ( clip_h <= Integrity_bar_coords[gr_screen.res][3] ) {
1111                 // draw the bright portion
1112                 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);           
1113         }
1114 }
1115
1116 // determine if the subsystem is in line-of sight, without taking into accout whether the player ship is
1117 // facing the subsystem
1118 int hud_targetbox_subsystem_in_view(object *target_objp, int *sx, int *sy)
1119 {
1120         ship_subsys     *subsys;
1121         vector          subobj_pos;
1122         vertex          subobj_vertex;
1123         int                     rval = -1;
1124         polymodel       *pm;
1125
1126         subsys = Player_ai->targeted_subsys;
1127         if (subsys != NULL ) {
1128                 vm_vec_unrotate(&subobj_pos, &subsys->system_info->pnt, &target_objp->orient);
1129                 vm_vec_add2(&subobj_pos, &target_objp->pos);
1130
1131                 // is it subsystem in view
1132                 if ( Player->subsys_in_view == -1 ) {
1133                         rval = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos, 0);
1134                 } else {
1135                         rval =  Player->subsys_in_view;
1136                 }
1137
1138                 // get screen coords, adjusting for autocenter
1139                 Assert(target_objp->type == OBJ_SHIP);
1140                 if (target_objp->type == OBJ_SHIP) {
1141                         pm = model_get(Ships[target_objp->instance].modelnum);
1142                         if (pm->flags & PM_FLAG_AUTOCEN) {
1143                                 vector temp, delta;
1144                                 vm_vec_copy_scale(&temp, &pm->autocenter, -1.0f);
1145                                 vm_vec_unrotate(&delta, &temp, &target_objp->orient);
1146                                 vm_vec_add2(&subobj_pos, &delta);
1147                         }
1148                 }
1149
1150                 g3_rotate_vertex(&subobj_vertex, &subobj_pos);
1151                 g3_project_vertex(&subobj_vertex);
1152                 *sx = (int) subobj_vertex.sx;
1153                 *sy = (int) subobj_vertex.sy;
1154         }
1155
1156         return rval;
1157 }
1158
1159 void hud_update_cargo_scan_sound()
1160 {
1161         if ( Player->cargo_inspect_time <= 0  ) {
1162                 player_stop_cargo_scan_sound();
1163                 return;
1164         }
1165         player_maybe_start_cargo_scan_sound();
1166
1167 }
1168
1169 // If the player is scanning for cargo, draw some cool scanning lines on the target monitor
1170 void hud_maybe_render_cargo_scan(ship_info *target_sip)
1171 {
1172         int x1, y1, x2, y2;
1173         int scan_time;                          // time required to scan ship
1174
1175         if ( Player->cargo_inspect_time <= 0  ) {
1176                 return;
1177         }
1178
1179         scan_time = target_sip->scan_time;
1180         // hud_set_default_color();
1181         hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT);
1182
1183         // draw horizontal scan line
1184         x1 = Cargo_scan_coords[gr_screen.res][0];
1185         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] ));
1186         x2 = x1 + Cargo_scan_coords[gr_screen.res][2];
1187
1188         gr_line(x1, y1, x2, y1);
1189
1190         // draw vertical scan line
1191         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] ));
1192         y1 = Cargo_scan_coords[gr_screen.res][1];
1193         y2 = y1 + Cargo_scan_coords[gr_screen.res][3];
1194
1195         gr_line(x1, y1-3, x1, y2-1);
1196 }
1197
1198 // Get the eye position for an object at the origin, called from hud_render_target_ship()
1199 // input:       eye_pos         =>      Global pos for eye (output parameter)
1200 //                      orient          =>      Orientation of object at the origin
1201 void hud_targetbox_get_eye(vector *eye_pos, matrix *orient, int ship_num)
1202 {
1203         ship            *shipp;
1204         polymodel       *pm;
1205         eye                     *ep;
1206         vector          origin = {0.0f, 0.0f, 0.0f};
1207
1208         shipp = &Ships[ship_num];
1209         pm = model_get( shipp->modelnum );
1210
1211         // If there is no eye, don't do anything
1212         if ( pm->n_view_positions == 0 ) {
1213                 return;
1214         }
1215
1216         ep = &(pm->view_positions[0] );
1217
1218         model_find_world_point( eye_pos, &ep->pnt, shipp->modelnum, ep->parent, orient, &origin );
1219 }
1220
1221 // -------------------------------------------------------------------------------------
1222 // hud_render_target_ship()
1223 //
1224 // Render a ship to the target monitor
1225 //
1226 void hud_render_target_ship(object *target_objp)
1227 {
1228         vector          obj_pos = {0.0f,0.0f,0.0f};
1229         vector          camera_eye = {0.0f,0.0f,0.0f};
1230         matrix          camera_orient = IDENTITY_MATRIX;
1231         ship            *target_shipp;
1232         ship_info       *target_sip;
1233         vector          orient_vec, up_vector;
1234         int                     sx, sy;
1235         int                     subsys_in_view;
1236         float           factor;
1237         
1238         target_shipp    = &Ships[target_objp->instance];
1239         target_sip              = &Ship_info[target_shipp->ship_info_index];
1240
1241         if ( Detail.targetview_model )  {
1242                 // take the forward orientation to be the vector from the player to the current target
1243                 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
1244                 vm_vec_normalize(&orient_vec);
1245
1246                 factor = -target_sip->closeup_pos.xyz.z;
1247
1248                 // use the player's up vector, and construct the viewers orientation matrix
1249                 up_vector = Player_obj->orient.v.uvec;
1250                 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
1251
1252                 // normalize the vector from the player to the current target, and scale by a factor to calculate
1253                 // the objects position
1254                 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
1255
1256                 // set camera eye to eye of ship relative to origin
1257         //      hud_targetbox_get_eye(&camera_eye, &camera_orient, Player_obj->instance);
1258
1259                 hud_render_target_setup(&camera_eye, &camera_orient, target_sip->closeup_zoom);
1260                 // model_clear_instance(target_sip->modelnum);
1261                 ship_model_start( target_objp );
1262
1263                 // maybe render a special hud-target-only model
1264                 if(target_sip->modelnum_hud >= 0){
1265                         model_render( target_sip->modelnum_hud, &target_objp->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_AUTOCENTER);
1266                 } else {
1267                         model_render( target_sip->modelnum, &target_objp->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_AUTOCENTER);
1268                 }
1269                 ship_model_stop( target_objp );
1270
1271                 sx = 0;
1272                 sy = 0;
1273                 // check if subsystem target has changed
1274                 if ( Player_ai->targeted_subsys == Player_ai->last_subsys_target ) {
1275                         vector save_pos;
1276                         save_pos = target_objp->pos;
1277                         target_objp->pos = obj_pos;
1278                         subsys_in_view = hud_targetbox_subsystem_in_view(target_objp, &sx, &sy);
1279                         target_objp->pos = save_pos;
1280
1281                         if ( subsys_in_view != -1 ) {
1282
1283                                 // AL 29-3-98: If subsystem is destroyed, draw gray brackets                                    
1284                                 if ( (Player_ai->targeted_subsys->current_hits <= 0) && (strnicmp(NOX("fighter"), Player_ai->targeted_subsys->system_info->name, 7)) ) {
1285                                         gr_set_color_fast(&IFF_colors[IFF_COLOR_MESSAGE][1]);
1286                                 } else {
1287                                         hud_set_iff_color( target_objp, 1 );
1288                                 }
1289
1290                                 if ( subsys_in_view ) {
1291                                         draw_brackets_square_quick(sx - 10, sy - 10, sx + 10, sy + 10);
1292                                 } else {
1293                                         draw_brackets_diamond_quick(sx - 10, sy - 10, sx + 10, sy + 10);
1294                                 }
1295                         }
1296                 }
1297                 hud_render_target_close();
1298         }
1299         HUD_reset_clip();
1300         hud_blit_target_foreground();
1301         hud_blit_target_integrity(0,OBJ_INDEX(target_objp));
1302
1303         hud_render_target_ship_info(target_objp);
1304         hud_maybe_render_cargo_scan(target_sip);
1305 }
1306
1307 // -------------------------------------------------------------------------------------
1308 // hud_render_target_debris()
1309 //
1310 // Render a piece of debris on the target monitor
1311 //
1312 void hud_render_target_debris(object *target_objp)
1313 {
1314         vector  obj_pos = {0.0f,0.0f,0.0f};
1315         vector  camera_eye = {0.0f,0.0f,0.0f};
1316         matrix  camera_orient = IDENTITY_MATRIX;
1317         debris  *debrisp;
1318         vector  orient_vec, up_vector;
1319         int             target_team, base_index;
1320         float           factor; 
1321
1322         debrisp = &Debris[target_objp->instance];
1323
1324         //target_sip = &Ship_info[debrisp->ship_info_index];
1325         target_team = obj_team(target_objp);
1326
1327
1328         if ( Detail.targetview_model )  {
1329                 // take the forward orientation to be the vector from the player to the current target
1330                 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
1331                 vm_vec_normalize(&orient_vec);
1332
1333                 factor = 2*target_objp->radius;
1334
1335                 // use the player's up vector, and construct the viewers orientation matrix
1336                 up_vector = Player_obj->orient.v.uvec;
1337                 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
1338
1339                 // normalize the vector from the player to the current target, and scale by a factor to calculate
1340                 // the objects position
1341                 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
1342
1343                 hud_render_target_setup(&camera_eye, &camera_orient, 0.5f);
1344                 model_clear_instance(debrisp->model_num);
1345                 submodel_render( debrisp->model_num, debrisp->submodel_num, &target_objp->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL );
1346                 hud_render_target_close();
1347         }
1348
1349         HUD_reset_clip();
1350         hud_blit_target_foreground();
1351         hud_blit_target_integrity(1);
1352         // hud_set_default_color();
1353         hud_set_gauge_color(HUD_TARGET_MONITOR);
1354
1355         // take ship "copies" into account before printing out ship class information
1356         base_index = debrisp->ship_info_index;
1357         if ( Ship_info[base_index].flags & SIF_SHIP_COPY )
1358                 base_index = ship_info_base_lookup( debrisp->ship_info_index );
1359
1360         // print out ship class that debris came from
1361         char *printable_ship_class = Ship_info[base_index].name;
1362         if ( strstr(Ship_info[base_index].name, NOX("#")) ) {
1363                 char temp_name[NAME_LENGTH];
1364                 strcpy(temp_name, Ship_info[base_index].name);
1365                 hud_end_string_at_first_hash_symbol(temp_name);
1366                 printable_ship_class = temp_name;
1367         }
1368
1369         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);    
1370         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));       
1371 }
1372
1373 // -------------------------------------------------------------------------------------
1374 // hud_render_target_weapon()
1375 //
1376 // Render a missile or a missile view to the target monitor
1377 //
1378 void hud_render_target_weapon(object *target_objp)
1379 {
1380         vector          obj_pos = {0.0f,0.0f,0.0f};
1381         vector          camera_eye = {0.0f,0.0f,0.0f};
1382         matrix          camera_orient = IDENTITY_MATRIX;
1383         vector          orient_vec, up_vector;
1384         weapon_info     *target_wip = NULL;
1385         weapon          *wp = NULL;
1386         object          *viewer_obj, *viewed_obj;
1387         int                     target_team, is_homing, is_player_missile, missile_view, viewed_model_num, w, h;
1388         float                   factor;
1389         char                    outstr[100];                            // temp buffer
1390
1391         target_team = obj_team(target_objp);
1392
1393         wp = &Weapons[target_objp->instance];
1394         target_wip = &Weapon_info[wp->weapon_info_index];
1395
1396         is_homing = FALSE;
1397         if ( target_wip->wi_flags & WIF_HOMING && wp->homing_object != &obj_used_list )
1398                 is_homing = TRUE;
1399
1400         is_player_missile = FALSE;
1401         if ( target_objp->parent_sig == Player_obj->signature ) {
1402                 is_player_missile = TRUE;
1403         }
1404
1405         if ( Detail.targetview_model )  {
1406
1407                 viewer_obj                      = Player_obj;
1408                 viewed_obj                      = target_objp;
1409                 missile_view            = FALSE;
1410                 viewed_model_num        = target_wip->model_num;
1411                 if ( is_homing && is_player_missile ) {
1412                         viewer_obj                      = target_objp;
1413                         viewed_obj                      = wp->homing_object;
1414                         missile_view            = TRUE;
1415                         viewed_model_num        = Ships[wp->homing_object->instance].modelnum;
1416                 }
1417
1418                 // take the forward orientation to be the vector from the player to the current target
1419                 vm_vec_sub(&orient_vec, &viewed_obj->pos, &viewer_obj->pos);
1420                 vm_vec_normalize(&orient_vec);
1421
1422                 if ( missile_view == FALSE )
1423                         factor = 2*target_objp->radius;
1424                 else
1425                         factor = vm_vec_dist_quick(&viewer_obj->pos, &viewed_obj->pos);
1426
1427                 // use the viewer's up vector, and construct the viewers orientation matrix
1428                 up_vector = viewer_obj->orient.v.uvec;
1429                 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
1430
1431                 // normalize the vector from the viewer to the viwed target, and scale by a factor to calculate
1432                 // the objects position
1433                 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
1434
1435                 hud_render_target_setup(&camera_eye, &camera_orient, View_zoom/3);
1436                 model_clear_instance(viewed_model_num);
1437                 model_render( viewed_model_num, &viewed_obj->orient, &obj_pos, MR_NO_LIGHTING | MR_LOCK_DETAIL );
1438                 hud_render_target_close();
1439         }
1440
1441         HUD_reset_clip();
1442         if ( is_homing == TRUE ) {
1443                 hud_blit_target_foreground();
1444         } else {
1445                 hud_blit_target_foreground();
1446         }
1447
1448         hud_blit_target_integrity(1);
1449         // hud_set_default_color();
1450         hud_set_gauge_color(HUD_TARGET_MONITOR);
1451
1452         // print out the weapon class name
1453         sprintf( outstr,"%s", target_wip->name );
1454         gr_get_string_size(&w,&h,outstr);
1455
1456         // drop name past the # sign
1457         if ( strstr(outstr, NOX("#")) ) {                       
1458                 hud_end_string_at_first_hash_symbol(outstr);                    
1459         }
1460         emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, outstr);     
1461
1462         // If a homing weapon, show time to impact
1463         if ( is_homing ) {
1464                 float dist, speed;
1465
1466                 dist = vm_vec_dist(&target_objp->pos, &wp->homing_object->pos);
1467                 speed = vm_vec_mag(&target_objp->phys_info.vel);
1468                 if ( speed > 0 ) {
1469                         sprintf(outstr, NOX("impact: %.1f sec"), dist/speed);
1470                 } else {
1471                         sprintf(outstr, XSTR( "unknown", 349));
1472                 }
1473
1474                 emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, outstr);          
1475         }
1476 }
1477
1478 // -------------------------------------------------------------------------------------
1479 // hud_render_target_model() will render the target in the small targetting box.  The box
1480 // is then shaded to give a monochrome effect
1481 //
1482 void hud_render_target_model()
1483 {
1484         object  *target_objp;
1485
1486         if ( !hud_gauge_active(HUD_TARGET_MONITOR) )
1487                 return;
1488
1489         if ( Player_ai->target_objnum == -1)
1490                 return;
1491
1492         if ( Target_static_playing ) 
1493                 return;
1494
1495         target_objp = &Objects[Player_ai->target_objnum];
1496
1497         // Draw the background frame
1498         hud_render_target_background();
1499
1500         switch ( target_objp->type ) {
1501                 case OBJ_SHIP:
1502                         hud_render_target_ship(target_objp);
1503                         break;
1504         
1505                 case OBJ_DEBRIS:
1506                         hud_render_target_debris(target_objp);
1507                         break;
1508
1509                 case OBJ_WEAPON:
1510                         hud_render_target_weapon(target_objp);
1511                         break;
1512
1513                 case OBJ_ASTEROID:
1514                         hud_render_target_asteroid(target_objp);
1515                         break;
1516
1517                 case OBJ_JUMP_NODE:
1518                         hud_render_target_jump_node(target_objp);
1519                         break;
1520
1521                 default:
1522                         // Error(LOCATION, "Trying to show object type %d on target monitor\n", target_objp->type);
1523                         hud_cease_targeting();
1524                         break;
1525         } // end switch
1526 }
1527
1528 void hud_cargo_scan_update(object *targetp, float frametime)
1529 {
1530         char outstr[256];                                               // temp buffer for sprintf'ing hud output
1531         int hx, hy;
1532
1533         // Account for HUD shaking
1534         hx = fl2i(HUD_offset_x);
1535         hy = fl2i(HUD_offset_y);
1536
1537         // display cargo inspection status
1538         if ( targetp->type == OBJ_SHIP ) {
1539                 if ( player_inspect_cargo(frametime, outstr) ) {
1540                         if ( hud_gauge_active(HUD_TARGET_MONITOR) ) {
1541                                 if ( Player->cargo_inspect_time > 0 ) {
1542                                         hud_targetbox_start_flash(TBOX_FLASH_CARGO);
1543                                 }
1544
1545                                 // Print out what the cargo is
1546                                 if ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) {
1547                                         // hud_set_bright_color();
1548                                         hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT);
1549                                 } else {
1550                                         hud_targetbox_maybe_flash(TBOX_FLASH_CARGO);
1551                                 }
1552
1553                                 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);                            
1554                                 hud_set_gauge_color(HUD_TARGET_MONITOR);
1555                         }
1556                 }
1557         }       // end if (is_ship)
1558
1559 }
1560
1561 // -----------------------------------------------------------------------------------
1562 // hud_show_target_data() will display the data about the target in and
1563 // around the targetting window
1564 //
1565 void hud_show_target_data(float frametime)
1566 {
1567         char outstr[256];                                               // temp buffer for sprintf'ing hud output
1568         int w,h;                                                                        // width and height of string about to print
1569         object          *target_objp;
1570         ship                    *shipp = NULL;
1571         debris          *debrisp = NULL;
1572         ship_info       *sip = NULL;
1573         int is_ship = 0;
1574
1575         hud_set_gauge_color(HUD_TARGET_MONITOR);
1576
1577         target_objp = &Objects[Player_ai->target_objnum];
1578
1579         switch( Objects[Player_ai->target_objnum].type ) {
1580                 case OBJ_SHIP:
1581                         shipp = &Ships[target_objp->instance];
1582                         sip = &Ship_info[shipp->ship_info_index];
1583                         is_ship = 1;
1584                         break;
1585
1586                 case OBJ_DEBRIS:
1587                         debrisp = &Debris[target_objp->instance]; 
1588                         sip = &Ship_info[debrisp->ship_info_index];
1589                         break;
1590
1591                 case OBJ_WEAPON:
1592                         sip = NULL;
1593                         break;
1594
1595                 case OBJ_ASTEROID:
1596                         sip = NULL;
1597                         break;
1598
1599                 case OBJ_JUMP_NODE:
1600                         return;
1601
1602                 default:
1603                         Int3(); // can't happen
1604                         break;
1605         }
1606
1607         int hx, hy;
1608
1609         // Account for HUD shaking
1610         hx = fl2i(HUD_offset_x);
1611         hy = fl2i(HUD_offset_y);
1612
1613         // print out the target distance and speed
1614         sprintf(outstr,XSTR( "d: %.0f%s", 350), Player_ai->current_target_distance, modifiers[Player_ai->current_target_dist_trend]);
1615
1616         hud_num_make_mono(outstr);
1617         gr_get_string_size(&w,&h,outstr);
1618
1619         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);       
1620
1621         float spd;
1622 #if 0
1623         spd = vm_vec_dist(&target_objp->pos, &target_objp->last_pos) / frametime;
1624 #endif
1625         // 7/28/99 DKA: Do not use vec_mag_quick -- the error is too big
1626         spd = vm_vec_mag(&target_objp->phys_info.vel);
1627 //      spd = target_objp->phys_info.fspeed;
1628         if ( spd < 0.1 ) {
1629                 spd = 0.0f;
1630         }
1631         // if the speed is 0, determine if we are docked with something -- if so, get the velocity from
1632         // our docked object instead
1633         if ( (spd == 0.0f) && is_ship ) {
1634                 ai_info *aip;
1635                 object *other_objp;
1636
1637                 aip = &Ai_info[shipp->ai_index];
1638                 if ( aip->ai_flags & AIF_DOCKED ) {
1639                         Assert( aip->dock_objnum != -1 );
1640                         other_objp = &Objects[aip->dock_objnum];
1641                         spd = other_objp->phys_info.fspeed;
1642                         if ( spd < 0.1 )
1643                                 spd = 0.0f;
1644                 }
1645         }
1646
1647         sprintf(outstr, XSTR( "s: %.0f%s", 351), spd, (spd>1)?modifiers[Player_ai->current_target_speed_trend]:"");
1648         hud_num_make_mono(outstr);
1649
1650         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);    
1651
1652         //
1653         // output target info for debug purposes only, this will be removed later
1654         //
1655
1656 #ifndef NDEBUG
1657         //XSTR:OFF
1658         char outstr2[256];      
1659         if ( Show_target_debug_info && (is_ship == 1) ) {
1660                 int sx, sy, dy;
1661                 sx = 5;
1662                 dy = gr_get_font_height() + 1;
1663                 sy = 300 - 7*dy;
1664
1665                 gr_set_color_fast(&HUD_color_debug);
1666
1667                 if ( shipp->ai_index >= 0 ) {
1668                         ai_info *aip = &Ai_info[shipp->ai_index];
1669
1670                         sprintf(outstr,"AI: %s",Ai_behavior_names[aip->mode]);
1671
1672                         switch (aip->mode) {
1673                         case AIM_CHASE:
1674                                 Assert(aip->submode <= SM_BIG_PARALLEL);        //      Must be <= largest chase submode value.
1675 //                              sprintf(outstr,"AI: %s",Submode_text[aip->submode]);
1676                                 sprintf(outstr2," / %s",Submode_text[aip->submode]);
1677                                 strcat(outstr,outstr2);
1678                                 break;
1679                         case AIM_STRAFE:
1680                                 Assert(aip->submode <= AIS_STRAFE_POSITION);    //      Must be <= largest chase submode value.
1681 //                              sprintf(outstr,"AI: %s",Strafe_submode_text[aip->submode-AIS_STRAFE_ATTACK]);
1682                                 sprintf(outstr2," / %s",Strafe_submode_text[aip->submode-AIS_STRAFE_ATTACK]);
1683                                 strcat(outstr,outstr2);
1684                                 break;
1685                         case AIM_WAYPOINTS:
1686 //                              gr_printf(sx, sy, "Wpnum: %i",aip->wp_index);
1687                                 sprintf(outstr2," / Wpnum: %i",aip->wp_index);
1688                                 strcat(outstr,outstr2);
1689                                 break;
1690                         default:
1691                                 break;
1692                         }
1693
1694                         gr_printf(sx, sy, outstr);
1695                         sy += dy;
1696
1697                         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));
1698                         sy += dy;
1699                         
1700                         // data can be found in target montior
1701                         // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+3, TARGET_WINDOW_Y1+5*h, "Shields: %d", (int) Players[Player_num].current_target->shields);
1702                         if (aip->target_objnum != -1) {
1703                                 char    target_str[32];
1704                                 float   dot, dist;
1705                                 vector  v2t;
1706
1707                                 if (aip->target_objnum == Player_obj-Objects)
1708                                         strcpy(target_str, "Player!");
1709                                 else
1710                                         sprintf(target_str, "%s", Ships[Objects[aip->target_objnum].instance].ship_name);
1711
1712 //              gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+4*h, "Target: %s", target_str);
1713                                 gr_printf(sx, sy, "Targ: %s", target_str);
1714                                 sy += dy;
1715
1716                                 dist = vm_vec_dist_quick(&Objects[Player_ai->target_objnum].pos, &Objects[aip->target_objnum].pos);
1717                                 vm_vec_normalized_dir(&v2t,&Objects[aip->target_objnum].pos, &Objects[Player_ai->target_objnum].pos);
1718
1719                                 dot = vm_vec_dot(&v2t, &Objects[Player_ai->target_objnum].orient.v.fvec);
1720
1721                                 // data can be found in target montior
1722                                 // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+3, TARGET_WINDOW_Y1+6*h, "Targ dist: %5.1f", dist);
1723 //              gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+5*h, "Targ dot: %3.2f", dot);
1724                                 gr_printf(sx, sy, "Targ dot: %3.2f", dot);
1725                                 sy += dy;
1726 //              gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+6*h, "Targ dst: %3.2f", dist);
1727                                 gr_printf(sx, sy, "Targ dst: %3.2f", dist);
1728                                 sy += dy;
1729
1730                                 if ( aip->targeted_subsys != NULL ) {
1731                                         sprintf(outstr, "Subsys: %s", aip->targeted_subsys->system_info->name);
1732                                         gr_printf(sx, sy, outstr);
1733                                 }
1734                                 sy += dy;
1735                         }
1736
1737                         // print out energy transfer information on the ship
1738                         sy = 70;
1739
1740                         sprintf(outstr,"MAX G/E: %.0f/%.0f",shipp->weapon_energy,shipp->current_max_speed);
1741                         gr_printf(sx, sy, outstr);
1742                         sy += dy;
1743                          
1744                         sprintf(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]);
1745                         gr_printf(sx, sy, outstr);
1746                         sy += dy;
1747
1748                         //      Show information about attacker.
1749                         {
1750                                 int     found = 0;
1751
1752                                 if (Enemy_attacker != NULL)
1753                                         if (Enemy_attacker->type == OBJ_SHIP) {
1754                                                 ship            *eshipp;
1755                                                 ai_info *eaip;
1756                                                 float           dot, dist;
1757                                                 vector  v2t;
1758
1759                                                 eshipp = &Ships[Enemy_attacker->instance];
1760                                                 eaip = &Ai_info[eshipp->ai_index];
1761
1762                                                 if (eaip->target_objnum == Player_obj-Objects) {
1763                                                         found = 1;
1764                                                         dist = vm_vec_dist_quick(&Enemy_attacker->pos, &Player_obj->pos);
1765                                                         vm_vec_normalized_dir(&v2t,&Objects[eaip->target_objnum].pos, &Enemy_attacker->pos);
1766
1767                                                         dot = vm_vec_dot(&v2t, &Enemy_attacker->orient.v.fvec);
1768
1769                                                         gr_printf(sx, sy, "#%i: %s", Enemy_attacker-Objects, Ships[Enemy_attacker->instance].ship_name);
1770                                                         sy += dy;
1771                                                         gr_printf(sx, sy, "Targ dist: %5.1f", dist);
1772                                                         sy += dy;
1773                                                         gr_printf(sx, sy, "Targ dot: %3.2f", dot);
1774                                                         sy += dy;
1775                                                 }
1776                                         }
1777
1778                                 if (Player_ai->target_objnum == Enemy_attacker - Objects)
1779                                         found = 0;
1780
1781                                 if (!found) {
1782                                         int     i;
1783
1784                                         Enemy_attacker = NULL;
1785                                         for (i=0; i<MAX_OBJECTS; i++)
1786                                                 if (Objects[i].type == OBJ_SHIP) {
1787                                                         int     enemy;
1788
1789                                                         if (i != Player_ai->target_objnum) {
1790                                                                 enemy = Ai_info[Ships[Objects[i].instance].ai_index].target_objnum;
1791
1792                                                                 if (enemy == Player_obj-Objects) {
1793                                                                         Enemy_attacker = &Objects[i];
1794                                                                         break;
1795                                                                 }
1796                                                         }
1797                                                 }
1798                                 }
1799                         }
1800
1801                         // Show target size
1802                         // hud_target_w
1803                         gr_printf(sx, sy, "Targ size: %dx%d", Hud_target_w, Hud_target_h );
1804                         sy += dy;
1805
1806                         polymodel *pm = model_get( shipp->modelnum );
1807                         gr_printf(sx, sy, "POF:%s", pm->filename );
1808                         sy += dy;
1809
1810                         gr_printf(sx, sy, "Mass: %.2f\n", pm->mass);
1811                         sy += dy;
1812                 }
1813         }
1814
1815         // display the weapons for the target on the HUD.  Include ammo counts.
1816         if ( Show_target_weapons && (is_ship == 1) ) {
1817                 int sx, sy, dy, i;
1818                 ship_weapon *swp;
1819
1820                 swp = &shipp->weapons;
1821                 sx = 400;
1822                 sy = 100;
1823                 dy = gr_get_font_height();
1824
1825                 sprintf(outstr,"Num primaries: %d", swp->num_primary_banks);
1826                 gr_printf(sx,sy,outstr);
1827                 sy += dy;
1828                 for ( i = 0; i < swp->num_primary_banks; i++ ) {
1829                         sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->primary_bank_weapons[i]].name);
1830                         gr_printf(sx,sy,outstr);
1831                         sy += dy;
1832                 }
1833
1834                 sy += dy;
1835                 sprintf(outstr,"Num secondaries: %d", swp->num_secondary_banks);
1836                 gr_printf(sx,sy,outstr);
1837                 sy += dy;
1838                 for ( i = 0; i < swp->num_secondary_banks; i++ ) {
1839                         sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->secondary_bank_weapons[i]].name);
1840                         gr_printf(sx,sy,outstr);
1841                         sy += dy;
1842                 }
1843         }
1844         //XSTR:ON
1845
1846 #endif
1847 }
1848
1849 // called at the start of each level
1850 void hud_targetbox_static_init()
1851 {
1852         Target_static_next = 0;;
1853         Target_static_playing = 0;
1854 }
1855
1856 // determine if we should draw static on top of the target box
1857 int hud_targetbox_static_maybe_blit(float frametime)
1858 {
1859         float   sensors_str;
1860
1861         // on lowest skill level, don't show static on target monitor
1862         if ( Game_skill_level == 0 )
1863                 return 0;
1864
1865         // if multiplayer observer, don't show static
1866         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
1867                 return 0;
1868         }
1869
1870         sensors_str = ship_get_subsystem_strength( Player_ship, SUBSYSTEM_SENSORS );
1871
1872         if ( ship_subsys_disrupted(Player_ship, SUBSYSTEM_SENSORS) ) {
1873                 sensors_str = SENSOR_STR_TARGET_NO_EFFECTS-1;
1874         }
1875
1876         if ( sensors_str > SENSOR_STR_TARGET_NO_EFFECTS ) {
1877                 Target_static_playing = 0;
1878                 Target_static_next = 0;
1879         } else {
1880                 if ( Target_static_next == 0 )
1881                         Target_static_next = 1;
1882         }
1883
1884         if ( timestamp_elapsed(Target_static_next) ) {
1885                 Target_static_playing ^= 1;
1886                 Target_static_next = timestamp_rand(50, 750);
1887         }
1888
1889         if ( Target_static_playing ) {
1890                 // hud_set_default_color();
1891                 hud_set_gauge_color(HUD_TARGET_MONITOR);
1892                 hud_anim_render(&Target_static, frametime, 1);
1893                 if ( Target_static_looping == -1 ) {
1894                         Target_static_looping = snd_play_looping(&Snds[SND_STATIC]);
1895                 }
1896         } else {
1897                 if ( Target_static_looping != -1 ) {
1898                         snd_stop(Target_static_looping);
1899                         Target_static_looping = -1;
1900                 }
1901         }
1902
1903         return Target_static_playing;
1904 }
1905
1906 // start the targetbox item flashing for duration ms
1907 // input:       index   =>      TBOX_FLASH_ #define
1908 //                              duration        =>      optional param (default value TBOX_FLASH_DURATION), how long to flash in ms
1909 void hud_targetbox_start_flash(int index, int duration)
1910 {
1911         Targetbox_flash_timers[index][0] = timestamp(duration);
1912 }
1913
1914 // stop flashing a specific targetbox item 
1915 void hud_targetbox_end_flash(int index)
1916 {
1917         Targetbox_flash_timers[index][0] = 1;
1918 }
1919
1920 // determine if a given flashing index is bright or not
1921 int hud_targetbox_is_bright(int index)
1922 {
1923         return (Targetbox_flash_flags & (1<<index));
1924 }
1925
1926 // determine if the flashing has expired
1927 int hud_targetbox_flash_expired(int index)
1928 {
1929         if ( timestamp_elapsed(Targetbox_flash_timers[index][0]) ) {
1930                 return 1;
1931         }
1932                                                                                                                                                 
1933         return 0;
1934
1935
1936
1937 void hudtargetbox_page_in()
1938 {
1939         bm_page_in_aabitmap( Target_view_gauge.first_frame, Target_view_gauge.num_frames);
1940
1941         bm_page_in_aabitmap( Target_view_integrity_gauge.first_frame, Target_view_integrity_gauge.num_frames );
1942
1943         bm_page_in_aabitmap( Target_view_extra.first_frame, Target_view_extra.num_frames );
1944 }