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 the
6 * source.
7 *
8 */
9
10
11
12 #include "asteroid/asteroid.h"
13 #include "cmdline/cmdline.h"
14 #include "debris/debris.h"
15 #include "freespace.h"
16 #include "gamesnd/gamesnd.h"
17 #include "graphics/matrix.h"
18 #include "hud/hudbrackets.h"
19 #include "hud/hudtargetbox.h"
20 #include "iff_defs/iff_defs.h"
21 #include "io/timer.h"
22 #include "jumpnode/jumpnode.h"
23 #include "localization/localize.h"
24 #include "mission/missionparse.h"
25 #include "model/model.h"
26 #include "network/multi.h"
27 #include "object/object.h"
28 #include "object/objectdock.h"
29 #include "parse/parselo.h"
30 #include "playerman/player.h"
31 #include "ship/ship.h"
32 #include "ship/subsysdamage.h"
33 #include "species_defs/species_defs.h"
34 #include "weapon/emp.h"
35 #include "weapon/weapon.h"
36
37 #ifndef NDEBUG
38 #include "hud/hudets.h"
39 #endif
40
41
42 extern float View_zoom;
43
44 int Target_window_coords[GR_NUM_RESOLUTIONS][4] =
45 {
46 { // GR_640
47 8, 362, 131, 112
48 },
49 { // GR_1024
50 8, 629, 131, 112
51 }
52 };
53
54 object *Enemy_attacker = NULL;
55
56 static int Target_static_next;
57 static int Target_static_playing;
58 sound_handle Target_static_looping = sound_handle::invalid();
59
60 int Target_display_cargo;
61 char Cargo_string[256] = "";
62
63 #ifndef NDEBUG
64 extern int Show_target_debug_info;
65 extern int Show_target_weapons;
66 #endif
67
68 // used to print out + or - after target distance and speed
69 const char* modifiers[] = {
70 //XSTR:OFF
71 "+",
72 "-",
73 ""
74 //XSTR:ON
75 };
76
77 #define NUM_TBOX_COORDS 11 // keep up to date
78 #define TBOX_BACKGROUND 0
79 #define TBOX_NAME 1
80 #define TBOX_CLASS 2
81 #define TBOX_DIST 3
82 #define TBOX_SPEED 4
83 #define TBOX_CARGO 5
84 #define TBOX_HULL 6
85 #define TBOX_EXTRA 7
86 #define TBOX_EXTRA_ORDERS 8
87 #define TBOX_EXTRA_TIME 9
88 #define TBOX_EXTRA_DOCK 10
89
90 // cargo scanning extents
91 int Cargo_scan_coords[GR_NUM_RESOLUTIONS][4] = {
92 { // GR_640
93 7, 364, 130, 109
94 },
95 { // GR_1024
96 7, 635, 130, 109
97 }
98 };
99
100 // first element is time flashing expires
101 int Targetbox_flash_timers[NUM_TBOX_FLASH_TIMERS];
102
103 int Targetbox_wire = 0;
104 int Targetbox_shader_effect = -1;
105 bool Lock_targetbox_mode = false;
106
107 // Different target states. This drives the text display right below the hull integrity on the targetbox.
108 #define TS_DIS 0
109 #define TS_OK 1
110 #define TS_DMG 2
111 #define TS_CRT 3
112
113 static int Current_ts; // holds current target status
114 static int Last_ts; // holds last target status.
115
116 /**
117 * @note Cut down long subsystem names to a more manageable length
118 */
hud_targetbox_truncate_subsys_name(char * outstr)119 void hud_targetbox_truncate_subsys_name(char *outstr)
120 {
121 if(Lcl_gr){
122 if ( strstr(outstr, "communication") ) {
123 strcpy(outstr, "Komm");
124 } else if ( !stricmp(outstr, "weapons") ) {
125 strcpy(outstr, "Waffen");
126 } else if ( strstr(outstr, "engine") || strstr(outstr, "Engine")) {
127 strcpy(outstr, "Antrieb");
128 } else if ( !stricmp(outstr, "sensors") ) {
129 strcpy(outstr, "Sensoren");
130 } else if ( strstr(outstr, "navigat") ) {
131 strcpy(outstr, "Nav");
132 } else if ( strstr(outstr, "fighterbay") || strstr(outstr, "Fighterbay") ) {
133 strcpy(outstr, "J\x84gerhangar");
134 } else if ( strstr(outstr, "missile") ) {
135 strcpy(outstr, "Raketenwerfer");
136 } else if ( strstr(outstr, "laser") || strstr(outstr, "turret") ) {
137 strcpy(outstr, "Gesch\x81tzturm");
138 } else if ( strstr(outstr, "Command Tower") || strstr(outstr, "Bridge") ) {
139 strcpy(outstr, "Br\x81""cke");
140 } else if ( strstr(outstr, "Barracks") ) {
141 strcpy(outstr, "Quartiere");
142 } else if ( strstr(outstr, "Reactor") ) {
143 strcpy(outstr, "Reaktor");
144 } else if ( strstr(outstr, "RadarDish") ) {
145 strcpy(outstr, "Radarantenne");
146 } else if (!stricmp(outstr, "Gas Collector")) {
147 strcpy(outstr, "Sammler");
148 }
149 } else if(Lcl_fr){
150 if ( strstr(outstr, "communication") ) {
151 strcpy(outstr, "comm");
152 } else if ( !stricmp(outstr, "weapons") ) {
153 strcpy(outstr, "armes");
154 } else if ( strstr(outstr, "engine") ) {
155 strcpy(outstr, "moteur");
156 } else if ( !stricmp(outstr, "sensors") ) {
157 strcpy(outstr, "detecteurs");
158 } else if ( strstr(outstr, "navi") ) {
159 strcpy(outstr, "nav");
160 } else if ( strstr(outstr, "missile") ) {
161 strcpy(outstr, "lanceur de missiles");
162 } else if ( strstr(outstr, "fighter") ) {
163 strcpy(outstr, "baie de chasse");
164 } else if ( strstr(outstr, "laser") || strstr(outstr, "turret") || strstr(outstr, "missile") ) {
165 strcpy(outstr, "tourelle");
166 }
167 } else if(Lcl_pl){
168 if ( strstr(outstr, "communication") ) {
169 strcpy(outstr, "komunikacja");
170 } else if ( !stricmp(outstr, "weapons") ) {
171 strcpy(outstr, "uzbrojenie");
172 } else if ( strstr(outstr, "engine") || strstr(outstr, "Engine")) {
173 strcpy(outstr, "silnik");
174 } else if ( !stricmp(outstr, "sensors") ) {
175 strcpy(outstr, "sensory");
176 } else if ( strstr(outstr, "navigat") ) {
177 strcpy(outstr, "nawigacja");
178 } else if ( strstr(outstr, "fighterbay") || strstr(outstr, "Fighterbay") ) {
179 strcpy(outstr, "dok my\x9Cliw.");
180 } else if ( strstr(outstr, "missile") ) {
181 strcpy(outstr, "wie\xBF. rakiet.");
182 } else if ( strstr(outstr, "laser") || strstr(outstr, "turret") ) {
183 strcpy(outstr, "wie\xBFyczka");
184 } else if ( strstr(outstr, "Command Tower") || strstr(outstr, "Bridge") ) {
185 strcpy(outstr, "mostek");
186 } else if ( strstr(outstr, "Barracks") ) {
187 strcpy(outstr, "koszary");
188 } else if ( strstr(outstr, "Reactor") ) {
189 strcpy(outstr, "reaktor");
190 } else if ( strstr(outstr, "RadarDish") || strstr(outstr, "Radar Dish") ) {
191 strcpy(outstr, "antena radaru");
192 } else if (!stricmp(outstr, "Gas Collector")) {
193 strcpy(outstr, "zbieracz gazu");
194 }
195 } else {
196 if (strstr(outstr, XSTR("communication", 333))) {
197 strcpy(outstr, XSTR("comm", 334));
198 } else if (strstr(outstr, XSTR("navigation", 335))) {
199 strcpy(outstr, XSTR("nav", 336));
200 } else if (strstr(outstr, "gas collector")) {
201 strcpy(outstr, "collector");
202 }
203 }
204 }
205
HudGaugeTargetBox()206 HudGaugeTargetBox::HudGaugeTargetBox():
207 HudGauge(HUD_OBJECT_TARGET_MONITOR, HUD_TARGET_MONITOR, false, false, (VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY), 255, 255, 255),
208 Monitor_mask(-1),
209 Use_subsys_name_offsets(false),
210 Use_subsys_integrity_offsets(false),
211 Use_disabled_status_offsets(false)
212 {
213 }
214
initViewportOffsets(int x,int y)215 void HudGaugeTargetBox::initViewportOffsets(int x, int y)
216 {
217 Viewport_offsets[0] = x;
218 Viewport_offsets[1] = y;
219 }
220
initViewportSize(int w,int h)221 void HudGaugeTargetBox::initViewportSize(int w, int h)
222 {
223 Viewport_w = w;
224 Viewport_h = h;
225 }
226
initIntegrityOffsets(int x,int y)227 void HudGaugeTargetBox::initIntegrityOffsets(int x, int y)
228 {
229 Integrity_bar_offsets[0] = x;
230 Integrity_bar_offsets[1] = y;
231 }
232
initIntegrityHeight(int h)233 void HudGaugeTargetBox::initIntegrityHeight(int h)
234 {
235 integrity_bar_h = h;
236 }
237
initStatusOffsets(int x,int y)238 void HudGaugeTargetBox::initStatusOffsets(int x, int y)
239 {
240 Status_offsets[0] = x;
241 Status_offsets[1] = y;
242 }
243
initNameOffsets(int x,int y)244 void HudGaugeTargetBox::initNameOffsets(int x, int y)
245 {
246 Name_offsets[0] = x;
247 Name_offsets[1] = y;
248 }
249
initClassOffsets(int x,int y)250 void HudGaugeTargetBox::initClassOffsets(int x, int y)
251 {
252 Class_offsets[0] = x;
253 Class_offsets[1] = y;
254 }
255
initDistOffsets(int x,int y)256 void HudGaugeTargetBox::initDistOffsets(int x, int y)
257 {
258 Dist_offsets[0] = x;
259 Dist_offsets[1] = y;
260 }
261
initSpeedOffsets(int x,int y)262 void HudGaugeTargetBox::initSpeedOffsets(int x, int y)
263 {
264 Speed_offsets[0] = x;
265 Speed_offsets[1] = y;
266 }
267
initCargoStringOffsets(int x,int y)268 void HudGaugeTargetBox::initCargoStringOffsets(int x, int y)
269 {
270 Cargo_string_offsets[0] = x;
271 Cargo_string_offsets[1] = y;
272 }
273
initHullOffsets(int x,int y)274 void HudGaugeTargetBox::initHullOffsets(int x, int y)
275 {
276 Hull_offsets[0] = x;
277 Hull_offsets[1] = y;
278 }
279
initCargoScanStartOffsets(int x,int y)280 void HudGaugeTargetBox::initCargoScanStartOffsets(int x, int y)
281 {
282 Cargo_scan_start_offsets[0] = x;
283 Cargo_scan_start_offsets[1] = y;
284 }
285
initCargoScanSize(int w,int h)286 void HudGaugeTargetBox::initCargoScanSize(int w, int h)
287 {
288 Cargo_scan_w = w;
289 Cargo_scan_h = h;
290 }
291
initSubsysNameOffsets(int x,int y,bool activate)292 void HudGaugeTargetBox::initSubsysNameOffsets(int x, int y, bool activate)
293 {
294 Subsys_name_offsets[0] = x;
295 Subsys_name_offsets[1] = y;
296 Use_subsys_name_offsets = activate;
297 }
298
initSubsysIntegrityOffsets(int x,int y,bool activate)299 void HudGaugeTargetBox::initSubsysIntegrityOffsets(int x, int y, bool activate)
300 {
301 Subsys_integrity_offsets[0] = x;
302 Subsys_integrity_offsets[1] = y;
303 Use_subsys_integrity_offsets = activate;
304 }
305
initDisabledStatusOffsets(int x,int y,bool activate)306 void HudGaugeTargetBox::initDisabledStatusOffsets(int x, int y, bool activate)
307 {
308 Disabled_status_offsets[0] = x;
309 Disabled_status_offsets[1] = y;
310 Use_disabled_status_offsets = activate;
311 }
312
initDesaturate(bool desaturate)313 void HudGaugeTargetBox::initDesaturate(bool desaturate)
314 {
315 Desaturated = desaturate;
316 }
317
initBitmaps(char * fname_monitor,char * fname_monitor_mask,char * fname_integrity,char * fname_static)318 void HudGaugeTargetBox::initBitmaps(char *fname_monitor, char *fname_monitor_mask, char *fname_integrity, char *fname_static)
319 {
320 Monitor_frame.first_frame = bm_load_animation(fname_monitor, &Monitor_frame.num_frames);
321 if ( Monitor_frame.first_frame < 0 ) {
322 Warning(LOCATION,"Cannot load hud ani: %s\n", fname_monitor);
323 }
324
325 Integrity_bar.first_frame = bm_load_animation(fname_integrity, &Integrity_bar.num_frames);
326 if ( Integrity_bar.first_frame < 0 ) {
327 Warning(LOCATION,"Cannot load hud ani: %s\n", fname_integrity);
328 }
329
330 if ( strlen(fname_monitor_mask) > 0 ) {
331 Monitor_mask = bm_load_animation(fname_monitor_mask);
332
333 if ( Monitor_mask < 0 ) {
334 Warning(LOCATION, "Cannot load bitmap hud mask: %s\n", fname_monitor_mask);
335 }
336 }
337
338 strcpy_s(static_fname, fname_static);
339 }
340
initialize()341 void HudGaugeTargetBox::initialize()
342 {
343 hud_anim_init(&Monitor_static, position[0] + Viewport_offsets[0], position[1] + Viewport_offsets[1], NOX(static_fname));
344
345 for(int i = 0; i < NUM_TBOX_FLASH_TIMERS; i++) {
346 initFlashTimer(i);
347 }
348
349 HudGauge::initialize();
350 }
351
initFlashTimer(int index)352 void HudGaugeTargetBox::initFlashTimer(int index)
353 {
354 Next_flash_timers[index] = 1;
355 flash_flags &= ~(1<<index);
356 }
357
render(float frametime)358 void HudGaugeTargetBox::render(float frametime)
359 {
360 object *target_objp;
361
362 if ( Player_ai->target_objnum == -1)
363 return;
364
365 if ( Target_static_playing )
366 return;
367
368 target_objp = &Objects[Player_ai->target_objnum];
369
370 setGaugeColor();
371
372 // blit the background frame
373 renderBitmap(Monitor_frame.first_frame, position[0], position[1]);
374
375 if ( Monitor_mask >= 0 ) {
376 // render the alpha mask
377 gr_alpha_mask_set(1, 0.5f);
378 gr_stencil_clear();
379 gr_stencil_set(GR_STENCIL_WRITE);
380 gr_set_color_buffer(0);
381
382 renderBitmapColor(Monitor_mask, position[0], position[1]);
383
384 gr_set_color_buffer(1);
385 gr_stencil_set(GR_STENCIL_NONE);
386 gr_alpha_mask_set(0, 1.0f);
387 }
388
389 switch ( target_objp->type ) {
390 case OBJ_SHIP:
391 renderTargetShip(target_objp);
392 break;
393
394 case OBJ_DEBRIS:
395 renderTargetDebris(target_objp);
396 break;
397
398 case OBJ_WEAPON:
399 renderTargetWeapon(target_objp);
400 break;
401
402 case OBJ_ASTEROID:
403 renderTargetAsteroid(target_objp);
404 break;
405
406 case OBJ_JUMP_NODE:
407 renderTargetJumpNode(target_objp);
408 break;
409
410 default:
411 hud_cease_targeting();
412 break;
413 } // end switch
414
415 if ( Target_static_playing ) {
416 setGaugeColor();
417 gr_set_screen_scale(base_w, base_h);
418 hud_anim_render(&Monitor_static, frametime, 1);
419 gr_reset_screen_scale();
420 } else {
421 showTargetData(frametime);
422 }
423
424 if(Target_display_cargo) {
425 // Print out what the cargo is
426 if ( maybeFlashSexp() == 1 ) {
427 setGaugeColor(HUD_C_BRIGHT);
428 } else {
429 maybeFlashElement(TBOX_FLASH_CARGO);
430 }
431
432 renderString(position[0] + Cargo_string_offsets[0], position[1] + Cargo_string_offsets[1], EG_TBOX_CARGO, Cargo_string);
433 }
434 }
435
renderTargetForeground()436 void HudGaugeTargetBox::renderTargetForeground()
437 {
438 setGaugeColor();
439
440 renderBitmap(Monitor_frame.first_frame+1, position[0], position[1]);
441 }
442
443 /**
444 * Draw the integrity bar that is on the right of the target monitor
445 */
renderTargetIntegrity(int disabled,int force_obj_num)446 void HudGaugeTargetBox::renderTargetIntegrity(int disabled,int force_obj_num)
447 {
448 int clip_h,w,h;
449 char buf[16];
450
451 if ( Integrity_bar.first_frame == -1 )
452 return;
453
454 if ( disabled ) {
455 renderBitmap(Integrity_bar.first_frame, position[0] + Integrity_bar_offsets[0], position[1] + Integrity_bar_offsets[1]);
456 return;
457 }
458
459 if(force_obj_num == -1)
460 Assert(Player_ai->target_objnum >= 0 );
461
462 clip_h = fl2i( (1 - Pl_target_integrity) * integrity_bar_h );
463
464 // print out status of ship
465 switch(Current_ts) {
466 case TS_DIS:
467 strcpy_s(buf,XSTR( "dis", 344));
468 break;
469 case TS_OK:
470 strcpy_s(buf,XSTR( "ok", 345));
471 break;
472 case TS_DMG:
473 strcpy_s(buf,XSTR( "dmg", 346));
474 break;
475 case TS_CRT:
476 strcpy_s(buf,XSTR( "crt", 347));
477 break;
478 }
479
480 maybeFlashElement(TBOX_FLASH_STATUS);
481
482 // finally print out the status of this ship
483 renderString(position[0] + Status_offsets[0], position[1] + Status_offsets[1], EG_TBOX_INTEG, buf);
484
485 setGaugeColor();
486
487 bm_get_info(Integrity_bar.first_frame,&w,&h);
488
489 if ( clip_h > 0 ) {
490 // draw the dark portion
491 renderBitmapEx(Integrity_bar.first_frame, position[0] + Integrity_bar_offsets[0], position[1] + Integrity_bar_offsets[1], w, clip_h,0,0);
492 }
493
494 if ( clip_h <= integrity_bar_h ) {
495 // draw the bright portion
496 renderBitmapEx(Integrity_bar.first_frame+1, position[0] + Integrity_bar_offsets[0], position[1] + Integrity_bar_offsets[1]+clip_h,w,h-clip_h,0,clip_h);
497 }
498 }
499
renderTargetSetup(vec3d * camera_eye,matrix * camera_orient,float zoom)500 void HudGaugeTargetBox::renderTargetSetup(vec3d *camera_eye, matrix *camera_orient, float zoom)
501 {
502 // JAS: g3_start_frame uses clip_width and clip_height to determine the
503 // size to render to. Normally, you would set this by using gr_set_clip,
504 // but because of the hacked in hud jittering, I couldn't. So come talk
505 // to me before modifying or reusing the following code. Thanks.
506
507 int clip_width = Viewport_w;
508 int clip_height = Viewport_h;
509
510 gr_screen.clip_width = clip_width;
511 gr_screen.clip_height = clip_height;
512 g3_start_frame(1); // Turn on zbuffering
513 hud_save_restore_camera_data(1);
514 g3_set_view_matrix( camera_eye, camera_orient, zoom);
515 model_set_detail_level(1); // use medium detail level
516
517 setClip(position[0] + Viewport_offsets[0], position[1] + Viewport_offsets[1], Viewport_w, Viewport_h);
518
519 // account for gauge RTT with cockpit here --wookieejedi
520 float clip_aspect;
521 if (gr_screen.rendering_to_texture != -1) {
522 clip_aspect = (i2fl(clip_width) / i2fl(clip_height));
523 } else {
524 clip_aspect = gr_screen.clip_aspect;
525 }
526
527 gr_set_proj_matrix(Proj_fov, clip_aspect, Min_draw_distance, Max_draw_distance);
528 gr_set_view_matrix(&Eye_position, &Eye_matrix);
529 }
530
renderTargetShip(object * target_objp)531 void HudGaugeTargetBox::renderTargetShip(object *target_objp)
532 {
533 vec3d obj_pos = ZERO_VECTOR;
534 vec3d camera_eye = ZERO_VECTOR;
535 matrix camera_orient = IDENTITY_MATRIX;
536 ship *target_shipp;
537 ship_info *target_sip;
538 vec3d orient_vec, up_vector;
539 int sx, sy;
540 int subsys_in_view;
541 float factor;
542
543 target_shipp = &Ships[target_objp->instance];
544 target_sip = &Ship_info[target_shipp->ship_info_index];
545
546 int flags=0;
547 if ( Detail.targetview_model ) {
548 // take the forward orientation to be the vector from the player to the current target
549 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
550 vm_vec_normalize(&orient_vec);
551
552 factor = -target_sip->closeup_pos_targetbox.xyz.z;
553
554 // use the player's up vector, and construct the viewers orientation matrix
555 if (Player_obj->type == OBJ_SHIP) {
556 vec3d tempv;
557 ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
558 } else {
559 camera_orient = Player_obj->orient;
560 }
561
562 up_vector = camera_orient.vec.uvec;
563 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
564
565 // normalize the vector from the player to the current target, and scale by a factor to calculate
566 // the objects position
567 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
568
569 // RT, changed scaling here
570 renderTargetSetup(&camera_eye, &camera_orient, target_sip->closeup_zoom_targetbox);
571
572 // IMPORTANT NOTE! Code handling the case 'missile_view == TRUE' in rendering section of renderTargetWeapon()
573 // is largely copied over from renderTargetShip(). To keep the codes similar please update
574 // both if and when needed
575 model_render_params render_info;
576 render_info.set_object_number(OBJ_INDEX(target_objp));
577
578 switch (Targetbox_wire) {
579 case 0:
580 flags |= MR_NO_LIGHTING;
581
582 break;
583 case 1:
584 if (ship_is_tagged(target_objp))
585 render_info.set_color(*iff_get_color(IFF_COLOR_TAGGED, 1));
586 else
587 render_info.set_color(*iff_get_color_by_team_and_object(target_shipp->team, Player_ship->team, 1, target_objp));
588
589 if (target_sip->uses_team_colors) {
590 render_info.set_team_color(target_shipp->team_name, target_shipp->secondary_team_name, target_shipp->team_change_timestamp, target_shipp->team_change_time);
591 }
592
593 flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
594
595 break;
596 case 2:
597 break;
598 case 3:
599 if (ship_is_tagged(target_objp))
600 render_info.set_color(*iff_get_color(IFF_COLOR_TAGGED, 1));
601 else
602 render_info.set_color(*iff_get_color_by_team_and_object(target_shipp->team, Player_ship->team, 1, target_objp));
603
604 flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
605
606 break;
607 }
608
609 if (target_sip->hud_target_lod >= 0) {
610 render_info.set_detail_level_lock(target_sip->hud_target_lod);
611 }
612
613 if(Targetbox_shader_effect > -1) {
614 render_info.set_animated_effect(Targetbox_shader_effect, 0.0f);
615 }
616
617 if ( Monitor_mask >= 0 ) {
618 gr_stencil_set(GR_STENCIL_READ);
619 }
620
621 if ( Desaturated ) {
622 flags |= MR_DESATURATED;
623 render_info.set_color(gauge_color);
624 }
625
626 if (!Glowpoint_override)
627 Glowpoint_override = true;
628
629 // set glowmap flag here since model_render (etc) require an objnum to handle glowmaps
630 // if we did pass the objnum, we'd also have thrusters drawn in the targetbox
631 if (target_shipp->flags[Ship::Ship_Flags::Glowmaps_disabled]) {
632 flags |= MR_NO_GLOWMAPS;
633 }
634
635 render_info.set_flags(flags | MR_AUTOCENTER | MR_NO_FOGGING);
636
637 // maybe render a special hud-target-only model
638 if(target_sip->model_num_hud >= 0){
639 model_render_immediate( &render_info, target_sip->model_num_hud, &target_objp->orient, &obj_pos);
640 } else {
641 render_info.set_replacement_textures(target_shipp->ship_replacement_textures);
642
643 model_render_immediate( &render_info, target_sip->model_num, &target_objp->orient, &obj_pos);
644 }
645
646 Glowpoint_override = false;
647
648 if ( Monitor_mask >= 0 ) {
649 gr_stencil_set(GR_STENCIL_NONE);
650 }
651
652 sx = 0;
653 sy = 0;
654 // check if subsystem target has changed
655 if ( Player_ai->targeted_subsys == Player_ai->last_subsys_target ) {
656 vec3d save_pos;
657
658 if (gr_screen.rendering_to_texture != -1) {
659 gr_set_screen_scale(canvas_w, canvas_h, -1, -1, target_w, target_h, target_w, target_h, true);
660 } else {
661 gr_set_screen_scale(base_w, base_h);
662 }
663
664 save_pos = target_objp->pos;
665 target_objp->pos = obj_pos;
666 subsys_in_view = hud_targetbox_subsystem_in_view(target_objp, &sx, &sy);
667 target_objp->pos = save_pos;
668
669 if ( subsys_in_view != -1 ) {
670
671 // AL 29-3-98: If subsystem is destroyed, draw gray brackets
672 // Goober5000 - hm, caught a tricky bug for destroyable fighterbays
673 if ( (Player_ai->targeted_subsys->current_hits <= 0) && ship_subsys_takes_damage(Player_ai->targeted_subsys) ) {
674 gr_set_color_fast(iff_get_color(IFF_COLOR_MESSAGE, 1));
675 } else {
676 hud_set_iff_color( target_objp, 1 );
677 }
678
679 graphics::line_draw_list line_draw_list;
680 if ( subsys_in_view ) {
681 draw_brackets_square_quick(&line_draw_list, sx - 10, sy - 10, sx + 10, sy + 10);
682 } else {
683 draw_brackets_diamond_quick(&line_draw_list, sx - 10, sy - 10, sx + 10, sy + 10);
684 }
685 line_draw_list.flush();
686 }
687 }
688 renderTargetClose();
689 }
690 renderTargetForeground();
691 renderTargetIntegrity(0,OBJ_INDEX(target_objp));
692
693 setGaugeColor();
694
695 renderTargetShipInfo(target_objp);
696 maybeRenderCargoScan(target_sip);
697 }
698
699 /**
700 * @note formerly hud_render_target_debris(object *target_objp) (Swifty)
701 */
renderTargetDebris(object * target_objp)702 void HudGaugeTargetBox::renderTargetDebris(object *target_objp)
703 {
704 vec3d obj_pos = ZERO_VECTOR;
705 vec3d camera_eye = ZERO_VECTOR;
706 matrix camera_orient = IDENTITY_MATRIX;
707 debris *debrisp;
708 vec3d orient_vec, up_vector;
709 float factor;
710 int flags=0;
711
712 debrisp = &Debris[target_objp->instance];
713
714 if ( Detail.targetview_model ) {
715 // take the forward orientation to be the vector from the player to the current target
716 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
717 vm_vec_normalize(&orient_vec);
718
719 factor = 2*target_objp->radius;
720
721 // use the player's up vector, and construct the viewers orientation matrix
722 if (Player_obj->type == OBJ_SHIP) {
723 vec3d tempv;
724 ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
725 } else {
726 camera_orient = Player_obj->orient;
727 }
728
729 up_vector = camera_orient.vec.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 renderTargetSetup(&camera_eye, &camera_orient, 0.5f);
737 model_clear_instance(debrisp->model_num);
738
739 model_render_params render_info;
740
741 switch (Targetbox_wire) {
742 case 0:
743 flags |= MR_NO_LIGHTING;
744
745 break;
746 case 1:
747 render_info.set_color(255, 255, 255);
748
749 flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
750
751 break;
752 case 2:
753 break;
754 case 3:
755 render_info.set_color(255, 255, 255);
756
757 flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
758
759 break;
760 }
761
762 if(Targetbox_shader_effect > -1) {
763 render_info.set_animated_effect(Targetbox_shader_effect, 0.0f);
764 }
765
766 if ( Monitor_mask >= 0 ) {
767 gr_stencil_set(GR_STENCIL_READ);
768 }
769
770 if ( Desaturated ) {
771 flags |= MR_DESATURATED;
772 render_info.set_color(gauge_color);
773 }
774
775 render_info.set_flags(flags | MR_NO_FOGGING);
776
777 auto pmi = model_get_instance(debrisp->model_instance_num);
778 auto pm = model_get(pmi->model_num);
779
780 // This calls the colour that doesn't get reset
781 submodel_render_immediate( &render_info, pm, pmi, debrisp->submodel_num, &target_objp->orient, &obj_pos);
782
783 if ( Monitor_mask >= 0 ) {
784 gr_stencil_set(GR_STENCIL_NONE);
785 }
786
787 renderTargetClose();
788 }
789 renderTargetForeground();
790 renderTargetIntegrity(1);
791
792 // print out ship class that debris came from
793 const char *printable_ship_class;
794 if (debrisp->parent_alt_name >= 0)
795 printable_ship_class = mission_parse_lookup_alt_index(debrisp->parent_alt_name);
796 else
797 printable_ship_class = Ship_info[debrisp->ship_info_index].get_display_name();
798
799 renderString(position[0] + Class_offsets[0], position[1] + Class_offsets[1], EG_TBOX_CLASS, printable_ship_class);
800 renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, XSTR("debris", 348));
801 }
802
803 /**
804 * @note Formerly hud_render_target_weapon(object *target_objp)
805 */
renderTargetWeapon(object * target_objp)806 void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
807 {
808 vec3d obj_pos = ZERO_VECTOR;
809 vec3d camera_eye = ZERO_VECTOR;
810 matrix camera_orient = IDENTITY_MATRIX;
811 vec3d orient_vec, up_vector;
812 vec3d projection_vec;
813 weapon_info *target_wip = NULL;
814 weapon *wp = NULL;
815 object *viewer_obj, *viewed_obj;
816 int *replacement_textures = NULL;
817 int target_team, is_homing, is_player_missile, missile_view, viewed_model_num, hud_target_lod, w, h;
818 int flags=0;
819
820 target_team = obj_team(target_objp);
821
822 wp = &Weapons[target_objp->instance];
823 target_wip = &Weapon_info[wp->weapon_info_index];
824
825 if (target_wip->model_num == -1)
826 return;
827
828 is_homing = FALSE;
829 if ( target_wip->is_homing() && wp->homing_object != &obj_used_list )
830 is_homing = TRUE;
831
832 is_player_missile = FALSE;
833 if ( target_objp->parent_sig == Player_obj->signature ) {
834 is_player_missile = TRUE;
835 }
836
837 if ( Detail.targetview_model ) {
838 ship *homing_shipp = NULL;
839 ship_info *homing_sip = NULL;
840
841 viewer_obj = Player_obj;
842 viewed_obj = target_objp;
843 missile_view = FALSE;
844 viewed_model_num = target_wip->model_num;
845 hud_target_lod = target_wip->hud_target_lod;
846 // adding a check here to make sure the homing object is a ship, technically it could be some other object just as well
847 if ( is_homing && is_player_missile && (wp->homing_object->type == OBJ_SHIP)) {
848 homing_shipp = &Ships[wp->homing_object->instance];
849 homing_sip = &Ship_info[homing_shipp->ship_info_index];
850
851 viewer_obj = target_objp;
852 viewed_obj = wp->homing_object;
853 missile_view = TRUE;
854 viewed_model_num = homing_sip->model_num;
855 replacement_textures = homing_shipp->ship_replacement_textures;
856 hud_target_lod = homing_sip->hud_target_lod;
857 }
858
859 // take the forward orientation to be the vector from the player to the current target
860 vm_vec_sub(&orient_vec, &viewed_obj->pos, &viewer_obj->pos);
861 vm_vec_normalize(&orient_vec);
862
863 if (missile_view == TRUE) {
864 vm_vec_sub(&projection_vec, &wp->homing_pos, &viewer_obj->pos);
865 vm_vec_normalize(&projection_vec);
866 }
867
868 // use the viewer's up vector, and construct the viewers orientation matrix
869 if (viewer_obj == Player_obj && Player_obj->type == OBJ_SHIP) {
870 vec3d tempv;
871 ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
872 } else {
873 camera_orient = viewer_obj->orient;
874 }
875
876 up_vector = camera_orient.vec.uvec;
877
878 if (missile_view == FALSE)
879 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
880 else
881 vm_vector_2_matrix(&camera_orient,&projection_vec,&up_vector,NULL);
882
883 // normalize the vector from the viewer to the viwed target, and scale by a factor to calculate
884 // the objects position
885 if (missile_view == FALSE) {
886 float factor = 2*target_objp->radius;
887 // small radius missiles need a bigger factor otherwise they are rendered larger than the targetbox
888 if (factor < 8.0f) {
889 factor = 8.0f;
890 }
891 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
892 } else {
893 vm_vec_sub(&obj_pos, &viewed_obj->pos, &viewer_obj->pos);
894 }
895
896 renderTargetSetup(&camera_eye, &camera_orient, View_zoom/3);
897 model_clear_instance(viewed_model_num);
898
899 model_render_params render_info;
900
901 // IMPORTANT NOTE! Code handling the rendering when 'missile_view == TRUE' is largely copied over from
902 // renderTargetShip(). To keep the codes similar please update both if and when needed
903 if (missile_view == FALSE) {
904 switch (Targetbox_wire) {
905 case 0:
906 flags |= MR_NO_LIGHTING;
907
908 break;
909 case 1:
910 render_info.set_color(*iff_get_color_by_team_and_object(target_team, Player_ship->team, 0, target_objp));
911
912 flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
913
914 break;
915 case 2:
916 break;
917 case 3:
918 render_info.set_color(*iff_get_color_by_team_and_object(target_team, Player_ship->team, 0, target_objp));
919
920 flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
921
922 break;
923 }
924 } else {
925 render_info.set_object_number(OBJ_INDEX(viewed_obj));
926
927 switch (Targetbox_wire) {
928 case 0:
929 flags |= MR_NO_LIGHTING;
930
931 break;
932 case 1:
933 if (ship_is_tagged(viewed_obj))
934 render_info.set_color(*iff_get_color(IFF_COLOR_TAGGED, 1));
935 else
936 render_info.set_color(*iff_get_color_by_team_and_object(homing_shipp->team, Player_ship->team, 1, viewed_obj));
937
938 if (homing_sip->uses_team_colors) {
939 render_info.set_team_color(homing_shipp->team_name, homing_shipp->secondary_team_name, homing_shipp->team_change_timestamp, homing_shipp->team_change_time);
940 }
941
942 flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
943
944 break;
945 case 2:
946 break;
947 case 3:
948 if (ship_is_tagged(viewed_obj))
949 render_info.set_color(*iff_get_color(IFF_COLOR_TAGGED, 1));
950 else
951 render_info.set_color(*iff_get_color_by_team_and_object(homing_shipp->team, Player_ship->team, 1, viewed_obj));
952
953 flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
954
955 break;
956 }
957 }
958
959 if (hud_target_lod >= 0) {
960 render_info.set_detail_level_lock(hud_target_lod);
961 }
962
963 if(Targetbox_shader_effect > -1) {
964 render_info.set_animated_effect(Targetbox_shader_effect, 0.0f);
965 }
966
967 if ( Monitor_mask >= 0 ) {
968 gr_stencil_set(GR_STENCIL_READ);
969 }
970
971 if ( Desaturated ) {
972 flags |= MR_DESATURATED;
973 render_info.set_color(gauge_color);
974 }
975
976 if (missile_view == TRUE) {
977 if (!Glowpoint_override)
978 Glowpoint_override = true;
979
980 // set glowmap flag here since model_render (etc) require an objnum to handle glowmaps
981 // if we did pass the objnum, we'd also have thrusters drawn in the targetbox
982 if (homing_shipp->flags[Ship::Ship_Flags::Glowmaps_disabled]) {
983 flags |= MR_NO_GLOWMAPS;
984 }
985 }
986
987 if (missile_view == FALSE ) {
988 render_info.set_flags(flags | MR_AUTOCENTER | MR_IS_MISSILE | MR_NO_FOGGING);
989 render_info.set_replacement_textures(replacement_textures);
990
991 model_render_immediate( &render_info, viewed_model_num, &viewed_obj->orient, &obj_pos );
992 } else {
993 // maybe render a special hud-target-only model
994 // autocentering is bad in this one
995 if(homing_sip->model_num_hud >= 0){
996 render_info.set_flags(flags | MR_NO_FOGGING);
997
998 model_render_immediate( &render_info, homing_sip->model_num_hud, &viewed_obj->orient, &obj_pos);
999 } else {
1000 render_info.set_flags(flags | MR_NO_FOGGING);
1001 render_info.set_replacement_textures(homing_shipp->ship_replacement_textures);
1002
1003 model_render_immediate( &render_info, homing_sip->model_num, &viewed_obj->orient, &obj_pos );
1004 }
1005 }
1006
1007 if (missile_view == TRUE) {
1008 Glowpoint_override = false;
1009 }
1010
1011 if ( Monitor_mask >= 0 ) {
1012 gr_stencil_set(GR_STENCIL_NONE);
1013 }
1014
1015 renderTargetClose();
1016 }
1017 renderTargetForeground();
1018
1019 renderTargetIntegrity(1);
1020 setGaugeColor();
1021
1022 // print out the weapon class name
1023 auto weapon_name = target_wip->get_display_name();
1024 gr_get_string_size(&w,&h,weapon_name);
1025
1026 renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, weapon_name);
1027
1028 // If a homing weapon, show time to impact
1029 if ( is_homing ) {
1030 float dist, speed;
1031 char outstr[100]; // temp buffer
1032
1033 speed = vm_vec_mag(&target_objp->phys_info.vel);
1034
1035 // do the extra math only if it won't lead to null vec issues
1036 if(!(IS_VEC_NULL_SQ_SAFE(&target_objp->phys_info.vel))){
1037 vec3d unit_vec, component_vec;
1038
1039 // in other words substract the magnitude of the target's velocity vectors parallel component from the speed of the weapon
1040 vm_vec_copy_normalize(&unit_vec, &target_objp->phys_info.vel);
1041 speed -= vm_vec_projection_parallel(&component_vec, &wp->homing_object->phys_info.vel, &unit_vec);
1042 }
1043
1044 dist = vm_vec_dist(&target_objp->pos, &wp->homing_pos);
1045
1046 if ( speed > 0 ) {
1047 sprintf(outstr, XSTR("impact: %.1f sec", 1596), dist/speed);
1048 } else {
1049 strcpy_s(outstr, XSTR( "unknown", 349));
1050 }
1051
1052 renderString(position[0] + Class_offsets[0], position[1] + Class_offsets[1], EG_TBOX_CLASS, outstr);
1053 }
1054 }
1055
1056 /**
1057 * @note Formerly hud_render_target_asteroid(object *target_objp)
1058 */
renderTargetAsteroid(object * target_objp)1059 void HudGaugeTargetBox::renderTargetAsteroid(object *target_objp)
1060 {
1061 vec3d obj_pos = ZERO_VECTOR;
1062 vec3d camera_eye = ZERO_VECTOR;
1063 matrix camera_orient = IDENTITY_MATRIX;
1064 asteroid *asteroidp;
1065 vec3d orient_vec, up_vector;
1066 float time_to_impact, factor;
1067 int pof;
1068
1069 int flags=0; //draw flags for wireframe
1070 asteroidp = &Asteroids[target_objp->instance];
1071
1072 pof = asteroidp->asteroid_subtype;
1073
1074 time_to_impact = asteroid_time_to_impact(target_objp);
1075
1076 if ( Detail.targetview_model ) {
1077 // take the forward orientation to be the vector from the player to the current target
1078 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
1079 vm_vec_normalize(&orient_vec);
1080
1081 factor = 2*target_objp->radius;
1082
1083 // use the player's up vector, and construct the viewers orientation matrix
1084 if (Player_obj->type == OBJ_SHIP) {
1085 vec3d tempv;
1086 ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
1087 } else {
1088 camera_orient = Player_obj->orient;
1089 }
1090
1091 up_vector = camera_orient.vec.uvec;
1092 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
1093
1094 // normalize the vector from the player to the current target, and scale by a factor to calculate
1095 // the objects position
1096 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
1097
1098 renderTargetSetup(&camera_eye, &camera_orient, 0.5f);
1099 model_clear_instance(Asteroid_info[asteroidp->asteroid_type].model_num[pof]);
1100
1101 model_render_params render_info;
1102
1103 switch (Targetbox_wire) {
1104 case 0:
1105 flags |= MR_NO_LIGHTING;
1106
1107 break;
1108 case 1:
1109 if (time_to_impact>=0)
1110 render_info.set_color(255,255,255);
1111 else
1112 render_info.set_color(64,64,0);
1113
1114 flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
1115
1116 break;
1117 case 2:
1118 break;
1119 case 3:
1120 if (time_to_impact>=0)
1121 render_info.set_color(255,255,255);
1122 else
1123 render_info.set_color(64,64,0);
1124
1125 flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
1126
1127 break;
1128 }
1129
1130 if(Targetbox_shader_effect > -1) {
1131 render_info.set_animated_effect(Targetbox_shader_effect, 0.0f);
1132 }
1133
1134 if ( Monitor_mask >= 0 ) {
1135 gr_stencil_set(GR_STENCIL_READ);
1136 }
1137
1138 if ( Desaturated ) {
1139 flags |= MR_DESATURATED;
1140 render_info.set_color(gauge_color);
1141 }
1142
1143 render_info.set_flags(flags | MR_NO_FOGGING);
1144
1145 model_render_immediate( &render_info, Asteroid_info[asteroidp->asteroid_type].model_num[pof], &target_objp->orient, &obj_pos );
1146
1147 if ( Monitor_mask >= 0 ) {
1148 gr_stencil_set(GR_STENCIL_NONE);
1149 }
1150
1151 renderTargetClose();
1152 }
1153 renderTargetForeground();
1154 renderTargetIntegrity(1);
1155 setGaugeColor();
1156
1157 // hud print type of Asteroid (debris)
1158 char hud_name[64];
1159 switch (asteroidp->asteroid_type) {
1160 case ASTEROID_TYPE_SMALL:
1161 case ASTEROID_TYPE_MEDIUM:
1162 case ASTEROID_TYPE_LARGE:
1163 strcpy_s(hud_name, XSTR("asteroid", 431));
1164 break;
1165
1166 default:
1167 strcpy_s(hud_name, Asteroid_info[asteroidp->asteroid_type].name);
1168 break;
1169 }
1170
1171 renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, hud_name);
1172
1173
1174 if ( time_to_impact >= 0.0f ) {
1175 renderPrintf(position[0] + Class_offsets[0], position[1] + Class_offsets[1], EG_TBOX_CLASS, XSTR("impact: %.1f sec", 1596), time_to_impact);
1176 }
1177 }
1178
1179 /**
1180 * Render a jump node on the target monitor
1181 * @note Formerly hud_render_target_jump_node(object *target_objp)
1182 */
renderTargetJumpNode(object * target_objp)1183 void HudGaugeTargetBox::renderTargetJumpNode(object *target_objp)
1184 {
1185 char outstr[256];
1186 vec3d obj_pos = ZERO_VECTOR;
1187 vec3d camera_eye = ZERO_VECTOR;
1188 matrix camera_orient = IDENTITY_MATRIX;
1189 vec3d orient_vec, up_vector;
1190 float factor, dist;
1191 int hx, hy, w, h;
1192 SCP_list<CJumpNode>::iterator jnp;
1193
1194 for (jnp = Jump_nodes.begin(); jnp != Jump_nodes.end(); ++jnp) {
1195 if(jnp->GetSCPObject() != target_objp)
1196 continue;
1197
1198 if ( jnp->IsHidden() ) {
1199 set_target_objnum( Player_ai, -1 );
1200 return;
1201 }
1202
1203 if ( Detail.targetview_model ) {
1204 // take the forward orientation to be the vector from the player to the current target
1205 vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
1206 vm_vec_normalize(&orient_vec);
1207
1208 factor = target_objp->radius*4.0f;
1209
1210 // use the player's up vector, and construct the viewers orientation matrix
1211 if (Player_obj->type == OBJ_SHIP) {
1212 vec3d tempv;
1213 ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
1214 } else {
1215 camera_orient = Player_obj->orient;
1216 }
1217
1218 up_vector = camera_orient.vec.uvec;
1219 vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
1220
1221 // normalize the vector from the player to the current target, and scale by a factor to calculate
1222 // the objects position
1223 vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
1224
1225 renderTargetSetup(&camera_eye, &camera_orient, 0.5f);
1226
1227 if ( Monitor_mask >= 0 ) {
1228 gr_stencil_set(GR_STENCIL_READ);
1229 }
1230
1231 jnp->Render( &obj_pos );
1232
1233 if ( Monitor_mask >= 0 ) {
1234 gr_stencil_set(GR_STENCIL_NONE);
1235 }
1236
1237 renderTargetClose();
1238 }
1239
1240 renderTargetForeground();
1241 renderTargetIntegrity(1);
1242 setGaugeColor();
1243
1244 strcpy_s(outstr, jnp->GetName());
1245 end_string_at_first_hash_symbol(outstr);
1246 renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, outstr);
1247
1248 dist = Player_ai->current_target_distance;
1249 if ( Hud_unit_multiplier > 0.0f ) { // use a different displayed distance scale
1250 dist = dist * Hud_unit_multiplier;
1251 }
1252
1253 // account for hud shaking
1254 hx = fl2i(HUD_offset_x);
1255 hy = fl2i(HUD_offset_y);
1256
1257 sprintf(outstr,XSTR( "d: %.0f", 340), dist);
1258 hud_num_make_mono(outstr, font_num);
1259 gr_get_string_size(&w,&h,outstr);
1260
1261 renderPrintf(position[0] + Dist_offsets[0]+hx, position[1] + Dist_offsets[1]+hy, EG_TBOX_DIST, "%s", outstr);
1262 }
1263 }
1264
1265 /**
1266 * Toggle through the valid targetbox modes
1267 *
1268 * @note 0==standard
1269 * @note 1==wireframe only
1270 * @note 2==standard with lighting
1271 */
hud_targetbox_switch_wireframe_mode()1272 void hud_targetbox_switch_wireframe_mode()
1273 {
1274
1275 Targetbox_wire++;
1276 if (Targetbox_wire==3)
1277 Targetbox_wire=0;
1278 }
1279
1280 /**
1281 * Init a specific targetbox timer
1282 */
hud_targetbox_init_flash_timer(int index)1283 void hud_targetbox_init_flash_timer(int index)
1284 {
1285 Targetbox_flash_timers[index] = 1;
1286 }
1287
1288 /**
1289 * Init the timers used to flash different parts of the targetbox.
1290 *
1291 * @note This needs to get called whenever the current target changes.
1292 * @note Need to call initFlashTimers for any TargetBox gauges and call initDockFlashTimer() for Extra Target Info gauges (Switfty)
1293 */
hud_targetbox_init_flash()1294 void hud_targetbox_init_flash()
1295 {
1296 for(int i = 0; i < NUM_TBOX_FLASH_TIMERS; i++) {
1297 hud_targetbox_init_flash_timer(i);
1298 }
1299
1300 Last_ts = -1;
1301 Current_ts = -1;
1302 }
1303
maybeFlashElement(int index,int flash_fast)1304 int HudGaugeTargetBox::maybeFlashElement(int index, int flash_fast)
1305 {
1306 int draw_bright=0;
1307
1308 setGaugeColor();
1309 if ( !timestamp_elapsed(Targetbox_flash_timers[index]) ) {
1310 if ( timestamp_elapsed(Next_flash_timers[index]) ) {
1311 if ( flash_fast ) {
1312 Next_flash_timers[index] = timestamp(fl2i(TBOX_FLASH_INTERVAL/2.0f));
1313 } else {
1314 Next_flash_timers[index] = timestamp(TBOX_FLASH_INTERVAL);
1315 }
1316 flash_flags ^= (1<<index); // toggle between default and bright frames
1317 }
1318
1319 if ( flash_flags & (1<<index) ) {
1320 setGaugeColor(HUD_C_BRIGHT);
1321 draw_bright=1;
1322 } else {
1323 setGaugeColor(HUD_C_DIM);
1324 }
1325 }
1326
1327 return draw_bright;
1328 }
1329
renderTargetClose()1330 void HudGaugeTargetBox::renderTargetClose()
1331 {
1332 gr_end_view_matrix();
1333 gr_end_proj_matrix();
1334
1335 g3_end_frame();
1336 hud_save_restore_camera_data(0);
1337 resetClip();
1338 }
1339
1340 /**
1341 * Get the shield and hull percentages for a given ship object
1342 *
1343 * @param objp Pointer to ship object that you want strength values for
1344 * @param shields OUTPUT parameter: percentage value of shields (0->1.0)
1345 * @param integrity OUTPUT parameter: percentage value of integrity (0->1.0)
1346 */
hud_get_target_strength(object * objp,float * shields,float * integrity)1347 void hud_get_target_strength(object *objp, float *shields, float *integrity)
1348 {
1349 *shields = get_shield_pct(objp);
1350 *integrity = get_hull_pct(objp);
1351 }
1352
HudGaugeExtraTargetData()1353 HudGaugeExtraTargetData::HudGaugeExtraTargetData():
1354 HudGauge(HUD_OBJECT_EXTRA_TARGET_DATA, HUD_TARGET_MONITOR_EXTRA_DATA, false, false, (VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY), 255, 255, 255)
1355 {
1356 initDockFlashTimer();
1357 }
1358
initialize()1359 void HudGaugeExtraTargetData::initialize()
1360 {
1361 initDockFlashTimer();
1362
1363 HudGauge::initialize();
1364 }
1365
initBracketOffsets(int x,int y)1366 void HudGaugeExtraTargetData::initBracketOffsets(int x, int y)
1367 {
1368 bracket_offsets[0] = x;
1369 bracket_offsets[1] = y;
1370 }
1371
initDockOffsets(int x,int y)1372 void HudGaugeExtraTargetData::initDockOffsets(int x, int y)
1373 {
1374 dock_offsets[0] = x;
1375 dock_offsets[1] = y;
1376 }
1377
initDockMaxWidth(int width)1378 void HudGaugeExtraTargetData::initDockMaxWidth(int width)
1379 {
1380 dock_max_w = width;
1381 }
1382
initTimeOffsets(int x,int y)1383 void HudGaugeExtraTargetData::initTimeOffsets(int x, int y)
1384 {
1385 time_offsets[0] = x;
1386 time_offsets[1] = y;
1387 }
1388
initOrderOffsets(int x,int y)1389 void HudGaugeExtraTargetData::initOrderOffsets(int x, int y)
1390 {
1391 order_offsets[0] = x;
1392 order_offsets[1] = y;
1393 }
1394
initOrderMaxWidth(int width)1395 void HudGaugeExtraTargetData::initOrderMaxWidth(int width)
1396 {
1397 order_max_w = width;
1398 }
1399
initBitmaps(char * fname)1400 void HudGaugeExtraTargetData::initBitmaps(char *fname)
1401 {
1402 bracket.first_frame = bm_load_animation(fname, &bracket.num_frames);
1403 if ( bracket.first_frame < 0 ) {
1404 Warning(LOCATION,"Cannot load hud ani: %s\n", fname);
1405 }
1406 }
1407
pageIn()1408 void HudGaugeExtraTargetData::pageIn()
1409 {
1410 bm_page_in_aabitmap( bracket.first_frame, bracket.num_frames );
1411 }
1412
1413 /**
1414 * @note Formerly hud_targetbox_show_extra_ship_info(target_shipp, target_objp) (Swifty)
1415 */
render(float)1416 void HudGaugeExtraTargetData::render(float /*frametime*/)
1417 {
1418 char tmpbuf[256];
1419 int has_orders = 0;
1420 int not_training;
1421 int extra_data_shown=0;
1422
1423 if(!canRender())
1424 return;
1425
1426 if ( Player_ai->target_objnum == -1)
1427 return;
1428
1429 if ( Target_static_playing )
1430 return;
1431
1432 object *target_objp;
1433 target_objp = &Objects[Player_ai->target_objnum];
1434
1435 // only render if this the current target is type OBJ_SHIP
1436 if(target_objp->type != OBJ_SHIP)
1437 return;
1438
1439 ship* target_shipp = &Ships[target_objp->instance];
1440
1441 setGaugeColor();
1442
1443 not_training = !(The_mission.game_type & MISSION_TYPE_TRAINING);
1444 if ( not_training) {
1445 // Print out current orders if the targeted ship is friendly
1446 // AL 12-26-97: only show orders and time to target for friendly ships
1447 // Backslash: actually let's consult the IFF table. Maybe we want to show orders for certain teams, or hide orders for friendlies
1448 if ( ((Player_ship->team == target_shipp->team) ||
1449 ((Iff_info[target_shipp->team].flags & IFFF_ORDERS_SHOWN) && !(Iff_info[target_shipp->team].flags & IFFF_ORDERS_HIDDEN)))
1450 && Ship_info[target_shipp->ship_info_index].is_flyable() ) {
1451 extra_data_shown = 1;
1452 auto orders = ship_return_orders(target_shipp);
1453 if (!orders.empty()) {
1454 char outstr[256];
1455 strcpy_s(outstr, orders.c_str());
1456 font::force_fit_string(outstr, 255, order_max_w);
1457 orders = outstr;
1458 has_orders = 1;
1459 } else {
1460 orders = XSTR("no orders", 337);
1461 }
1462
1463 renderString(position[0] + order_offsets[0], position[1] + order_offsets[1], EG_TBOX_EXTRA1, orders.c_str());
1464 }
1465
1466 if ( has_orders ) {
1467 char outstr[256];
1468 strcpy_s(outstr, XSTR( "time to: ", 338));
1469 if ( ship_return_time_to_goal(tmpbuf, target_shipp) ) {
1470 strcat_s(outstr, tmpbuf);
1471
1472 renderString(position[0] + time_offsets[0], position[1] + time_offsets[1], EG_TBOX_EXTRA2, outstr);
1473 }
1474 }
1475 }
1476
1477 if (Player_ai->last_target != Player_ai->target_objnum) {
1478 endFlashDock();
1479 }
1480
1481 // Print out dock status
1482 if ( object_is_docked(target_objp) )
1483 {
1484 startFlashDock(2000);
1485 // count the objects directly docked to me
1486 int dock_count = dock_count_direct_docked_objects(target_objp);
1487
1488 char outstr[256];
1489 // docked to only one object
1490 if (dock_count == 1)
1491 {
1492 sprintf(outstr, XSTR("Docked: %s", 339), Ships[dock_get_first_docked_object(target_objp)->instance].get_display_name());
1493 }
1494 // docked to multiple objects
1495 else
1496 {
1497 sprintf(outstr, XSTR("Docked: %d objects", 1623), dock_count);
1498 }
1499
1500 font::force_fit_string(outstr, 255, dock_max_w);
1501 maybeFlashDock();
1502
1503 renderString(position[0] + dock_offsets[0], position[1] + dock_offsets[1], EG_TBOX_EXTRA3, outstr);
1504 extra_data_shown=1;
1505 }
1506
1507 if ( extra_data_shown ) {
1508 renderBitmap(bracket.first_frame, position[0] + bracket_offsets[0], position[1] + bracket_offsets[1]);
1509 }
1510 }
1511
initDockFlashTimer()1512 void HudGaugeExtraTargetData::initDockFlashTimer()
1513 {
1514 flash_timer[0] = 1;
1515 flash_timer[1] = 1;
1516 flash_flags = false;
1517 }
1518
startFlashDock(int duration)1519 void HudGaugeExtraTargetData::startFlashDock(int duration)
1520 {
1521 flash_timer[0] = timestamp(duration);
1522 }
1523
maybeFlashDock(int flash_fast)1524 int HudGaugeExtraTargetData::maybeFlashDock(int flash_fast)
1525 {
1526 int draw_bright=0;
1527
1528 setGaugeColor();
1529 if ( !timestamp_elapsed(flash_timer[0]) ) {
1530 if ( timestamp_elapsed(flash_timer[1]) ) {
1531 if ( flash_fast ) {
1532 flash_timer[1] = timestamp(fl2i(TBOX_FLASH_INTERVAL/2.0f));
1533 } else {
1534 flash_timer[1] = timestamp(TBOX_FLASH_INTERVAL);
1535 }
1536
1537 // toggle between default and bright frames
1538 if(flash_flags)
1539 flash_flags = false;
1540 else
1541 flash_flags = true;
1542 }
1543
1544 if (flash_flags) {
1545 setGaugeColor(HUD_C_BRIGHT);
1546 draw_bright=1;
1547 } else {
1548 setGaugeColor(HUD_C_DIM);
1549 }
1550 }
1551
1552 return draw_bright;
1553 }
1554
endFlashDock()1555 void HudGaugeExtraTargetData::endFlashDock()
1556 {
1557 flash_timer[0] = timestamp(0);
1558 }
1559
1560 //from aicode.cpp. Less include...problems...this way.
1561 extern flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(ship_weapon *swp);
1562 extern bool turret_weapon_has_subtype(ship_weapon *swp, int subtype);
get_turret_subsys_name(ship_weapon * swp,char * outstr)1563 void get_turret_subsys_name(ship_weapon *swp, char *outstr)
1564 {
1565 Assert(swp != NULL); // Goober5000 //WMC
1566
1567 //WMC - find the first weapon, if there is one
1568 if (swp->num_primary_banks || swp->num_secondary_banks) {
1569 auto flags = turret_weapon_aggregate_flags(swp);
1570
1571 // check if beam or flak using weapon flags
1572 if (flags[Weapon::Info_Flags::Beam]) {
1573 sprintf(outstr, "%s", XSTR("Beam turret", 1567));
1574 } else if (flags[Weapon::Info_Flags::Flak]) {
1575 sprintf(outstr, "%s", XSTR("Flak turret", 1566));
1576 } else {
1577 if (turret_weapon_has_subtype(swp, WP_MISSILE)) {
1578 sprintf(outstr, "%s", XSTR("Missile lnchr", 1569));
1579 } else if (turret_weapon_has_subtype(swp, WP_LASER)) {
1580 // ballistic too! - Goober5000
1581 if (flags[Weapon::Info_Flags::Ballistic])
1582 {
1583 sprintf(outstr, "%s", XSTR("Turret", 1487));
1584 }
1585 // the TVWP has some primaries flagged as bombs
1586 else if (flags[Weapon::Info_Flags::Bomb])
1587 {
1588 sprintf(outstr, "%s", XSTR("Missile lnchr", 1569));
1589 }
1590 else
1591 {
1592 sprintf(outstr, "%s", XSTR("Laser turret", 1568));
1593 }
1594 } else {
1595 // Mantis #2226: find out if there are any weapons here at all
1596 if (flags.none_set()) {
1597 sprintf(outstr, "%s", NOX("Unused"));
1598 } else {
1599 // Illegal subtype
1600 static bool Turret_illegal_subtype_warned = false;
1601 if (!Turret_illegal_subtype_warned) {
1602 Turret_illegal_subtype_warned = true;
1603 Warning(LOCATION, "This turret has an illegal subtype! Trace out and fix!");
1604 }
1605 sprintf(outstr, "%s", XSTR("Turret", 1487));
1606 }
1607 }
1608 }
1609 } else if(swp->num_tertiary_banks) {
1610 //TODO: add tertiary turret code stuff here
1611 sprintf(outstr, "%s", NOX("Unknown"));
1612 } else {
1613 // This should not happen
1614 sprintf(outstr, "%s", NOX("Unused"));
1615 }
1616 }
1617
renderTargetShipInfo(object * target_objp)1618 void HudGaugeTargetBox::renderTargetShipInfo(object *target_objp)
1619 {
1620 ship *target_shipp;
1621 int w, h, screen_integrity = 1;
1622 char outstr[NAME_LENGTH];
1623 char outstr_name[NAME_LENGTH*2+3];
1624 char outstr_class[NAME_LENGTH];
1625 float ship_integrity, shield_strength;
1626
1627 Assert(target_objp); // Goober5000
1628 Assert(target_objp->type == OBJ_SHIP);
1629 target_shipp = &Ships[target_objp->instance];
1630
1631 // set up colors
1632 if ( HudGauge::maybeFlashSexp() == 1 ) {
1633 hud_set_iff_color(target_objp, 1);
1634 } else {
1635 // Print out ship name, with wing name if it exists
1636 if ( maybeFlashElement(TBOX_FLASH_NAME) ) {
1637 hud_set_iff_color(target_objp, 1);
1638 } else {
1639 hud_set_iff_color(target_objp);
1640 }
1641 }
1642
1643 // set up lines
1644 hud_stuff_ship_name(outstr_name, target_shipp);
1645 hud_stuff_ship_class(outstr_class, target_shipp);
1646
1647 // maybe concatenate the callsign
1648 if (*outstr_name)
1649 {
1650 char outstr_callsign[NAME_LENGTH];
1651
1652 hud_stuff_ship_callsign(outstr_callsign, target_shipp);
1653 if (*outstr_callsign)
1654 sprintf(&outstr_name[strlen(outstr_name)], " (%s)", outstr_callsign);
1655 }
1656 // maybe substitute the callsign
1657 else
1658 {
1659 hud_stuff_ship_callsign(outstr_name, target_shipp);
1660 }
1661
1662 // print lines based on current coords
1663 renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, outstr_name);
1664 renderString(position[0] + Class_offsets[0], position[1] + Class_offsets[1], EG_TBOX_CLASS, outstr_class);
1665
1666 // ----------
1667
1668 ship_integrity = 1.0f;
1669 shield_strength = 1.0f;
1670 hud_get_target_strength(target_objp, &shield_strength, &ship_integrity);
1671
1672 // convert to values of 0->100
1673 shield_strength *= 100.0f;
1674 ship_integrity *= 100.0f;
1675
1676 screen_integrity = (int)std::lround(ship_integrity);
1677 if ( screen_integrity == 0 ) {
1678 if ( ship_integrity > 0 ) {
1679 screen_integrity = 1;
1680 }
1681 }
1682 // Print out right-justified integrity
1683 sprintf(outstr, XSTR( "%d%%", 341), screen_integrity);
1684 gr_get_string_size(&w,&h,outstr);
1685
1686 if ( HudGauge::maybeFlashSexp() == 1 ) {
1687 setGaugeColor(HUD_C_BRIGHT);
1688 } else {
1689 maybeFlashElement(TBOX_FLASH_HULL);
1690 }
1691
1692 renderPrintf(position[0] + Hull_offsets[0]-w, position[1] + Hull_offsets[1], EG_TBOX_HULL, "%s", outstr);
1693 setGaugeColor();
1694
1695 // print out the targeted sub-system and % integrity
1696 if (Player_ai->targeted_subsys != NULL) {
1697 shield_strength = Player_ai->targeted_subsys->current_hits/Player_ai->targeted_subsys->max_hits * 100.0f;
1698 screen_integrity = (int)std::lround(shield_strength);
1699
1700 if ( screen_integrity < 0 ) {
1701 screen_integrity = 0;
1702 }
1703
1704 if ( screen_integrity == 0 ) {
1705 if ( shield_strength > 0 ) {
1706 screen_integrity = 1;
1707 }
1708 }
1709
1710 maybeFlashElement(TBOX_FLASH_SUBSYS);
1711
1712 // get turret subsys name
1713 if (Player_ai->targeted_subsys->system_info->type == SUBSYSTEM_TURRET && !ship_subsys_has_instance_name(Player_ai->targeted_subsys)) {
1714 get_turret_subsys_name(&Player_ai->targeted_subsys->weapons, outstr);
1715 } else {
1716 sprintf(outstr, "%s", ship_subsys_get_name(Player_ai->targeted_subsys));
1717 }
1718
1719 char *p_line;
1720 // hence pipe shall be the linebreak
1721 char linebreak[2] = "|";
1722 int n_linebreaks = 0;
1723 p_line = strpbrk(outstr,linebreak);
1724
1725 // figure out how many linebreaks we actually have
1726 while (p_line != NULL) {
1727 n_linebreaks++;
1728 p_line = strpbrk(p_line+1,linebreak);
1729 }
1730
1731 int subsys_name_pos_x;
1732 int subsys_name_pos_y;
1733
1734 if ( Use_subsys_name_offsets ) {
1735 subsys_name_pos_x = position[0] + Subsys_name_offsets[0];
1736 subsys_name_pos_y = position[1] + Subsys_name_offsets[1];
1737 } else {
1738 subsys_name_pos_x = position[0] + Viewport_offsets[0] + 2;
1739 subsys_name_pos_y = position[1] + Viewport_offsets[1] + Viewport_h;
1740 }
1741
1742 if (n_linebreaks) {
1743 p_line = strtok(outstr,linebreak);
1744 while (p_line != NULL) {
1745 renderPrintf(subsys_name_pos_x, subsys_name_pos_y-h-((h+1)*n_linebreaks), "%s", p_line);
1746 p_line = strtok(NULL,linebreak);
1747 n_linebreaks--;
1748 }
1749 } else {
1750 hud_targetbox_truncate_subsys_name(outstr);
1751 renderPrintf(subsys_name_pos_x, subsys_name_pos_y-h, "%s", outstr);
1752 }
1753
1754 int subsys_integrity_pos_x;
1755 int subsys_integrity_pos_y;
1756
1757 if ( Use_subsys_integrity_offsets ) {
1758 subsys_integrity_pos_x = position[0] + Subsys_integrity_offsets[0];
1759 subsys_integrity_pos_y = position[1] + Subsys_integrity_offsets[1];
1760 } else {
1761 subsys_integrity_pos_x = position[0] + Viewport_offsets[0] + Viewport_w - 1;
1762 subsys_integrity_pos_y = position[1] + Viewport_offsets[1] + Viewport_h;
1763 }
1764
1765 // AL 23-3-98: Fighter bays are a special case. Player cannot destroy them, so don't
1766 // show the subsystem strength
1767 // Goober5000: don't display any strength if we can't destroy this subsystem - but sometimes
1768 // fighterbays can be destroyed
1769 if ( ship_subsys_takes_damage(Player_ai->targeted_subsys) )
1770 {
1771 sprintf(outstr,XSTR( "%d%%", 341),screen_integrity);
1772 gr_get_string_size(&w,&h,outstr);
1773 renderPrintf(subsys_integrity_pos_x - w, subsys_integrity_pos_y - h, "%s", outstr);
1774 }
1775
1776 setGaugeColor();
1777 }
1778
1779 // print out 'disabled' on the monitor if the target is disabled
1780 if ( (target_shipp->flags[Ship::Ship_Flags::Disabled]) || (ship_subsys_disrupted(target_shipp, SUBSYSTEM_ENGINE)) ) {
1781 if ( target_shipp->flags[Ship::Ship_Flags::Disabled] ) {
1782 strcpy_s(outstr, XSTR( "DISABLED", 342));
1783 } else {
1784 strcpy_s(outstr, XSTR( "DISRUPTED", 343));
1785 }
1786 gr_get_string_size(&w,&h,outstr);
1787
1788 int disabled_status_pos_x;
1789 int disabled_status_pos_y;
1790
1791 if ( Use_disabled_status_offsets ) {
1792 disabled_status_pos_x = position[0] + Disabled_status_offsets[0];
1793 disabled_status_pos_y = position[1] + Disabled_status_offsets[1];
1794 } else {
1795 disabled_status_pos_x = position[0] + Viewport_offsets[0] + Viewport_w/2 - w/2 - 1;
1796 disabled_status_pos_y = position[1] + Viewport_offsets[1] + Viewport_h - 2*h;
1797 }
1798
1799 renderPrintf(disabled_status_pos_x, disabled_status_pos_y, "%s", outstr);
1800 }
1801 }
1802
1803 /**
1804 * Determine if the subsystem is in line-of sight, without taking into account whether the player ship is
1805 * facing the subsystem
1806 */
hud_targetbox_subsystem_in_view(object * target_objp,int * sx,int * sy)1807 int hud_targetbox_subsystem_in_view(object *target_objp, int *sx, int *sy)
1808 {
1809 ship_subsys *subsys;
1810 vec3d subobj_pos;
1811 vertex subobj_vertex;
1812 int rval = -1;
1813 polymodel *pm;
1814
1815 subsys = Player_ai->targeted_subsys;
1816 if (subsys != NULL ) {
1817 get_subsystem_pos(&subobj_pos, target_objp, subsys);
1818
1819 // is it subsystem in view
1820 if ( Player->subsys_in_view == -1 ) {
1821 rval = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos, 0);
1822 } else {
1823 rval = Player->subsys_in_view;
1824 }
1825
1826 // get screen coords, adjusting for autocenter
1827 Assert(target_objp->type == OBJ_SHIP);
1828 if (target_objp->type == OBJ_SHIP) {
1829 pm = model_get(Ship_info[Ships[target_objp->instance].ship_info_index].model_num);
1830 if (pm->flags & PM_FLAG_AUTOCEN) {
1831 vec3d temp, delta;
1832 vm_vec_copy_scale(&temp, &pm->autocenter, -1.0f);
1833 vm_vec_unrotate(&delta, &temp, &target_objp->orient);
1834 vm_vec_add2(&subobj_pos, &delta);
1835 }
1836 }
1837
1838 g3_rotate_vertex(&subobj_vertex, &subobj_pos);
1839 g3_project_vertex(&subobj_vertex);
1840 *sx = (int) subobj_vertex.screen.xyw.x;
1841 *sy = (int) subobj_vertex.screen.xyw.y;
1842 }
1843
1844 return rval;
1845 }
1846
hud_cargo_scan_update(object * targetp,float frametime)1847 void hud_cargo_scan_update(object *targetp, float frametime)
1848 {
1849 // update cargo inspection status
1850 Cargo_string[0] = 0;
1851 if ( targetp->type == OBJ_SHIP ) {
1852 Target_display_cargo = player_inspect_cargo(frametime, Cargo_string);
1853 if ( Target_display_cargo ) {
1854 if ( Player->cargo_inspect_time > 0 ) {
1855 hud_targetbox_start_flash(TBOX_FLASH_CARGO);
1856 }
1857 }
1858 }
1859 }
1860
hud_update_cargo_scan_sound()1861 void hud_update_cargo_scan_sound()
1862 {
1863 if ( Player->cargo_inspect_time <= 0 ) {
1864 player_stop_cargo_scan_sound();
1865 return;
1866 }
1867 player_maybe_start_cargo_scan_sound();
1868
1869 }
1870
1871 /**
1872 * If the player is scanning for cargo, draw some cool scanning lines on the target monitor
1873 */
maybeRenderCargoScan(ship_info * target_sip)1874 void HudGaugeTargetBox::maybeRenderCargoScan(ship_info *target_sip)
1875 {
1876 int x1, y1, x2, y2;
1877 int scan_time; // time required to scan ship
1878
1879 if ( Player->cargo_inspect_time <= 0 ) {
1880 return;
1881 }
1882
1883 scan_time = target_sip->scan_time;
1884 setGaugeColor(HUD_C_BRIGHT);
1885
1886 // draw horizontal scan line
1887 x1 = position[0] + Cargo_scan_start_offsets[0]; // Cargo_scan_coords[gr_screen.res][0];
1888 y1 = fl2i(0.5f + position[1] + Cargo_scan_start_offsets[1] + ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_h ));
1889 x2 = x1 + Cargo_scan_w;
1890
1891 renderLine(x1, y1, x2, y1);
1892
1893 // RT Changed this to be optional
1894 if(Cmdline_dualscanlines) {
1895 // added 2nd horizontal scan line - phreak
1896 y1 = fl2i(position[1] + Cargo_scan_start_offsets[1] + Cargo_scan_h - ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_h ));
1897 renderLine(x1, y1, x2, y1);
1898 }
1899
1900 // draw vertical scan line
1901 x1 = fl2i(0.5f + position[0] + Cargo_scan_start_offsets[0] + ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_w ));
1902 y1 = position[1] + Cargo_scan_start_offsets[1];
1903 y2 = y1 + Cargo_scan_h;
1904
1905 renderLine(x1, y1-3, x1, y2-1);
1906
1907 // RT Changed this to be optional
1908 if(Cmdline_dualscanlines) {
1909 // added 2nd vertical scan line - phreak
1910 x1 = fl2i(0.5f + Cargo_scan_w + position[0] + Cargo_scan_start_offsets[0] - ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_w ));
1911 renderLine(x1, y1-3, x1, y2-1);
1912 }
1913 }
1914
showTargetData(float)1915 void HudGaugeTargetBox::showTargetData(float /*frametime*/)
1916 {
1917 char outstr[256]; // temp buffer for sprintf'ing hud output
1918 int w,h; // width and height of string about to print
1919 object *target_objp;
1920 ship *shipp = NULL;
1921 debris *debrisp = NULL;
1922 ship_info *sip = NULL;
1923 int is_ship = 0;
1924 float displayed_target_distance, displayed_target_speed, current_target_distance, current_target_speed;
1925
1926 setGaugeColor();
1927
1928 target_objp = &Objects[Player_ai->target_objnum];
1929
1930 current_target_distance = Player_ai->current_target_distance;
1931
1932 if ( Hud_unit_multiplier > 0.0f ) { // use a different displayed distance scale
1933 displayed_target_distance = current_target_distance * Hud_unit_multiplier;
1934 } else {
1935 displayed_target_distance = current_target_distance;
1936 }
1937
1938 switch( Objects[Player_ai->target_objnum].type ) {
1939 case OBJ_SHIP:
1940 shipp = &Ships[target_objp->instance];
1941 sip = &Ship_info[shipp->ship_info_index];
1942 is_ship = 1;
1943 break;
1944
1945 case OBJ_DEBRIS:
1946 debrisp = &Debris[target_objp->instance];
1947 sip = &Ship_info[debrisp->ship_info_index];
1948 break;
1949
1950 case OBJ_WEAPON:
1951 sip = NULL;
1952 break;
1953
1954 case OBJ_ASTEROID:
1955 sip = NULL;
1956 break;
1957
1958 case OBJ_JUMP_NODE:
1959 return;
1960
1961 default:
1962 Int3(); // can't happen
1963 break;
1964 }
1965
1966 int hx, hy;
1967
1968 // Account for HUD shaking
1969 hx = fl2i(HUD_offset_x);
1970 hy = fl2i(HUD_offset_y);
1971
1972 // print out the target distance and speed
1973 sprintf(outstr,XSTR( "d: %.0f%s", 350), displayed_target_distance, modifiers[Player_ai->current_target_dist_trend]);
1974
1975 hud_num_make_mono(outstr, font_num);
1976 gr_get_string_size(&w,&h,outstr);
1977
1978 renderString(position[0] + Dist_offsets[0]+hx, position[1] + Dist_offsets[1]+hy, EG_TBOX_DIST, outstr);
1979
1980 #if 0
1981 current_target_speed = vm_vec_dist(&target_objp->pos, &target_objp->last_pos) / frametime;
1982 #endif
1983 // 7/28/99 DKA: Do not use vec_mag_quick -- the error is too big
1984 current_target_speed = vm_vec_mag(&target_objp->phys_info.vel);
1985 if ( current_target_speed < 0.1f ) {
1986 current_target_speed = 0.0f;
1987 }
1988 // if the speed is 0, determine if we are docked with something -- if so, get the docked velocity
1989 if ( (current_target_speed == 0.0f) && is_ship ) {
1990 current_target_speed = dock_calc_docked_fspeed(&Objects[shipp->objnum]);
1991
1992 if ( current_target_speed < 0.1f ) {
1993 current_target_speed = 0.0f;
1994 }
1995 }
1996
1997 if ( Hud_speed_multiplier > 0.0f ) { // use a different displayed speed scale
1998 displayed_target_speed = current_target_speed * Hud_speed_multiplier;
1999 } else {
2000 displayed_target_speed = current_target_speed;
2001 }
2002
2003 sprintf(outstr, XSTR( "s: %.0f%s", 351), displayed_target_speed, (displayed_target_speed>1)?modifiers[Player_ai->current_target_speed_trend]:"");
2004 hud_num_make_mono(outstr, font_num);
2005
2006 renderString(position[0] + Speed_offsets[0]+hx, position[1] + Speed_offsets[1]+hy, EG_TBOX_SPEED, outstr);
2007
2008 //
2009 // output target info for debug purposes only, this will be removed later
2010 //
2011
2012 #ifndef NDEBUG
2013 //XSTR:OFF
2014 char outstr2[256];
2015 if ( Show_target_debug_info && (is_ship == 1) ) {
2016 int sx, sy, dy;
2017 sx = gr_screen.center_offset_x + 5;
2018 dy = gr_get_font_height() + 1;
2019 sy = gr_screen.center_offset_y + 300 - 7*dy;
2020
2021 gr_set_color_fast(&HUD_color_debug);
2022
2023 if ( shipp->ai_index >= 0 ) {
2024 ai_info *aip = &Ai_info[shipp->ai_index];
2025
2026 sprintf(outstr,"AI: %s",Ai_behavior_names[aip->mode]);
2027
2028 switch (aip->mode) {
2029 case AIM_CHASE:
2030 Assert(aip->submode <= SM_BIG_PARALLEL); // Must be <= largest chase submode value.
2031 sprintf(outstr2," / %s",Submode_text[aip->submode]);
2032 strcat_s(outstr,outstr2);
2033 break;
2034 case AIM_STRAFE:
2035 Assert(aip->submode <= AIS_STRAFE_POSITION); // Must be <= largest chase submode value.
2036 sprintf(outstr2," / %s",Strafe_submode_text[aip->submode-AIS_STRAFE_ATTACK]);
2037 strcat_s(outstr,outstr2);
2038 break;
2039 case AIM_WAYPOINTS:
2040 break;
2041 default:
2042 break;
2043 }
2044
2045 gr_printf_no_resize(sx, sy, "%s", outstr);
2046 sy += dy;
2047
2048 gr_printf_no_resize(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));
2049 sy += dy;
2050
2051 // data can be found in target montior
2052 if (aip->target_objnum != -1) {
2053 const char *target_str;
2054 float dot, dist;
2055 vec3d v2t;
2056
2057 if (aip->target_objnum == OBJ_INDEX(Player_obj))
2058 target_str = "Player!";
2059 else
2060 target_str = Ships[Objects[aip->target_objnum].instance].get_display_name();
2061
2062 gr_printf_no_resize(sx, sy, "Targ: %s", target_str);
2063 sy += dy;
2064
2065 dist = vm_vec_dist_quick(&Objects[Player_ai->target_objnum].pos, &Objects[aip->target_objnum].pos);
2066 vm_vec_normalized_dir(&v2t,&Objects[aip->target_objnum].pos, &Objects[Player_ai->target_objnum].pos);
2067
2068 dot = vm_vec_dot(&v2t, &Objects[Player_ai->target_objnum].orient.vec.fvec);
2069
2070 // data can be found in target monitor
2071 gr_printf_no_resize(sx, sy, "Targ dot: %3.2f", dot);
2072 sy += dy;
2073 gr_printf_no_resize(sx, sy, "Targ dst: %3.2f", dist);
2074 sy += dy;
2075
2076 if ( aip->targeted_subsys != NULL ) {
2077 sprintf(outstr, "Subsys: %s", aip->targeted_subsys->system_info->subobj_name);
2078 gr_printf_no_resize(sx, sy, "%s", outstr);
2079 }
2080 sy += dy;
2081 }
2082
2083 // print out energy transfer information on the ship
2084 sy = gr_screen.center_offset_y + 70;
2085
2086 sprintf(outstr,"MAX G/E: %.0f/%.0f",shipp->weapon_energy,shipp->current_max_speed);
2087 gr_printf_no_resize(sx, sy, "%s", outstr);
2088 sy += dy;
2089
2090 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]);
2091 gr_printf_no_resize(sx, sy, "%s", outstr);
2092 sy += dy;
2093
2094 // Show information about attacker.
2095 {
2096 int found = 0;
2097
2098 if (Enemy_attacker != NULL)
2099 if (Enemy_attacker->type == OBJ_SHIP) {
2100 ship *eshipp;
2101 ai_info *eaip;
2102 float dot, dist;
2103 vec3d v2t;
2104
2105 eshipp = &Ships[Enemy_attacker->instance];
2106 eaip = &Ai_info[eshipp->ai_index];
2107
2108 if (eaip->target_objnum == OBJ_INDEX(Player_obj)) {
2109 found = 1;
2110 dist = vm_vec_dist_quick(&Enemy_attacker->pos, &Player_obj->pos);
2111 vm_vec_normalized_dir(&v2t,&Objects[eaip->target_objnum].pos, &Enemy_attacker->pos);
2112
2113 dot = vm_vec_dot(&v2t, &Enemy_attacker->orient.vec.fvec);
2114
2115 gr_printf_no_resize(sx, sy, "#%i: %s", OBJ_INDEX(Enemy_attacker), Ships[Enemy_attacker->instance].get_display_name());
2116 sy += dy;
2117 gr_printf_no_resize(sx, sy, "Targ dist: %5.1f", dist);
2118 sy += dy;
2119 gr_printf_no_resize(sx, sy, "Targ dot: %3.2f", dot);
2120 sy += dy;
2121 }
2122 }
2123
2124 if (Player_ai->target_objnum == Enemy_attacker - Objects)
2125 found = 0;
2126
2127 if (!found) {
2128 int i;
2129
2130 Enemy_attacker = NULL;
2131 for (i=0; i<MAX_OBJECTS; i++)
2132 if (Objects[i].type == OBJ_SHIP) {
2133 int enemy;
2134
2135 if (i != Player_ai->target_objnum) {
2136 enemy = Ai_info[Ships[Objects[i].instance].ai_index].target_objnum;
2137
2138 if (enemy == Player_obj-Objects) {
2139 Enemy_attacker = &Objects[i];
2140 break;
2141 }
2142 }
2143 }
2144 }
2145 }
2146
2147 // Show target size
2148 // hud_target_w
2149 gr_printf_no_resize(sx, sy, "Targ size: %dx%d", Hud_target_w, Hud_target_h );
2150 sy += dy;
2151
2152 polymodel *pm = model_get(sip->model_num);
2153 gr_printf_no_resize(sx, sy, "POF:%s", pm->filename );
2154 sy += dy;
2155
2156 gr_printf_no_resize(sx, sy, "Mass: %.2f\n", pm->mass);
2157 sy += dy;
2158 }
2159 }
2160
2161 // display the weapons for the target on the HUD. Include ammo counts.
2162 if ( Show_target_weapons && (is_ship == 1) ) {
2163 int sx, sy, dy, i;
2164 ship_weapon *swp;
2165
2166 swp = &shipp->weapons;
2167 sx = gr_screen.center_offset_x + 400;
2168 sy = gr_screen.center_offset_y + 100;
2169 dy = gr_get_font_height();
2170
2171 sprintf(outstr,"Num primaries: %d", swp->num_primary_banks);
2172 gr_printf_no_resize(sx,sy,"%s", outstr);
2173 sy += dy;
2174 for ( i = 0; i < swp->num_primary_banks; i++ ) {
2175 sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->primary_bank_weapons[i]].get_display_name());
2176 gr_printf_no_resize(sx,sy,"%s", outstr);
2177 sy += dy;
2178 }
2179
2180 sy += dy;
2181 sprintf(outstr,"Num secondaries: %d", swp->num_secondary_banks);
2182 gr_printf_no_resize(sx,sy,"%s", outstr);
2183 sy += dy;
2184 for ( i = 0; i < swp->num_secondary_banks; i++ ) {
2185 sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->secondary_bank_weapons[i]].get_display_name());
2186 gr_printf_no_resize(sx,sy,"%s", outstr);
2187 sy += dy;
2188 }
2189 }
2190 //XSTR:ON
2191
2192 #endif
2193 }
2194
2195 /**
2196 * Called at the start of each level
2197 */
hud_init_target_static()2198 void hud_init_target_static()
2199 {
2200 Target_static_next = 0;
2201 Target_static_playing = 0;
2202 }
2203
2204 /**
2205 * Determine if we should draw static on top of the target box
2206 */
hud_update_target_static()2207 void hud_update_target_static()
2208 {
2209 float sensors_str;
2210
2211 // on lowest skill level, don't show static on target monitor
2212 if ( Game_skill_level == 0 )
2213 return;
2214
2215 // if multiplayer observer, don't show static
2216 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER))
2217 return;
2218
2219 sensors_str = ship_get_subsystem_strength( Player_ship, SUBSYSTEM_SENSORS );
2220
2221 if ( ship_subsys_disrupted(Player_ship, SUBSYSTEM_SENSORS) ) {
2222 sensors_str = SENSOR_STR_TARGET_NO_EFFECTS-1;
2223 }
2224
2225 if ( sensors_str > SENSOR_STR_TARGET_NO_EFFECTS ) {
2226 Target_static_playing = 0;
2227 Target_static_next = 0;
2228 } else {
2229 if ( Target_static_next == 0 )
2230 Target_static_next = 1;
2231 }
2232
2233 if ( timestamp_elapsed(Target_static_next) ) {
2234 Target_static_playing ^= 1;
2235 Target_static_next = timestamp_rand(50, 750);
2236 }
2237
2238 if ( Target_static_playing ) {
2239 if (!Target_static_looping.isValid()) {
2240 Target_static_looping = snd_play_looping(gamesnd_get_game_sound(GameSounds::STATIC));
2241 }
2242 } else {
2243 if (Target_static_looping.isValid()) {
2244 snd_stop(Target_static_looping);
2245 Target_static_looping = sound_handle::invalid();
2246 }
2247 }
2248 }
2249
2250 /**
2251 * Updates the HUD status description of a particular ship
2252 *
2253 * Checks for disabled or ships with disrupted engines, as well as damage levels
2254 * of the target ship. If status has changed, then the HUD will flash
2255 *
2256 * @param targetp Instance of the ship target -- note the targetp->instance cannot be negative
2257 *
2258 */
hud_update_ship_status(object * targetp)2259 void hud_update_ship_status(object *targetp)
2260 {
2261 Assert( targetp != NULL );
2262 Assert( (targetp->instance >= 0) && (targetp->instance < MAX_SHIPS) );
2263
2264 if ( (targetp->instance >= 0) && (targetp->instance < MAX_SHIPS) ) {
2265 // print out status of ship for the targetbox
2266 if ( (Ships[targetp->instance].flags[Ship::Ship_Flags::Disabled]) || (ship_subsys_disrupted(&Ships[targetp->instance], SUBSYSTEM_ENGINE)) ) {
2267 Current_ts = TS_DIS;
2268 } else {
2269 if ( Pl_target_integrity > 0.9 ) {
2270 Current_ts = TS_OK;
2271 } else if ( Pl_target_integrity > 0.2 ) {
2272 Current_ts = TS_DMG;
2273 } else {
2274 Current_ts = TS_CRT;
2275 }
2276 }
2277
2278 if ( Last_ts != -1 && Current_ts != Last_ts ) {
2279 hud_targetbox_start_flash(TBOX_FLASH_STATUS);
2280 }
2281 }
2282
2283 Last_ts = Current_ts;
2284 }
2285
2286 /**
2287 * Start the targetbox item flashing for duration ms
2288 *
2289 * @param index TBOX_FLASH_ define
2290 * @param duration optional param (default value TBOX_FLASH_DURATION), how long to flash in ms
2291 */
hud_targetbox_start_flash(int index,int duration)2292 void hud_targetbox_start_flash(int index, int duration)
2293 {
2294 Targetbox_flash_timers[index] = timestamp(duration);
2295 }
2296
2297 /**
2298 * Stop flashing a specific targetbox item
2299 */
hud_targetbox_end_flash(int index)2300 void hud_targetbox_end_flash(int index)
2301 {
2302 Targetbox_flash_timers[index] = timestamp(0);
2303 }
2304
pageIn()2305 void HudGaugeTargetBox::pageIn()
2306 {
2307 bm_page_in_aabitmap( Monitor_frame.first_frame, Monitor_frame.num_frames);
2308
2309 bm_page_in_aabitmap( Integrity_bar.first_frame, Integrity_bar.num_frames );
2310 }
2311