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