mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 12:41:47 -10:00
Currently `$Closeup_Pos:` and `$Closeup_Zoom:` control the camera zoom and position values for the techroom, briefing and HUD Target Box. Unfortunately, with very large ships this results in an issue, to fit the view of an entire big ship in the HUD Target Box the zoom and position must be set a certain way which results in the ship looking very far away when viewed in the techroom. This PR adds two new fields that control camera postion and zoom but only for the HUD Target Box, thus modders can now set values for both and have the ships look good in both the Techroom and HUD Target Box. The new hud target box values are optional, and if not specifed they default to the values for `$Closeup_Pos:` and `$Closeup_Zoom:` .
2314 lines
64 KiB
C++
2314 lines
64 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#include "asteroid/asteroid.h"
|
|
#include "cmdline/cmdline.h"
|
|
#include "debris/debris.h"
|
|
#include "freespace.h"
|
|
#include "gamesnd/gamesnd.h"
|
|
#include "graphics/matrix.h"
|
|
#include "hud/hudbrackets.h"
|
|
#include "hud/hudtargetbox.h"
|
|
#include "iff_defs/iff_defs.h"
|
|
#include "io/timer.h"
|
|
#include "jumpnode/jumpnode.h"
|
|
#include "localization/localize.h"
|
|
#include "mission/missionparse.h"
|
|
#include "model/model.h"
|
|
#include "network/multi.h"
|
|
#include "object/object.h"
|
|
#include "object/objectdock.h"
|
|
#include "parse/parselo.h"
|
|
#include "playerman/player.h"
|
|
#include "ship/ship.h"
|
|
#include "ship/subsysdamage.h"
|
|
#include "species_defs/species_defs.h"
|
|
#include "weapon/emp.h"
|
|
#include "weapon/weapon.h"
|
|
|
|
#ifndef NDEBUG
|
|
#include "hud/hudets.h"
|
|
#endif
|
|
|
|
|
|
extern float View_zoom;
|
|
|
|
int Target_window_coords[GR_NUM_RESOLUTIONS][4] =
|
|
{
|
|
{ // GR_640
|
|
8, 362, 131, 112
|
|
},
|
|
{ // GR_1024
|
|
8, 629, 131, 112
|
|
}
|
|
};
|
|
|
|
object *Enemy_attacker = NULL;
|
|
|
|
static int Target_static_next;
|
|
static int Target_static_playing;
|
|
sound_handle Target_static_looping = sound_handle::invalid();
|
|
|
|
int Target_display_cargo;
|
|
char Cargo_string[256] = "";
|
|
|
|
#ifndef NDEBUG
|
|
extern int Show_target_debug_info;
|
|
extern int Show_target_weapons;
|
|
#endif
|
|
|
|
// used to print out + or - after target distance and speed
|
|
const char* modifiers[] = {
|
|
//XSTR:OFF
|
|
"+",
|
|
"-",
|
|
""
|
|
//XSTR:ON
|
|
};
|
|
|
|
#define NUM_TBOX_COORDS 11 // keep up to date
|
|
#define TBOX_BACKGROUND 0
|
|
#define TBOX_NAME 1
|
|
#define TBOX_CLASS 2
|
|
#define TBOX_DIST 3
|
|
#define TBOX_SPEED 4
|
|
#define TBOX_CARGO 5
|
|
#define TBOX_HULL 6
|
|
#define TBOX_EXTRA 7
|
|
#define TBOX_EXTRA_ORDERS 8
|
|
#define TBOX_EXTRA_TIME 9
|
|
#define TBOX_EXTRA_DOCK 10
|
|
|
|
// cargo scanning extents
|
|
int Cargo_scan_coords[GR_NUM_RESOLUTIONS][4] = {
|
|
{ // GR_640
|
|
7, 364, 130, 109
|
|
},
|
|
{ // GR_1024
|
|
7, 635, 130, 109
|
|
}
|
|
};
|
|
|
|
// first element is time flashing expires
|
|
int Targetbox_flash_timers[NUM_TBOX_FLASH_TIMERS];
|
|
|
|
int Targetbox_wire = 0;
|
|
int Targetbox_shader_effect = -1;
|
|
bool Lock_targetbox_mode = false;
|
|
|
|
// Different target states. This drives the text display right below the hull integrity on the targetbox.
|
|
#define TS_DIS 0
|
|
#define TS_OK 1
|
|
#define TS_DMG 2
|
|
#define TS_CRT 3
|
|
|
|
static int Current_ts; // holds current target status
|
|
static int Last_ts; // holds last target status.
|
|
|
|
/**
|
|
* @note Cut down long subsystem names to a more manageable length
|
|
*/
|
|
void hud_targetbox_truncate_subsys_name(char *outstr)
|
|
{
|
|
if(Lcl_gr){
|
|
if ( strstr(outstr, "communication") ) {
|
|
strcpy(outstr, "Komm");
|
|
} else if ( !stricmp(outstr, "weapons") ) {
|
|
strcpy(outstr, "Waffen");
|
|
} else if ( strstr(outstr, "engine") || strstr(outstr, "Engine")) {
|
|
strcpy(outstr, "Antrieb");
|
|
} else if ( !stricmp(outstr, "sensors") ) {
|
|
strcpy(outstr, "Sensoren");
|
|
} else if ( strstr(outstr, "navigat") ) {
|
|
strcpy(outstr, "Nav");
|
|
} else if ( strstr(outstr, "fighterbay") || strstr(outstr, "Fighterbay") ) {
|
|
strcpy(outstr, "J\x84gerhangar");
|
|
} else if ( strstr(outstr, "missile") ) {
|
|
strcpy(outstr, "Raketenwerfer");
|
|
} else if ( strstr(outstr, "laser") || strstr(outstr, "turret") ) {
|
|
strcpy(outstr, "Gesch\x81tzturm");
|
|
} else if ( strstr(outstr, "Command Tower") || strstr(outstr, "Bridge") ) {
|
|
strcpy(outstr, "Br\x81""cke");
|
|
} else if ( strstr(outstr, "Barracks") ) {
|
|
strcpy(outstr, "Quartiere");
|
|
} else if ( strstr(outstr, "Reactor") ) {
|
|
strcpy(outstr, "Reaktor");
|
|
} else if ( strstr(outstr, "RadarDish") ) {
|
|
strcpy(outstr, "Radarantenne");
|
|
} else if (!stricmp(outstr, "Gas Collector")) {
|
|
strcpy(outstr, "Sammler");
|
|
}
|
|
} else if(Lcl_fr){
|
|
if ( strstr(outstr, "communication") ) {
|
|
strcpy(outstr, "comm");
|
|
} else if ( !stricmp(outstr, "weapons") ) {
|
|
strcpy(outstr, "armes");
|
|
} else if ( strstr(outstr, "engine") ) {
|
|
strcpy(outstr, "moteur");
|
|
} else if ( !stricmp(outstr, "sensors") ) {
|
|
strcpy(outstr, "detecteurs");
|
|
} else if ( strstr(outstr, "navi") ) {
|
|
strcpy(outstr, "nav");
|
|
} else if ( strstr(outstr, "missile") ) {
|
|
strcpy(outstr, "lanceur de missiles");
|
|
} else if ( strstr(outstr, "fighter") ) {
|
|
strcpy(outstr, "baie de chasse");
|
|
} else if ( strstr(outstr, "laser") || strstr(outstr, "turret") || strstr(outstr, "missile") ) {
|
|
strcpy(outstr, "tourelle");
|
|
}
|
|
} else if(Lcl_pl){
|
|
if ( strstr(outstr, "communication") ) {
|
|
strcpy(outstr, "komunikacja");
|
|
} else if ( !stricmp(outstr, "weapons") ) {
|
|
strcpy(outstr, "uzbrojenie");
|
|
} else if ( strstr(outstr, "engine") || strstr(outstr, "Engine")) {
|
|
strcpy(outstr, "silnik");
|
|
} else if ( !stricmp(outstr, "sensors") ) {
|
|
strcpy(outstr, "sensory");
|
|
} else if ( strstr(outstr, "navigat") ) {
|
|
strcpy(outstr, "nawigacja");
|
|
} else if ( strstr(outstr, "fighterbay") || strstr(outstr, "Fighterbay") ) {
|
|
strcpy(outstr, "dok my\x9Cliw.");
|
|
} else if ( strstr(outstr, "missile") ) {
|
|
strcpy(outstr, "wie\xBF. rakiet.");
|
|
} else if ( strstr(outstr, "laser") || strstr(outstr, "turret") ) {
|
|
strcpy(outstr, "wie\xBFyczka");
|
|
} else if ( strstr(outstr, "Command Tower") || strstr(outstr, "Bridge") ) {
|
|
strcpy(outstr, "mostek");
|
|
} else if ( strstr(outstr, "Barracks") ) {
|
|
strcpy(outstr, "koszary");
|
|
} else if ( strstr(outstr, "Reactor") ) {
|
|
strcpy(outstr, "reaktor");
|
|
} else if ( strstr(outstr, "RadarDish") || strstr(outstr, "Radar Dish") ) {
|
|
strcpy(outstr, "antena radaru");
|
|
} else if (!stricmp(outstr, "Gas Collector")) {
|
|
strcpy(outstr, "zbieracz gazu");
|
|
}
|
|
} else {
|
|
if (strstr(outstr, XSTR("communication", 333))) {
|
|
strcpy(outstr, XSTR("comm", 334));
|
|
} else if (strstr(outstr, XSTR("navigation", 335))) {
|
|
strcpy(outstr, XSTR("nav", 336));
|
|
} else if (strstr(outstr, "gas collector")) {
|
|
strcpy(outstr, "collector");
|
|
}
|
|
}
|
|
}
|
|
|
|
HudGaugeTargetBox::HudGaugeTargetBox():
|
|
HudGauge(HUD_OBJECT_TARGET_MONITOR, HUD_TARGET_MONITOR, false, false, (VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY), 255, 255, 255),
|
|
Monitor_mask(-1),
|
|
Use_subsys_name_offsets(false),
|
|
Use_subsys_integrity_offsets(false),
|
|
Use_disabled_status_offsets(false)
|
|
{
|
|
}
|
|
|
|
void HudGaugeTargetBox::initViewportOffsets(int x, int y)
|
|
{
|
|
Viewport_offsets[0] = x;
|
|
Viewport_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initViewportSize(int w, int h)
|
|
{
|
|
Viewport_w = w;
|
|
Viewport_h = h;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initIntegrityOffsets(int x, int y)
|
|
{
|
|
Integrity_bar_offsets[0] = x;
|
|
Integrity_bar_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initIntegrityHeight(int h)
|
|
{
|
|
integrity_bar_h = h;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initStatusOffsets(int x, int y)
|
|
{
|
|
Status_offsets[0] = x;
|
|
Status_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initNameOffsets(int x, int y)
|
|
{
|
|
Name_offsets[0] = x;
|
|
Name_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initClassOffsets(int x, int y)
|
|
{
|
|
Class_offsets[0] = x;
|
|
Class_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initDistOffsets(int x, int y)
|
|
{
|
|
Dist_offsets[0] = x;
|
|
Dist_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initSpeedOffsets(int x, int y)
|
|
{
|
|
Speed_offsets[0] = x;
|
|
Speed_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initCargoStringOffsets(int x, int y)
|
|
{
|
|
Cargo_string_offsets[0] = x;
|
|
Cargo_string_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initHullOffsets(int x, int y)
|
|
{
|
|
Hull_offsets[0] = x;
|
|
Hull_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initCargoScanStartOffsets(int x, int y)
|
|
{
|
|
Cargo_scan_start_offsets[0] = x;
|
|
Cargo_scan_start_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initCargoScanSize(int w, int h)
|
|
{
|
|
Cargo_scan_w = w;
|
|
Cargo_scan_h = h;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initSubsysNameOffsets(int x, int y, bool activate)
|
|
{
|
|
Subsys_name_offsets[0] = x;
|
|
Subsys_name_offsets[1] = y;
|
|
Use_subsys_name_offsets = activate;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initSubsysIntegrityOffsets(int x, int y, bool activate)
|
|
{
|
|
Subsys_integrity_offsets[0] = x;
|
|
Subsys_integrity_offsets[1] = y;
|
|
Use_subsys_integrity_offsets = activate;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initDisabledStatusOffsets(int x, int y, bool activate)
|
|
{
|
|
Disabled_status_offsets[0] = x;
|
|
Disabled_status_offsets[1] = y;
|
|
Use_disabled_status_offsets = activate;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initDesaturate(bool desaturate)
|
|
{
|
|
Desaturated = desaturate;
|
|
}
|
|
|
|
void HudGaugeTargetBox::initBitmaps(char *fname_monitor, char *fname_monitor_mask, char *fname_integrity, char *fname_static)
|
|
{
|
|
Monitor_frame.first_frame = bm_load_animation(fname_monitor, &Monitor_frame.num_frames);
|
|
if ( Monitor_frame.first_frame < 0 ) {
|
|
Warning(LOCATION,"Cannot load hud ani: %s\n", fname_monitor);
|
|
}
|
|
|
|
Integrity_bar.first_frame = bm_load_animation(fname_integrity, &Integrity_bar.num_frames);
|
|
if ( Integrity_bar.first_frame < 0 ) {
|
|
Warning(LOCATION,"Cannot load hud ani: %s\n", fname_integrity);
|
|
}
|
|
|
|
if ( strlen(fname_monitor_mask) > 0 ) {
|
|
Monitor_mask = bm_load_animation(fname_monitor_mask);
|
|
|
|
if ( Monitor_mask < 0 ) {
|
|
Warning(LOCATION, "Cannot load bitmap hud mask: %s\n", fname_monitor_mask);
|
|
}
|
|
}
|
|
|
|
strcpy_s(static_fname, fname_static);
|
|
}
|
|
|
|
void HudGaugeTargetBox::initialize()
|
|
{
|
|
hud_anim_init(&Monitor_static, position[0] + Viewport_offsets[0], position[1] + Viewport_offsets[1], NOX(static_fname));
|
|
|
|
for(int i = 0; i < NUM_TBOX_FLASH_TIMERS; i++) {
|
|
initFlashTimer(i);
|
|
}
|
|
|
|
HudGauge::initialize();
|
|
}
|
|
|
|
void HudGaugeTargetBox::initFlashTimer(int index)
|
|
{
|
|
Next_flash_timers[index] = 1;
|
|
flash_flags &= ~(1<<index);
|
|
}
|
|
|
|
void HudGaugeTargetBox::render(float frametime)
|
|
{
|
|
object *target_objp;
|
|
|
|
if ( Player_ai->target_objnum == -1)
|
|
return;
|
|
|
|
if ( Target_static_playing )
|
|
return;
|
|
|
|
target_objp = &Objects[Player_ai->target_objnum];
|
|
|
|
setGaugeColor();
|
|
|
|
// blit the background frame
|
|
renderBitmap(Monitor_frame.first_frame, position[0], position[1]);
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
// render the alpha mask
|
|
gr_alpha_mask_set(1, 0.5f);
|
|
gr_stencil_clear();
|
|
gr_stencil_set(GR_STENCIL_WRITE);
|
|
gr_set_color_buffer(0);
|
|
|
|
renderBitmapColor(Monitor_mask, position[0], position[1]);
|
|
|
|
gr_set_color_buffer(1);
|
|
gr_stencil_set(GR_STENCIL_NONE);
|
|
gr_alpha_mask_set(0, 1.0f);
|
|
}
|
|
|
|
switch ( target_objp->type ) {
|
|
case OBJ_SHIP:
|
|
renderTargetShip(target_objp);
|
|
break;
|
|
|
|
case OBJ_DEBRIS:
|
|
renderTargetDebris(target_objp);
|
|
break;
|
|
|
|
case OBJ_WEAPON:
|
|
renderTargetWeapon(target_objp);
|
|
break;
|
|
|
|
case OBJ_ASTEROID:
|
|
renderTargetAsteroid(target_objp);
|
|
break;
|
|
|
|
case OBJ_JUMP_NODE:
|
|
renderTargetJumpNode(target_objp);
|
|
break;
|
|
|
|
default:
|
|
hud_cease_targeting();
|
|
break;
|
|
} // end switch
|
|
|
|
if ( Target_static_playing ) {
|
|
setGaugeColor();
|
|
gr_set_screen_scale(base_w, base_h);
|
|
hud_anim_render(&Monitor_static, frametime, 1);
|
|
gr_reset_screen_scale();
|
|
} else {
|
|
showTargetData(frametime);
|
|
}
|
|
|
|
if(Target_display_cargo) {
|
|
// Print out what the cargo is
|
|
if ( maybeFlashSexp() == 1 ) {
|
|
setGaugeColor(HUD_C_BRIGHT);
|
|
} else {
|
|
maybeFlashElement(TBOX_FLASH_CARGO);
|
|
}
|
|
|
|
renderString(position[0] + Cargo_string_offsets[0], position[1] + Cargo_string_offsets[1], EG_TBOX_CARGO, Cargo_string);
|
|
}
|
|
}
|
|
|
|
void HudGaugeTargetBox::renderTargetForeground()
|
|
{
|
|
setGaugeColor();
|
|
|
|
renderBitmap(Monitor_frame.first_frame+1, position[0], position[1]);
|
|
}
|
|
|
|
/**
|
|
* Draw the integrity bar that is on the right of the target monitor
|
|
*/
|
|
void HudGaugeTargetBox::renderTargetIntegrity(int disabled,int force_obj_num)
|
|
{
|
|
int clip_h,w,h;
|
|
char buf[16];
|
|
|
|
if ( Integrity_bar.first_frame == -1 )
|
|
return;
|
|
|
|
if ( disabled ) {
|
|
renderBitmap(Integrity_bar.first_frame, position[0] + Integrity_bar_offsets[0], position[1] + Integrity_bar_offsets[1]);
|
|
return;
|
|
}
|
|
|
|
if(force_obj_num == -1)
|
|
Assert(Player_ai->target_objnum >= 0 );
|
|
|
|
clip_h = fl2i( (1 - Pl_target_integrity) * integrity_bar_h );
|
|
|
|
// print out status of ship
|
|
switch(Current_ts) {
|
|
case TS_DIS:
|
|
strcpy_s(buf,XSTR( "dis", 344));
|
|
break;
|
|
case TS_OK:
|
|
strcpy_s(buf,XSTR( "ok", 345));
|
|
break;
|
|
case TS_DMG:
|
|
strcpy_s(buf,XSTR( "dmg", 346));
|
|
break;
|
|
case TS_CRT:
|
|
strcpy_s(buf,XSTR( "crt", 347));
|
|
break;
|
|
}
|
|
|
|
maybeFlashElement(TBOX_FLASH_STATUS);
|
|
|
|
// finally print out the status of this ship
|
|
renderString(position[0] + Status_offsets[0], position[1] + Status_offsets[1], EG_TBOX_INTEG, buf);
|
|
|
|
setGaugeColor();
|
|
|
|
bm_get_info(Integrity_bar.first_frame,&w,&h);
|
|
|
|
if ( clip_h > 0 ) {
|
|
// draw the dark portion
|
|
renderBitmapEx(Integrity_bar.first_frame, position[0] + Integrity_bar_offsets[0], position[1] + Integrity_bar_offsets[1], w, clip_h,0,0);
|
|
}
|
|
|
|
if ( clip_h <= integrity_bar_h ) {
|
|
// draw the bright portion
|
|
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);
|
|
}
|
|
}
|
|
|
|
void HudGaugeTargetBox::renderTargetSetup(vec3d *camera_eye, matrix *camera_orient, float zoom)
|
|
{
|
|
// JAS: g3_start_frame uses clip_width and clip_height to determine the
|
|
// size to render to. Normally, you would set this by using gr_set_clip,
|
|
// but because of the hacked in hud jittering, I couldn't. So come talk
|
|
// to me before modifying or reusing the following code. Thanks.
|
|
|
|
int clip_width = Viewport_w;
|
|
int clip_height = Viewport_h;
|
|
|
|
gr_screen.clip_width = clip_width;
|
|
gr_screen.clip_height = clip_height;
|
|
g3_start_frame(1); // Turn on zbuffering
|
|
hud_save_restore_camera_data(1);
|
|
g3_set_view_matrix( camera_eye, camera_orient, zoom);
|
|
model_set_detail_level(1); // use medium detail level
|
|
|
|
setClip(position[0] + Viewport_offsets[0], position[1] + Viewport_offsets[1], Viewport_w, Viewport_h);
|
|
|
|
// account for gauge RTT with cockpit here --wookieejedi
|
|
float clip_aspect;
|
|
if (gr_screen.rendering_to_texture != -1) {
|
|
clip_aspect = (i2fl(clip_width) / i2fl(clip_height));
|
|
} else {
|
|
clip_aspect = gr_screen.clip_aspect;
|
|
}
|
|
|
|
gr_set_proj_matrix(Proj_fov, clip_aspect, Min_draw_distance, Max_draw_distance);
|
|
gr_set_view_matrix(&Eye_position, &Eye_matrix);
|
|
}
|
|
|
|
void HudGaugeTargetBox::renderTargetShip(object *target_objp)
|
|
{
|
|
vec3d obj_pos = ZERO_VECTOR;
|
|
vec3d camera_eye = ZERO_VECTOR;
|
|
matrix camera_orient = IDENTITY_MATRIX;
|
|
ship *target_shipp;
|
|
ship_info *target_sip;
|
|
vec3d orient_vec, up_vector;
|
|
int sx, sy;
|
|
int subsys_in_view;
|
|
float factor;
|
|
|
|
target_shipp = &Ships[target_objp->instance];
|
|
target_sip = &Ship_info[target_shipp->ship_info_index];
|
|
|
|
int flags=0;
|
|
if ( Detail.targetview_model ) {
|
|
// take the forward orientation to be the vector from the player to the current target
|
|
vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
|
|
vm_vec_normalize(&orient_vec);
|
|
|
|
factor = -target_sip->closeup_pos_targetbox.xyz.z;
|
|
|
|
// use the player's up vector, and construct the viewers orientation matrix
|
|
if (Player_obj->type == OBJ_SHIP) {
|
|
vec3d tempv;
|
|
ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
|
|
} else {
|
|
camera_orient = Player_obj->orient;
|
|
}
|
|
|
|
up_vector = camera_orient.vec.uvec;
|
|
vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
|
|
|
|
// normalize the vector from the player to the current target, and scale by a factor to calculate
|
|
// the objects position
|
|
vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
|
|
|
|
// RT, changed scaling here
|
|
renderTargetSetup(&camera_eye, &camera_orient, target_sip->closeup_zoom_targetbox);
|
|
|
|
// IMPORTANT NOTE! Code handling the case 'missile_view == TRUE' in rendering section of renderTargetWeapon()
|
|
// is largely copied over from renderTargetShip(). To keep the codes similar please update
|
|
// both if and when needed
|
|
model_render_params render_info;
|
|
render_info.set_object_number(OBJ_INDEX(target_objp));
|
|
|
|
switch (Targetbox_wire) {
|
|
case 0:
|
|
flags |= MR_NO_LIGHTING;
|
|
|
|
break;
|
|
case 1:
|
|
if (ship_is_tagged(target_objp))
|
|
render_info.set_color(*iff_get_color(IFF_COLOR_TAGGED, 1));
|
|
else
|
|
render_info.set_color(*iff_get_color_by_team_and_object(target_shipp->team, Player_ship->team, 1, target_objp));
|
|
|
|
if (target_sip->uses_team_colors) {
|
|
render_info.set_team_color(target_shipp->team_name, target_shipp->secondary_team_name, target_shipp->team_change_timestamp, target_shipp->team_change_time);
|
|
}
|
|
|
|
flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
if (ship_is_tagged(target_objp))
|
|
render_info.set_color(*iff_get_color(IFF_COLOR_TAGGED, 1));
|
|
else
|
|
render_info.set_color(*iff_get_color_by_team_and_object(target_shipp->team, Player_ship->team, 1, target_objp));
|
|
|
|
flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
}
|
|
|
|
if (target_sip->hud_target_lod >= 0) {
|
|
render_info.set_detail_level_lock(target_sip->hud_target_lod);
|
|
}
|
|
|
|
if(Targetbox_shader_effect > -1) {
|
|
render_info.set_animated_effect(Targetbox_shader_effect, 0.0f);
|
|
}
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_READ);
|
|
}
|
|
|
|
if ( Desaturated ) {
|
|
flags |= MR_DESATURATED;
|
|
render_info.set_color(gauge_color);
|
|
}
|
|
|
|
if (!Glowpoint_override)
|
|
Glowpoint_override = true;
|
|
|
|
// set glowmap flag here since model_render (etc) require an objnum to handle glowmaps
|
|
// if we did pass the objnum, we'd also have thrusters drawn in the targetbox
|
|
if (target_shipp->flags[Ship::Ship_Flags::Glowmaps_disabled]) {
|
|
flags |= MR_NO_GLOWMAPS;
|
|
}
|
|
|
|
render_info.set_flags(flags | MR_AUTOCENTER | MR_NO_FOGGING);
|
|
|
|
// maybe render a special hud-target-only model
|
|
if(target_sip->model_num_hud >= 0){
|
|
model_render_immediate( &render_info, target_sip->model_num_hud, &target_objp->orient, &obj_pos);
|
|
} else {
|
|
render_info.set_replacement_textures(target_shipp->ship_replacement_textures);
|
|
|
|
model_render_immediate( &render_info, target_sip->model_num, &target_objp->orient, &obj_pos);
|
|
}
|
|
|
|
Glowpoint_override = false;
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_NONE);
|
|
}
|
|
|
|
sx = 0;
|
|
sy = 0;
|
|
// check if subsystem target has changed
|
|
if ( Player_ai->targeted_subsys == Player_ai->last_subsys_target ) {
|
|
vec3d save_pos;
|
|
|
|
if (gr_screen.rendering_to_texture != -1) {
|
|
gr_set_screen_scale(canvas_w, canvas_h, -1, -1, target_w, target_h, target_w, target_h, true);
|
|
} else {
|
|
gr_set_screen_scale(base_w, base_h);
|
|
}
|
|
|
|
save_pos = target_objp->pos;
|
|
target_objp->pos = obj_pos;
|
|
subsys_in_view = hud_targetbox_subsystem_in_view(target_objp, &sx, &sy);
|
|
target_objp->pos = save_pos;
|
|
|
|
if ( subsys_in_view != -1 ) {
|
|
|
|
// AL 29-3-98: If subsystem is destroyed, draw gray brackets
|
|
// Goober5000 - hm, caught a tricky bug for destroyable fighterbays
|
|
if ( (Player_ai->targeted_subsys->current_hits <= 0) && ship_subsys_takes_damage(Player_ai->targeted_subsys) ) {
|
|
gr_set_color_fast(iff_get_color(IFF_COLOR_MESSAGE, 1));
|
|
} else {
|
|
hud_set_iff_color( target_objp, 1 );
|
|
}
|
|
|
|
graphics::line_draw_list line_draw_list;
|
|
if ( subsys_in_view ) {
|
|
draw_brackets_square_quick(&line_draw_list, sx - 10, sy - 10, sx + 10, sy + 10);
|
|
} else {
|
|
draw_brackets_diamond_quick(&line_draw_list, sx - 10, sy - 10, sx + 10, sy + 10);
|
|
}
|
|
line_draw_list.flush();
|
|
}
|
|
}
|
|
renderTargetClose();
|
|
}
|
|
renderTargetForeground();
|
|
renderTargetIntegrity(0,OBJ_INDEX(target_objp));
|
|
|
|
setGaugeColor();
|
|
|
|
renderTargetShipInfo(target_objp);
|
|
maybeRenderCargoScan(target_sip);
|
|
}
|
|
|
|
/**
|
|
* @note formerly hud_render_target_debris(object *target_objp) (Swifty)
|
|
*/
|
|
void HudGaugeTargetBox::renderTargetDebris(object *target_objp)
|
|
{
|
|
vec3d obj_pos = ZERO_VECTOR;
|
|
vec3d camera_eye = ZERO_VECTOR;
|
|
matrix camera_orient = IDENTITY_MATRIX;
|
|
debris *debrisp;
|
|
vec3d orient_vec, up_vector;
|
|
float factor;
|
|
int flags=0;
|
|
|
|
debrisp = &Debris[target_objp->instance];
|
|
|
|
if ( Detail.targetview_model ) {
|
|
// take the forward orientation to be the vector from the player to the current target
|
|
vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
|
|
vm_vec_normalize(&orient_vec);
|
|
|
|
factor = 2*target_objp->radius;
|
|
|
|
// use the player's up vector, and construct the viewers orientation matrix
|
|
if (Player_obj->type == OBJ_SHIP) {
|
|
vec3d tempv;
|
|
ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
|
|
} else {
|
|
camera_orient = Player_obj->orient;
|
|
}
|
|
|
|
up_vector = camera_orient.vec.uvec;
|
|
vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
|
|
|
|
// normalize the vector from the player to the current target, and scale by a factor to calculate
|
|
// the objects position
|
|
vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
|
|
|
|
renderTargetSetup(&camera_eye, &camera_orient, 0.5f);
|
|
model_clear_instance(debrisp->model_num);
|
|
|
|
model_render_params render_info;
|
|
|
|
switch (Targetbox_wire) {
|
|
case 0:
|
|
flags |= MR_NO_LIGHTING;
|
|
|
|
break;
|
|
case 1:
|
|
render_info.set_color(255, 255, 255);
|
|
|
|
flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
render_info.set_color(255, 255, 255);
|
|
|
|
flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
}
|
|
|
|
if(Targetbox_shader_effect > -1) {
|
|
render_info.set_animated_effect(Targetbox_shader_effect, 0.0f);
|
|
}
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_READ);
|
|
}
|
|
|
|
if ( Desaturated ) {
|
|
flags |= MR_DESATURATED;
|
|
render_info.set_color(gauge_color);
|
|
}
|
|
|
|
render_info.set_flags(flags | MR_NO_FOGGING);
|
|
|
|
// This calls the colour that doesn't get reset
|
|
submodel_render_immediate( &render_info, debrisp->model_num, debrisp->submodel_num, &target_objp->orient, &obj_pos);
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_NONE);
|
|
}
|
|
|
|
renderTargetClose();
|
|
}
|
|
renderTargetForeground();
|
|
renderTargetIntegrity(1);
|
|
|
|
// print out ship class that debris came from
|
|
char printable_ship_class[NAME_LENGTH];
|
|
if (debrisp->parent_alt_name >= 0)
|
|
mission_parse_lookup_alt_index(debrisp->parent_alt_name, printable_ship_class);
|
|
else
|
|
strcpy_s(printable_ship_class, (Ship_info[debrisp->ship_info_index].alt_name[0]) ? Ship_info[debrisp->ship_info_index].alt_name : Ship_info[debrisp->ship_info_index].name);
|
|
|
|
end_string_at_first_hash_symbol(printable_ship_class);
|
|
|
|
renderString(position[0] + Class_offsets[0], position[1] + Class_offsets[1], EG_TBOX_CLASS, printable_ship_class);
|
|
renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, XSTR("Debris", 348));
|
|
}
|
|
|
|
/**
|
|
* @note Formerly hud_render_target_weapon(object *target_objp)
|
|
*/
|
|
void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
|
|
{
|
|
vec3d obj_pos = ZERO_VECTOR;
|
|
vec3d camera_eye = ZERO_VECTOR;
|
|
matrix camera_orient = IDENTITY_MATRIX;
|
|
vec3d orient_vec, up_vector;
|
|
vec3d projection_vec;
|
|
weapon_info *target_wip = NULL;
|
|
weapon *wp = NULL;
|
|
object *viewer_obj, *viewed_obj;
|
|
int *replacement_textures = NULL;
|
|
int target_team, is_homing, is_player_missile, missile_view, viewed_model_num, hud_target_lod, w, h;
|
|
char outstr[100]; // temp buffer
|
|
int flags=0;
|
|
|
|
target_team = obj_team(target_objp);
|
|
|
|
wp = &Weapons[target_objp->instance];
|
|
target_wip = &Weapon_info[wp->weapon_info_index];
|
|
|
|
if (target_wip->model_num == -1)
|
|
return;
|
|
|
|
is_homing = FALSE;
|
|
if ( target_wip->is_homing() && wp->homing_object != &obj_used_list )
|
|
is_homing = TRUE;
|
|
|
|
is_player_missile = FALSE;
|
|
if ( target_objp->parent_sig == Player_obj->signature ) {
|
|
is_player_missile = TRUE;
|
|
}
|
|
|
|
if ( Detail.targetview_model ) {
|
|
ship *homing_shipp = NULL;
|
|
ship_info *homing_sip = NULL;
|
|
|
|
viewer_obj = Player_obj;
|
|
viewed_obj = target_objp;
|
|
missile_view = FALSE;
|
|
viewed_model_num = target_wip->model_num;
|
|
hud_target_lod = target_wip->hud_target_lod;
|
|
// adding a check here to make sure the homing object is a ship, technically it could be some other object just as well
|
|
if ( is_homing && is_player_missile && (wp->homing_object->type == OBJ_SHIP)) {
|
|
homing_shipp = &Ships[wp->homing_object->instance];
|
|
homing_sip = &Ship_info[homing_shipp->ship_info_index];
|
|
|
|
viewer_obj = target_objp;
|
|
viewed_obj = wp->homing_object;
|
|
missile_view = TRUE;
|
|
viewed_model_num = homing_sip->model_num;
|
|
replacement_textures = homing_shipp->ship_replacement_textures;
|
|
hud_target_lod = homing_sip->hud_target_lod;
|
|
}
|
|
|
|
// take the forward orientation to be the vector from the player to the current target
|
|
vm_vec_sub(&orient_vec, &viewed_obj->pos, &viewer_obj->pos);
|
|
vm_vec_normalize(&orient_vec);
|
|
|
|
if (missile_view == TRUE) {
|
|
vm_vec_sub(&projection_vec, &wp->homing_pos, &viewer_obj->pos);
|
|
vm_vec_normalize(&projection_vec);
|
|
}
|
|
|
|
// use the viewer's up vector, and construct the viewers orientation matrix
|
|
if (viewer_obj == Player_obj && Player_obj->type == OBJ_SHIP) {
|
|
vec3d tempv;
|
|
ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
|
|
} else {
|
|
camera_orient = viewer_obj->orient;
|
|
}
|
|
|
|
up_vector = camera_orient.vec.uvec;
|
|
|
|
if (missile_view == FALSE)
|
|
vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
|
|
else
|
|
vm_vector_2_matrix(&camera_orient,&projection_vec,&up_vector,NULL);
|
|
|
|
// normalize the vector from the viewer to the viwed target, and scale by a factor to calculate
|
|
// the objects position
|
|
if (missile_view == FALSE) {
|
|
float factor = 2*target_objp->radius;
|
|
// small radius missiles need a bigger factor otherwise they are rendered larger than the targetbox
|
|
if (factor < 8.0f) {
|
|
factor = 8.0f;
|
|
}
|
|
vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
|
|
} else {
|
|
vm_vec_sub(&obj_pos, &viewed_obj->pos, &viewer_obj->pos);
|
|
}
|
|
|
|
renderTargetSetup(&camera_eye, &camera_orient, View_zoom/3);
|
|
model_clear_instance(viewed_model_num);
|
|
|
|
model_render_params render_info;
|
|
|
|
// IMPORTANT NOTE! Code handling the rendering when 'missile_view == TRUE' is largely copied over from
|
|
// renderTargetShip(). To keep the codes similar please update both if and when needed
|
|
if (missile_view == FALSE) {
|
|
switch (Targetbox_wire) {
|
|
case 0:
|
|
flags |= MR_NO_LIGHTING;
|
|
|
|
break;
|
|
case 1:
|
|
render_info.set_color(*iff_get_color_by_team_and_object(target_team, Player_ship->team, 0, target_objp));
|
|
|
|
flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
render_info.set_color(*iff_get_color_by_team_and_object(target_team, Player_ship->team, 0, target_objp));
|
|
|
|
flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
}
|
|
} else {
|
|
render_info.set_object_number(OBJ_INDEX(viewed_obj));
|
|
|
|
switch (Targetbox_wire) {
|
|
case 0:
|
|
flags |= MR_NO_LIGHTING;
|
|
|
|
break;
|
|
case 1:
|
|
if (ship_is_tagged(viewed_obj))
|
|
render_info.set_color(*iff_get_color(IFF_COLOR_TAGGED, 1));
|
|
else
|
|
render_info.set_color(*iff_get_color_by_team_and_object(homing_shipp->team, Player_ship->team, 1, viewed_obj));
|
|
|
|
if (homing_sip->uses_team_colors) {
|
|
render_info.set_team_color(homing_shipp->team_name, homing_shipp->secondary_team_name, homing_shipp->team_change_timestamp, homing_shipp->team_change_time);
|
|
}
|
|
|
|
flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
if (ship_is_tagged(viewed_obj))
|
|
render_info.set_color(*iff_get_color(IFF_COLOR_TAGGED, 1));
|
|
else
|
|
render_info.set_color(*iff_get_color_by_team_and_object(homing_shipp->team, Player_ship->team, 1, viewed_obj));
|
|
|
|
flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (hud_target_lod >= 0) {
|
|
render_info.set_detail_level_lock(hud_target_lod);
|
|
}
|
|
|
|
if(Targetbox_shader_effect > -1) {
|
|
render_info.set_animated_effect(Targetbox_shader_effect, 0.0f);
|
|
}
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_READ);
|
|
}
|
|
|
|
if ( Desaturated ) {
|
|
flags |= MR_DESATURATED;
|
|
render_info.set_color(gauge_color);
|
|
}
|
|
|
|
if (missile_view == TRUE) {
|
|
if (!Glowpoint_override)
|
|
Glowpoint_override = true;
|
|
|
|
// set glowmap flag here since model_render (etc) require an objnum to handle glowmaps
|
|
// if we did pass the objnum, we'd also have thrusters drawn in the targetbox
|
|
if (homing_shipp->flags[Ship::Ship_Flags::Glowmaps_disabled]) {
|
|
flags |= MR_NO_GLOWMAPS;
|
|
}
|
|
}
|
|
|
|
if (missile_view == FALSE ) {
|
|
render_info.set_flags(flags | MR_AUTOCENTER | MR_IS_MISSILE | MR_NO_FOGGING);
|
|
render_info.set_replacement_textures(replacement_textures);
|
|
|
|
model_render_immediate( &render_info, viewed_model_num, &viewed_obj->orient, &obj_pos );
|
|
} else {
|
|
// maybe render a special hud-target-only model
|
|
// autocentering is bad in this one
|
|
if(homing_sip->model_num_hud >= 0){
|
|
render_info.set_flags(flags | MR_NO_FOGGING);
|
|
|
|
model_render_immediate( &render_info, homing_sip->model_num_hud, &viewed_obj->orient, &obj_pos);
|
|
} else {
|
|
render_info.set_flags(flags | MR_NO_FOGGING);
|
|
render_info.set_replacement_textures(homing_shipp->ship_replacement_textures);
|
|
|
|
model_render_immediate( &render_info, homing_sip->model_num, &viewed_obj->orient, &obj_pos );
|
|
}
|
|
}
|
|
|
|
if (missile_view == TRUE) {
|
|
Glowpoint_override = false;
|
|
}
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_NONE);
|
|
}
|
|
|
|
renderTargetClose();
|
|
}
|
|
renderTargetForeground();
|
|
|
|
renderTargetIntegrity(1);
|
|
setGaugeColor();
|
|
|
|
// print out the weapon class name
|
|
sprintf( outstr,"%s", target_wip->get_display_string() );
|
|
gr_get_string_size(&w,&h,outstr);
|
|
|
|
// drop name past the # sign
|
|
end_string_at_first_hash_symbol(outstr);
|
|
|
|
renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, outstr);
|
|
|
|
// If a homing weapon, show time to impact
|
|
if ( is_homing ) {
|
|
float dist, speed;
|
|
|
|
speed = vm_vec_mag(&target_objp->phys_info.vel);
|
|
|
|
// do the extra math only if it won't lead to null vec issues
|
|
if(!(IS_VEC_NULL_SQ_SAFE(&target_objp->phys_info.vel))){
|
|
vec3d unit_vec, component_vec;
|
|
|
|
// in other words substract the magnitude of the target's velocity vectors parallel component from the speed of the weapon
|
|
vm_vec_copy_normalize(&unit_vec, &target_objp->phys_info.vel);
|
|
speed -= vm_vec_projection_parallel(&component_vec, &wp->homing_object->phys_info.vel, &unit_vec);
|
|
}
|
|
|
|
dist = vm_vec_dist(&target_objp->pos, &wp->homing_pos);
|
|
|
|
if ( speed > 0 ) {
|
|
sprintf(outstr, XSTR("impact: %.1f sec", 1596), dist/speed);
|
|
} else {
|
|
strcpy_s(outstr, XSTR( "unknown", 349));
|
|
}
|
|
|
|
renderString(position[0] + Class_offsets[0], position[1] + Class_offsets[1], EG_TBOX_CLASS, outstr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @note Formerly hud_render_target_asteroid(object *target_objp)
|
|
*/
|
|
void HudGaugeTargetBox::renderTargetAsteroid(object *target_objp)
|
|
{
|
|
vec3d obj_pos = ZERO_VECTOR;
|
|
vec3d camera_eye = ZERO_VECTOR;
|
|
matrix camera_orient = IDENTITY_MATRIX;
|
|
asteroid *asteroidp;
|
|
vec3d orient_vec, up_vector;
|
|
float time_to_impact, factor;
|
|
int pof;
|
|
|
|
int flags=0; //draw flags for wireframe
|
|
asteroidp = &Asteroids[target_objp->instance];
|
|
|
|
pof = asteroidp->asteroid_subtype;
|
|
|
|
time_to_impact = asteroid_time_to_impact(target_objp);
|
|
|
|
if ( Detail.targetview_model ) {
|
|
// take the forward orientation to be the vector from the player to the current target
|
|
vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
|
|
vm_vec_normalize(&orient_vec);
|
|
|
|
factor = 2*target_objp->radius;
|
|
|
|
// use the player's up vector, and construct the viewers orientation matrix
|
|
if (Player_obj->type == OBJ_SHIP) {
|
|
vec3d tempv;
|
|
ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
|
|
} else {
|
|
camera_orient = Player_obj->orient;
|
|
}
|
|
|
|
up_vector = camera_orient.vec.uvec;
|
|
vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
|
|
|
|
// normalize the vector from the player to the current target, and scale by a factor to calculate
|
|
// the objects position
|
|
vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
|
|
|
|
renderTargetSetup(&camera_eye, &camera_orient, 0.5f);
|
|
model_clear_instance(Asteroid_info[asteroidp->asteroid_type].model_num[pof]);
|
|
|
|
model_render_params render_info;
|
|
|
|
switch (Targetbox_wire) {
|
|
case 0:
|
|
flags |= MR_NO_LIGHTING;
|
|
|
|
break;
|
|
case 1:
|
|
if (time_to_impact>=0)
|
|
render_info.set_color(255,255,255);
|
|
else
|
|
render_info.set_color(64,64,0);
|
|
|
|
flags = MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
if (time_to_impact>=0)
|
|
render_info.set_color(255,255,255);
|
|
else
|
|
render_info.set_color(64,64,0);
|
|
|
|
flags |= MR_NO_LIGHTING | MR_NO_TEXTURING;
|
|
|
|
break;
|
|
}
|
|
|
|
if(Targetbox_shader_effect > -1) {
|
|
render_info.set_animated_effect(Targetbox_shader_effect, 0.0f);
|
|
}
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_READ);
|
|
}
|
|
|
|
if ( Desaturated ) {
|
|
flags |= MR_DESATURATED;
|
|
render_info.set_color(gauge_color);
|
|
}
|
|
|
|
render_info.set_flags(flags | MR_NO_FOGGING);
|
|
|
|
model_render_immediate( &render_info, Asteroid_info[asteroidp->asteroid_type].model_num[pof], &target_objp->orient, &obj_pos );
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_NONE);
|
|
}
|
|
|
|
renderTargetClose();
|
|
}
|
|
renderTargetForeground();
|
|
renderTargetIntegrity(1);
|
|
setGaugeColor();
|
|
|
|
// hud print type of Asteroid (debris)
|
|
char hud_name[64];
|
|
switch (asteroidp->asteroid_type) {
|
|
case ASTEROID_TYPE_SMALL:
|
|
case ASTEROID_TYPE_MEDIUM:
|
|
case ASTEROID_TYPE_LARGE:
|
|
strcpy_s(hud_name, NOX("asteroid"));
|
|
break;
|
|
|
|
default:
|
|
sprintf(hud_name, NOX("%s debris"), Species_info[(asteroidp->asteroid_type / NUM_DEBRIS_SIZES) - 1].species_name);
|
|
break;
|
|
}
|
|
|
|
renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, hud_name);
|
|
|
|
|
|
if ( time_to_impact >= 0.0f ) {
|
|
renderPrintf(position[0] + Class_offsets[0], position[1] + Class_offsets[1], EG_TBOX_CLASS, NOX("impact: %.1f sec"), time_to_impact);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Render a jump node on the target monitor
|
|
* @note Formerly hud_render_target_jump_node(object *target_objp)
|
|
*/
|
|
void HudGaugeTargetBox::renderTargetJumpNode(object *target_objp)
|
|
{
|
|
char outstr[256];
|
|
vec3d obj_pos = ZERO_VECTOR;
|
|
vec3d camera_eye = ZERO_VECTOR;
|
|
matrix camera_orient = IDENTITY_MATRIX;
|
|
vec3d orient_vec, up_vector;
|
|
float factor, dist;
|
|
int hx, hy, w, h;
|
|
SCP_list<CJumpNode>::iterator jnp;
|
|
|
|
for (jnp = Jump_nodes.begin(); jnp != Jump_nodes.end(); ++jnp) {
|
|
if(jnp->GetSCPObject() != target_objp)
|
|
continue;
|
|
|
|
if ( jnp->IsHidden() ) {
|
|
set_target_objnum( Player_ai, -1 );
|
|
return;
|
|
}
|
|
|
|
if ( Detail.targetview_model ) {
|
|
// take the forward orientation to be the vector from the player to the current target
|
|
vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
|
|
vm_vec_normalize(&orient_vec);
|
|
|
|
factor = target_objp->radius*4.0f;
|
|
|
|
// use the player's up vector, and construct the viewers orientation matrix
|
|
if (Player_obj->type == OBJ_SHIP) {
|
|
vec3d tempv;
|
|
ship_get_eye(&tempv, &camera_orient, Player_obj, false, false);
|
|
} else {
|
|
camera_orient = Player_obj->orient;
|
|
}
|
|
|
|
up_vector = camera_orient.vec.uvec;
|
|
vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL);
|
|
|
|
// normalize the vector from the player to the current target, and scale by a factor to calculate
|
|
// the objects position
|
|
vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
|
|
|
|
renderTargetSetup(&camera_eye, &camera_orient, 0.5f);
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_READ);
|
|
}
|
|
|
|
jnp->Render( &obj_pos );
|
|
|
|
if ( Monitor_mask >= 0 ) {
|
|
gr_stencil_set(GR_STENCIL_NONE);
|
|
}
|
|
|
|
renderTargetClose();
|
|
}
|
|
|
|
renderTargetForeground();
|
|
renderTargetIntegrity(1);
|
|
setGaugeColor();
|
|
|
|
strcpy_s(outstr, jnp->GetName());
|
|
end_string_at_first_hash_symbol(outstr);
|
|
renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, outstr);
|
|
|
|
dist = Player_ai->current_target_distance;
|
|
if ( Hud_unit_multiplier > 0.0f ) { // use a different displayed distance scale
|
|
dist = dist * Hud_unit_multiplier;
|
|
}
|
|
|
|
// account for hud shaking
|
|
hx = fl2i(HUD_offset_x);
|
|
hy = fl2i(HUD_offset_y);
|
|
|
|
sprintf(outstr,XSTR( "d: %.0f", 340), dist);
|
|
hud_num_make_mono(outstr, font_num);
|
|
gr_get_string_size(&w,&h,outstr);
|
|
|
|
renderPrintf(position[0] + Dist_offsets[0]+hx, position[1] + Dist_offsets[1]+hy, EG_TBOX_DIST, "%s", outstr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggle through the valid targetbox modes
|
|
*
|
|
* @note 0==standard
|
|
* @note 1==wireframe only
|
|
* @note 2==standard with lighting
|
|
*/
|
|
void hud_targetbox_switch_wireframe_mode()
|
|
{
|
|
|
|
Targetbox_wire++;
|
|
if (Targetbox_wire==3)
|
|
Targetbox_wire=0;
|
|
}
|
|
|
|
/**
|
|
* Init a specific targetbox timer
|
|
*/
|
|
void hud_targetbox_init_flash_timer(int index)
|
|
{
|
|
Targetbox_flash_timers[index] = 1;
|
|
}
|
|
|
|
/**
|
|
* Init the timers used to flash different parts of the targetbox.
|
|
*
|
|
* @note This needs to get called whenever the current target changes.
|
|
* @note Need to call initFlashTimers for any TargetBox gauges and call initDockFlashTimer() for Extra Target Info gauges (Switfty)
|
|
*/
|
|
void hud_targetbox_init_flash()
|
|
{
|
|
for(int i = 0; i < NUM_TBOX_FLASH_TIMERS; i++) {
|
|
hud_targetbox_init_flash_timer(i);
|
|
}
|
|
|
|
Last_ts = -1;
|
|
Current_ts = -1;
|
|
}
|
|
|
|
int HudGaugeTargetBox::maybeFlashElement(int index, int flash_fast)
|
|
{
|
|
int draw_bright=0;
|
|
|
|
setGaugeColor();
|
|
if ( !timestamp_elapsed(Targetbox_flash_timers[index]) ) {
|
|
if ( timestamp_elapsed(Next_flash_timers[index]) ) {
|
|
if ( flash_fast ) {
|
|
Next_flash_timers[index] = timestamp(fl2i(TBOX_FLASH_INTERVAL/2.0f));
|
|
} else {
|
|
Next_flash_timers[index] = timestamp(TBOX_FLASH_INTERVAL);
|
|
}
|
|
flash_flags ^= (1<<index); // toggle between default and bright frames
|
|
}
|
|
|
|
if ( flash_flags & (1<<index) ) {
|
|
setGaugeColor(HUD_C_BRIGHT);
|
|
draw_bright=1;
|
|
} else {
|
|
setGaugeColor(HUD_C_DIM);
|
|
}
|
|
}
|
|
|
|
return draw_bright;
|
|
}
|
|
|
|
void HudGaugeTargetBox::renderTargetClose()
|
|
{
|
|
gr_end_view_matrix();
|
|
gr_end_proj_matrix();
|
|
|
|
g3_end_frame();
|
|
hud_save_restore_camera_data(0);
|
|
resetClip();
|
|
}
|
|
|
|
/**
|
|
* Get the shield and hull percentages for a given ship object
|
|
*
|
|
* @param objp Pointer to ship object that you want strength values for
|
|
* @param shields OUTPUT parameter: percentage value of shields (0->1.0)
|
|
* @param integrity OUTPUT parameter: percentage value of integrity (0->1.0)
|
|
*/
|
|
void hud_get_target_strength(object *objp, float *shields, float *integrity)
|
|
{
|
|
*shields = get_shield_pct(objp);
|
|
*integrity = get_hull_pct(objp);
|
|
}
|
|
|
|
HudGaugeExtraTargetData::HudGaugeExtraTargetData():
|
|
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)
|
|
{
|
|
initDockFlashTimer();
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initialize()
|
|
{
|
|
initDockFlashTimer();
|
|
|
|
HudGauge::initialize();
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initBracketOffsets(int x, int y)
|
|
{
|
|
bracket_offsets[0] = x;
|
|
bracket_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initDockOffsets(int x, int y)
|
|
{
|
|
dock_offsets[0] = x;
|
|
dock_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initDockMaxWidth(int width)
|
|
{
|
|
dock_max_w = width;
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initTimeOffsets(int x, int y)
|
|
{
|
|
time_offsets[0] = x;
|
|
time_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initOrderOffsets(int x, int y)
|
|
{
|
|
order_offsets[0] = x;
|
|
order_offsets[1] = y;
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initOrderMaxWidth(int width)
|
|
{
|
|
order_max_w = width;
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initBitmaps(char *fname)
|
|
{
|
|
bracket.first_frame = bm_load_animation(fname, &bracket.num_frames);
|
|
if ( bracket.first_frame < 0 ) {
|
|
Warning(LOCATION,"Cannot load hud ani: %s\n", fname);
|
|
}
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::pageIn()
|
|
{
|
|
bm_page_in_aabitmap( bracket.first_frame, bracket.num_frames );
|
|
}
|
|
|
|
/**
|
|
* @note Formerly hud_targetbox_show_extra_ship_info(target_shipp, target_objp) (Swifty)
|
|
*/
|
|
void HudGaugeExtraTargetData::render(float /*frametime*/)
|
|
{
|
|
char tmpbuf[256];
|
|
int has_orders = 0;
|
|
int not_training;
|
|
int extra_data_shown=0;
|
|
|
|
if(!canRender())
|
|
return;
|
|
|
|
if ( Player_ai->target_objnum == -1)
|
|
return;
|
|
|
|
if ( Target_static_playing )
|
|
return;
|
|
|
|
object *target_objp;
|
|
target_objp = &Objects[Player_ai->target_objnum];
|
|
|
|
// only render if this the current target is type OBJ_SHIP
|
|
if(target_objp->type != OBJ_SHIP)
|
|
return;
|
|
|
|
ship* target_shipp = &Ships[target_objp->instance];
|
|
|
|
setGaugeColor();
|
|
|
|
not_training = !(The_mission.game_type & MISSION_TYPE_TRAINING);
|
|
if ( not_training) {
|
|
// Print out current orders if the targeted ship is friendly
|
|
// AL 12-26-97: only show orders and time to target for friendly ships
|
|
// Backslash: actually let's consult the IFF table. Maybe we want to show orders for certain teams, or hide orders for friendlies
|
|
if ( ((Player_ship->team == target_shipp->team) ||
|
|
((Iff_info[target_shipp->team].flags & IFFF_ORDERS_SHOWN) && !(Iff_info[target_shipp->team].flags & IFFF_ORDERS_HIDDEN)))
|
|
&& Ship_info[target_shipp->ship_info_index].is_flyable() ) {
|
|
extra_data_shown = 1;
|
|
auto orders = ship_return_orders(target_shipp);
|
|
if (!orders.empty()) {
|
|
char outstr[256];
|
|
strcpy_s(outstr, orders.c_str());
|
|
font::force_fit_string(outstr, 255, order_max_w);
|
|
orders = outstr;
|
|
has_orders = 1;
|
|
} else {
|
|
orders = XSTR("no orders", 337);
|
|
}
|
|
|
|
renderString(position[0] + order_offsets[0], position[1] + order_offsets[1], EG_TBOX_EXTRA1, orders.c_str());
|
|
}
|
|
|
|
if ( has_orders ) {
|
|
char outstr[256];
|
|
strcpy_s(outstr, XSTR( "time to: ", 338));
|
|
if ( ship_return_time_to_goal(tmpbuf, target_shipp) ) {
|
|
strcat_s(outstr, tmpbuf);
|
|
|
|
renderString(position[0] + time_offsets[0], position[1] + time_offsets[1], EG_TBOX_EXTRA2, outstr);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Player_ai->last_target != Player_ai->target_objnum) {
|
|
endFlashDock();
|
|
}
|
|
|
|
// Print out dock status
|
|
if ( object_is_docked(target_objp) )
|
|
{
|
|
startFlashDock(2000);
|
|
// count the objects directly docked to me
|
|
int dock_count = dock_count_direct_docked_objects(target_objp);
|
|
|
|
char outstr[256];
|
|
// docked to only one object
|
|
if (dock_count == 1)
|
|
{
|
|
sprintf(outstr, XSTR("Docked: %s", 339), Ships[dock_get_first_docked_object(target_objp)->instance].get_display_string());
|
|
end_string_at_first_hash_symbol(outstr);
|
|
}
|
|
// docked to multiple objects
|
|
else
|
|
{
|
|
sprintf(outstr, XSTR("Docked: %d objects", 1623), dock_count);
|
|
}
|
|
|
|
font::force_fit_string(outstr, 255, dock_max_w);
|
|
maybeFlashDock();
|
|
|
|
renderString(position[0] + dock_offsets[0], position[1] + dock_offsets[1], EG_TBOX_EXTRA3, outstr);
|
|
extra_data_shown=1;
|
|
}
|
|
|
|
if ( extra_data_shown ) {
|
|
renderBitmap(bracket.first_frame, position[0] + bracket_offsets[0], position[1] + bracket_offsets[1]);
|
|
}
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::initDockFlashTimer()
|
|
{
|
|
flash_timer[0] = 1;
|
|
flash_timer[1] = 1;
|
|
flash_flags = false;
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::startFlashDock(int duration)
|
|
{
|
|
flash_timer[0] = timestamp(duration);
|
|
}
|
|
|
|
int HudGaugeExtraTargetData::maybeFlashDock(int flash_fast)
|
|
{
|
|
int draw_bright=0;
|
|
|
|
setGaugeColor();
|
|
if ( !timestamp_elapsed(flash_timer[0]) ) {
|
|
if ( timestamp_elapsed(flash_timer[1]) ) {
|
|
if ( flash_fast ) {
|
|
flash_timer[1] = timestamp(fl2i(TBOX_FLASH_INTERVAL/2.0f));
|
|
} else {
|
|
flash_timer[1] = timestamp(TBOX_FLASH_INTERVAL);
|
|
}
|
|
|
|
// toggle between default and bright frames
|
|
if(flash_flags)
|
|
flash_flags = false;
|
|
else
|
|
flash_flags = true;
|
|
}
|
|
|
|
if (flash_flags) {
|
|
setGaugeColor(HUD_C_BRIGHT);
|
|
draw_bright=1;
|
|
} else {
|
|
setGaugeColor(HUD_C_DIM);
|
|
}
|
|
}
|
|
|
|
return draw_bright;
|
|
}
|
|
|
|
void HudGaugeExtraTargetData::endFlashDock()
|
|
{
|
|
flash_timer[0] = timestamp(0);
|
|
}
|
|
|
|
//from aicode.cpp. Less include...problems...this way.
|
|
extern flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(ship_weapon *swp);
|
|
extern bool turret_weapon_has_subtype(ship_weapon *swp, int subtype);
|
|
void get_turret_subsys_name(ship_weapon *swp, char *outstr)
|
|
{
|
|
Assert(swp != NULL); // Goober5000 //WMC
|
|
|
|
//WMC - find the first weapon, if there is one
|
|
if (swp->num_primary_banks || swp->num_secondary_banks) {
|
|
auto flags = turret_weapon_aggregate_flags(swp);
|
|
|
|
// check if beam or flak using weapon flags
|
|
if (flags[Weapon::Info_Flags::Beam]) {
|
|
sprintf(outstr, "%s", XSTR("Beam turret", 1567));
|
|
} else if (flags[Weapon::Info_Flags::Flak]) {
|
|
sprintf(outstr, "%s", XSTR("Flak turret", 1566));
|
|
} else {
|
|
if (turret_weapon_has_subtype(swp, WP_MISSILE)) {
|
|
sprintf(outstr, "%s", XSTR("Missile lnchr", 1569));
|
|
} else if (turret_weapon_has_subtype(swp, WP_LASER)) {
|
|
// ballistic too! - Goober5000
|
|
if (flags[Weapon::Info_Flags::Ballistic])
|
|
{
|
|
sprintf(outstr, "%s", XSTR("Turret", 1487));
|
|
}
|
|
// the TVWP has some primaries flagged as bombs
|
|
else if (flags[Weapon::Info_Flags::Bomb])
|
|
{
|
|
sprintf(outstr, "%s", XSTR("Missile lnchr", 1569));
|
|
}
|
|
else
|
|
{
|
|
sprintf(outstr, "%s", XSTR("Laser turret", 1568));
|
|
}
|
|
} else {
|
|
// Mantis #2226: find out if there are any weapons here at all
|
|
if (flags.none_set()) {
|
|
sprintf(outstr, "%s", NOX("Unused"));
|
|
} else {
|
|
// Illegal subtype
|
|
static bool Turret_illegal_subtype_warned = false;
|
|
if (!Turret_illegal_subtype_warned) {
|
|
Turret_illegal_subtype_warned = true;
|
|
Warning(LOCATION, "This turret has an illegal subtype! Trace out and fix!");
|
|
}
|
|
sprintf(outstr, "%s", XSTR("Turret", 1487));
|
|
}
|
|
}
|
|
}
|
|
} else if(swp->num_tertiary_banks) {
|
|
//TODO: add tertiary turret code stuff here
|
|
sprintf(outstr, "%s", NOX("Unknown"));
|
|
} else {
|
|
// This should not happen
|
|
sprintf(outstr, "%s", NOX("Unused"));
|
|
}
|
|
}
|
|
|
|
void HudGaugeTargetBox::renderTargetShipInfo(object *target_objp)
|
|
{
|
|
ship *target_shipp;
|
|
int w, h, screen_integrity = 1;
|
|
char outstr[NAME_LENGTH];
|
|
char outstr_name[NAME_LENGTH*2+3];
|
|
char outstr_class[NAME_LENGTH];
|
|
float ship_integrity, shield_strength;
|
|
|
|
Assert(target_objp); // Goober5000
|
|
Assert(target_objp->type == OBJ_SHIP);
|
|
target_shipp = &Ships[target_objp->instance];
|
|
|
|
// set up colors
|
|
if ( HudGauge::maybeFlashSexp() == 1 ) {
|
|
hud_set_iff_color(target_objp, 1);
|
|
} else {
|
|
// Print out ship name, with wing name if it exists
|
|
if ( maybeFlashElement(TBOX_FLASH_NAME) ) {
|
|
hud_set_iff_color(target_objp, 1);
|
|
} else {
|
|
hud_set_iff_color(target_objp);
|
|
}
|
|
}
|
|
|
|
// set up lines
|
|
hud_stuff_ship_name(outstr_name, target_shipp);
|
|
hud_stuff_ship_class(outstr_class, target_shipp);
|
|
|
|
// maybe concatenate the callsign
|
|
if (*outstr_name)
|
|
{
|
|
char outstr_callsign[NAME_LENGTH];
|
|
|
|
hud_stuff_ship_callsign(outstr_callsign, target_shipp);
|
|
if (*outstr_callsign)
|
|
sprintf(&outstr_name[strlen(outstr_name)], " (%s)", outstr_callsign);
|
|
}
|
|
// maybe substitute the callsign
|
|
else
|
|
{
|
|
hud_stuff_ship_callsign(outstr_name, target_shipp);
|
|
}
|
|
|
|
// print lines based on current coords
|
|
renderString(position[0] + Name_offsets[0], position[1] + Name_offsets[1], EG_TBOX_NAME, outstr_name);
|
|
renderString(position[0] + Class_offsets[0], position[1] + Class_offsets[1], EG_TBOX_CLASS, outstr_class);
|
|
|
|
// ----------
|
|
|
|
ship_integrity = 1.0f;
|
|
shield_strength = 1.0f;
|
|
hud_get_target_strength(target_objp, &shield_strength, &ship_integrity);
|
|
|
|
// convert to values of 0->100
|
|
shield_strength *= 100.0f;
|
|
ship_integrity *= 100.0f;
|
|
|
|
screen_integrity = (int)std::lround(ship_integrity);
|
|
if ( screen_integrity == 0 ) {
|
|
if ( ship_integrity > 0 ) {
|
|
screen_integrity = 1;
|
|
}
|
|
}
|
|
// Print out right-justified integrity
|
|
sprintf(outstr, XSTR( "%d%%", 341), screen_integrity);
|
|
gr_get_string_size(&w,&h,outstr);
|
|
|
|
if ( HudGauge::maybeFlashSexp() == 1 ) {
|
|
setGaugeColor(HUD_C_BRIGHT);
|
|
} else {
|
|
maybeFlashElement(TBOX_FLASH_HULL);
|
|
}
|
|
|
|
renderPrintf(position[0] + Hull_offsets[0]-w, position[1] + Hull_offsets[1], EG_TBOX_HULL, "%s", outstr);
|
|
setGaugeColor();
|
|
|
|
// print out the targeted sub-system and % integrity
|
|
if (Player_ai->targeted_subsys != NULL) {
|
|
shield_strength = Player_ai->targeted_subsys->current_hits/Player_ai->targeted_subsys->max_hits * 100.0f;
|
|
screen_integrity = (int)std::lround(shield_strength);
|
|
|
|
if ( screen_integrity < 0 ) {
|
|
screen_integrity = 0;
|
|
}
|
|
|
|
if ( screen_integrity == 0 ) {
|
|
if ( shield_strength > 0 ) {
|
|
screen_integrity = 1;
|
|
}
|
|
}
|
|
|
|
maybeFlashElement(TBOX_FLASH_SUBSYS);
|
|
|
|
// get turret subsys name
|
|
if (Player_ai->targeted_subsys->system_info->type == SUBSYSTEM_TURRET && !ship_subsys_has_instance_name(Player_ai->targeted_subsys)) {
|
|
get_turret_subsys_name(&Player_ai->targeted_subsys->weapons, outstr);
|
|
} else {
|
|
sprintf(outstr, "%s", ship_subsys_get_name(Player_ai->targeted_subsys));
|
|
}
|
|
|
|
char *p_line;
|
|
// hence pipe shall be the linebreak
|
|
char linebreak[2] = "|";
|
|
int n_linebreaks = 0;
|
|
p_line = strpbrk(outstr,linebreak);
|
|
|
|
// figure out how many linebreaks we actually have
|
|
while (p_line != NULL) {
|
|
n_linebreaks++;
|
|
p_line = strpbrk(p_line+1,linebreak);
|
|
}
|
|
|
|
int subsys_name_pos_x;
|
|
int subsys_name_pos_y;
|
|
|
|
if ( Use_subsys_name_offsets ) {
|
|
subsys_name_pos_x = position[0] + Subsys_name_offsets[0];
|
|
subsys_name_pos_y = position[1] + Subsys_name_offsets[1];
|
|
} else {
|
|
subsys_name_pos_x = position[0] + Viewport_offsets[0] + 2;
|
|
subsys_name_pos_y = position[1] + Viewport_offsets[1] + Viewport_h;
|
|
}
|
|
|
|
if (n_linebreaks) {
|
|
p_line = strtok(outstr,linebreak);
|
|
while (p_line != NULL) {
|
|
renderPrintf(subsys_name_pos_x, subsys_name_pos_y-h-((h+1)*n_linebreaks), "%s", p_line);
|
|
p_line = strtok(NULL,linebreak);
|
|
n_linebreaks--;
|
|
}
|
|
} else {
|
|
hud_targetbox_truncate_subsys_name(outstr);
|
|
renderPrintf(subsys_name_pos_x, subsys_name_pos_y-h, "%s", outstr);
|
|
}
|
|
|
|
int subsys_integrity_pos_x;
|
|
int subsys_integrity_pos_y;
|
|
|
|
if ( Use_subsys_integrity_offsets ) {
|
|
subsys_integrity_pos_x = position[0] + Subsys_integrity_offsets[0];
|
|
subsys_integrity_pos_y = position[1] + Subsys_integrity_offsets[1];
|
|
} else {
|
|
subsys_integrity_pos_x = position[0] + Viewport_offsets[0] + Viewport_w - 1;
|
|
subsys_integrity_pos_y = position[1] + Viewport_offsets[1] + Viewport_h;
|
|
}
|
|
|
|
// AL 23-3-98: Fighter bays are a special case. Player cannot destroy them, so don't
|
|
// show the subsystem strength
|
|
// Goober5000: don't display any strength if we can't destroy this subsystem - but sometimes
|
|
// fighterbays can be destroyed
|
|
if ( ship_subsys_takes_damage(Player_ai->targeted_subsys) )
|
|
{
|
|
sprintf(outstr,XSTR( "%d%%", 341),screen_integrity);
|
|
gr_get_string_size(&w,&h,outstr);
|
|
renderPrintf(subsys_integrity_pos_x - w, subsys_integrity_pos_y - h, "%s", outstr);
|
|
}
|
|
|
|
setGaugeColor();
|
|
}
|
|
|
|
// print out 'disabled' on the monitor if the target is disabled
|
|
if ( (target_shipp->flags[Ship::Ship_Flags::Disabled]) || (ship_subsys_disrupted(target_shipp, SUBSYSTEM_ENGINE)) ) {
|
|
if ( target_shipp->flags[Ship::Ship_Flags::Disabled] ) {
|
|
strcpy_s(outstr, XSTR( "DISABLED", 342));
|
|
} else {
|
|
strcpy_s(outstr, XSTR( "DISRUPTED", 343));
|
|
}
|
|
gr_get_string_size(&w,&h,outstr);
|
|
|
|
int disabled_status_pos_x;
|
|
int disabled_status_pos_y;
|
|
|
|
if ( Use_disabled_status_offsets ) {
|
|
disabled_status_pos_x = position[0] + Disabled_status_offsets[0];
|
|
disabled_status_pos_y = position[1] + Disabled_status_offsets[1];
|
|
} else {
|
|
disabled_status_pos_x = position[0] + Viewport_offsets[0] + Viewport_w/2 - w/2 - 1;
|
|
disabled_status_pos_y = position[1] + Viewport_offsets[1] + Viewport_h - 2*h;
|
|
}
|
|
|
|
renderPrintf(disabled_status_pos_x, disabled_status_pos_y, "%s", outstr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine if the subsystem is in line-of sight, without taking into account whether the player ship is
|
|
* facing the subsystem
|
|
*/
|
|
int hud_targetbox_subsystem_in_view(object *target_objp, int *sx, int *sy)
|
|
{
|
|
ship_subsys *subsys;
|
|
vec3d subobj_pos;
|
|
vertex subobj_vertex;
|
|
int rval = -1;
|
|
polymodel *pm;
|
|
|
|
subsys = Player_ai->targeted_subsys;
|
|
if (subsys != NULL ) {
|
|
get_subsystem_pos(&subobj_pos, target_objp, subsys);
|
|
|
|
// is it subsystem in view
|
|
if ( Player->subsys_in_view == -1 ) {
|
|
rval = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos, 0);
|
|
} else {
|
|
rval = Player->subsys_in_view;
|
|
}
|
|
|
|
// get screen coords, adjusting for autocenter
|
|
Assert(target_objp->type == OBJ_SHIP);
|
|
if (target_objp->type == OBJ_SHIP) {
|
|
pm = model_get(Ship_info[Ships[target_objp->instance].ship_info_index].model_num);
|
|
if (pm->flags & PM_FLAG_AUTOCEN) {
|
|
vec3d temp, delta;
|
|
vm_vec_copy_scale(&temp, &pm->autocenter, -1.0f);
|
|
vm_vec_unrotate(&delta, &temp, &target_objp->orient);
|
|
vm_vec_add2(&subobj_pos, &delta);
|
|
}
|
|
}
|
|
|
|
g3_rotate_vertex(&subobj_vertex, &subobj_pos);
|
|
g3_project_vertex(&subobj_vertex);
|
|
*sx = (int) subobj_vertex.screen.xyw.x;
|
|
*sy = (int) subobj_vertex.screen.xyw.y;
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|
|
void hud_cargo_scan_update(object *targetp, float frametime)
|
|
{
|
|
// update cargo inspection status
|
|
Cargo_string[0] = 0;
|
|
if ( targetp->type == OBJ_SHIP ) {
|
|
Target_display_cargo = player_inspect_cargo(frametime, Cargo_string);
|
|
if ( Target_display_cargo ) {
|
|
if ( Player->cargo_inspect_time > 0 ) {
|
|
hud_targetbox_start_flash(TBOX_FLASH_CARGO);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void hud_update_cargo_scan_sound()
|
|
{
|
|
if ( Player->cargo_inspect_time <= 0 ) {
|
|
player_stop_cargo_scan_sound();
|
|
return;
|
|
}
|
|
player_maybe_start_cargo_scan_sound();
|
|
|
|
}
|
|
|
|
/**
|
|
* If the player is scanning for cargo, draw some cool scanning lines on the target monitor
|
|
*/
|
|
void HudGaugeTargetBox::maybeRenderCargoScan(ship_info *target_sip)
|
|
{
|
|
int x1, y1, x2, y2;
|
|
int scan_time; // time required to scan ship
|
|
|
|
if ( Player->cargo_inspect_time <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
scan_time = target_sip->scan_time;
|
|
setGaugeColor(HUD_C_BRIGHT);
|
|
|
|
// draw horizontal scan line
|
|
x1 = position[0] + Cargo_scan_start_offsets[0]; // Cargo_scan_coords[gr_screen.res][0];
|
|
y1 = fl2i(0.5f + position[1] + Cargo_scan_start_offsets[1] + ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_h ));
|
|
x2 = x1 + Cargo_scan_w;
|
|
|
|
renderLine(x1, y1, x2, y1);
|
|
|
|
// RT Changed this to be optional
|
|
if(Cmdline_dualscanlines) {
|
|
// added 2nd horizontal scan line - phreak
|
|
y1 = fl2i(position[1] + Cargo_scan_start_offsets[1] + Cargo_scan_h - ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_h ));
|
|
renderLine(x1, y1, x2, y1);
|
|
}
|
|
|
|
// draw vertical scan line
|
|
x1 = fl2i(0.5f + position[0] + Cargo_scan_start_offsets[0] + ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_w ));
|
|
y1 = position[1] + Cargo_scan_start_offsets[1];
|
|
y2 = y1 + Cargo_scan_h;
|
|
|
|
renderLine(x1, y1-3, x1, y2-1);
|
|
|
|
// RT Changed this to be optional
|
|
if(Cmdline_dualscanlines) {
|
|
// added 2nd vertical scan line - phreak
|
|
x1 = fl2i(0.5f + Cargo_scan_w + position[0] + Cargo_scan_start_offsets[0] - ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_w ));
|
|
renderLine(x1, y1-3, x1, y2-1);
|
|
}
|
|
}
|
|
|
|
void HudGaugeTargetBox::showTargetData(float /*frametime*/)
|
|
{
|
|
char outstr[256]; // temp buffer for sprintf'ing hud output
|
|
int w,h; // width and height of string about to print
|
|
object *target_objp;
|
|
ship *shipp = NULL;
|
|
debris *debrisp = NULL;
|
|
ship_info *sip = NULL;
|
|
int is_ship = 0;
|
|
float displayed_target_distance, displayed_target_speed, current_target_distance, current_target_speed;
|
|
|
|
setGaugeColor();
|
|
|
|
target_objp = &Objects[Player_ai->target_objnum];
|
|
|
|
current_target_distance = Player_ai->current_target_distance;
|
|
|
|
if ( Hud_unit_multiplier > 0.0f ) { // use a different displayed distance scale
|
|
displayed_target_distance = current_target_distance * Hud_unit_multiplier;
|
|
} else {
|
|
displayed_target_distance = current_target_distance;
|
|
}
|
|
|
|
switch( Objects[Player_ai->target_objnum].type ) {
|
|
case OBJ_SHIP:
|
|
shipp = &Ships[target_objp->instance];
|
|
sip = &Ship_info[shipp->ship_info_index];
|
|
is_ship = 1;
|
|
break;
|
|
|
|
case OBJ_DEBRIS:
|
|
debrisp = &Debris[target_objp->instance];
|
|
sip = &Ship_info[debrisp->ship_info_index];
|
|
break;
|
|
|
|
case OBJ_WEAPON:
|
|
sip = NULL;
|
|
break;
|
|
|
|
case OBJ_ASTEROID:
|
|
sip = NULL;
|
|
break;
|
|
|
|
case OBJ_JUMP_NODE:
|
|
return;
|
|
|
|
default:
|
|
Int3(); // can't happen
|
|
break;
|
|
}
|
|
|
|
int hx, hy;
|
|
|
|
// Account for HUD shaking
|
|
hx = fl2i(HUD_offset_x);
|
|
hy = fl2i(HUD_offset_y);
|
|
|
|
// print out the target distance and speed
|
|
sprintf(outstr,XSTR( "d: %.0f%s", 350), displayed_target_distance, modifiers[Player_ai->current_target_dist_trend]);
|
|
|
|
hud_num_make_mono(outstr, font_num);
|
|
gr_get_string_size(&w,&h,outstr);
|
|
|
|
renderString(position[0] + Dist_offsets[0]+hx, position[1] + Dist_offsets[1]+hy, EG_TBOX_DIST, outstr);
|
|
|
|
#if 0
|
|
current_target_speed = vm_vec_dist(&target_objp->pos, &target_objp->last_pos) / frametime;
|
|
#endif
|
|
// 7/28/99 DKA: Do not use vec_mag_quick -- the error is too big
|
|
current_target_speed = vm_vec_mag(&target_objp->phys_info.vel);
|
|
if ( current_target_speed < 0.1f ) {
|
|
current_target_speed = 0.0f;
|
|
}
|
|
// if the speed is 0, determine if we are docked with something -- if so, get the docked velocity
|
|
if ( (current_target_speed == 0.0f) && is_ship ) {
|
|
current_target_speed = dock_calc_docked_fspeed(&Objects[shipp->objnum]);
|
|
|
|
if ( current_target_speed < 0.1f ) {
|
|
current_target_speed = 0.0f;
|
|
}
|
|
}
|
|
|
|
if ( Hud_speed_multiplier > 0.0f ) { // use a different displayed speed scale
|
|
displayed_target_speed = current_target_speed * Hud_speed_multiplier;
|
|
} else {
|
|
displayed_target_speed = current_target_speed;
|
|
}
|
|
|
|
sprintf(outstr, XSTR( "s: %.0f%s", 351), displayed_target_speed, (displayed_target_speed>1)?modifiers[Player_ai->current_target_speed_trend]:"");
|
|
hud_num_make_mono(outstr, font_num);
|
|
|
|
renderString(position[0] + Speed_offsets[0]+hx, position[1] + Speed_offsets[1]+hy, EG_TBOX_SPEED, outstr);
|
|
|
|
//
|
|
// output target info for debug purposes only, this will be removed later
|
|
//
|
|
|
|
#ifndef NDEBUG
|
|
//XSTR:OFF
|
|
char outstr2[256];
|
|
if ( Show_target_debug_info && (is_ship == 1) ) {
|
|
int sx, sy, dy;
|
|
sx = gr_screen.center_offset_x + 5;
|
|
dy = gr_get_font_height() + 1;
|
|
sy = gr_screen.center_offset_y + 300 - 7*dy;
|
|
|
|
gr_set_color_fast(&HUD_color_debug);
|
|
|
|
if ( shipp->ai_index >= 0 ) {
|
|
ai_info *aip = &Ai_info[shipp->ai_index];
|
|
|
|
sprintf(outstr,"AI: %s",Ai_behavior_names[aip->mode]);
|
|
|
|
switch (aip->mode) {
|
|
case AIM_CHASE:
|
|
Assert(aip->submode <= SM_BIG_PARALLEL); // Must be <= largest chase submode value.
|
|
sprintf(outstr2," / %s",Submode_text[aip->submode]);
|
|
strcat_s(outstr,outstr2);
|
|
break;
|
|
case AIM_STRAFE:
|
|
Assert(aip->submode <= AIS_STRAFE_POSITION); // Must be <= largest chase submode value.
|
|
sprintf(outstr2," / %s",Strafe_submode_text[aip->submode-AIS_STRAFE_ATTACK]);
|
|
strcat_s(outstr,outstr2);
|
|
break;
|
|
case AIM_WAYPOINTS:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
gr_printf_no_resize(sx, sy, "%s", outstr);
|
|
sy += dy;
|
|
|
|
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));
|
|
sy += dy;
|
|
|
|
// data can be found in target montior
|
|
if (aip->target_objnum != -1) {
|
|
char target_str[32];
|
|
float dot, dist;
|
|
vec3d v2t;
|
|
|
|
if (aip->target_objnum == OBJ_INDEX(Player_obj))
|
|
strcpy_s(target_str, "Player!");
|
|
else
|
|
sprintf(target_str, "%s", Ships[Objects[aip->target_objnum].instance].get_display_string());
|
|
|
|
gr_printf_no_resize(sx, sy, "Targ: %s", target_str);
|
|
sy += dy;
|
|
|
|
dist = vm_vec_dist_quick(&Objects[Player_ai->target_objnum].pos, &Objects[aip->target_objnum].pos);
|
|
vm_vec_normalized_dir(&v2t,&Objects[aip->target_objnum].pos, &Objects[Player_ai->target_objnum].pos);
|
|
|
|
dot = vm_vec_dot(&v2t, &Objects[Player_ai->target_objnum].orient.vec.fvec);
|
|
|
|
// data can be found in target monitor
|
|
gr_printf_no_resize(sx, sy, "Targ dot: %3.2f", dot);
|
|
sy += dy;
|
|
gr_printf_no_resize(sx, sy, "Targ dst: %3.2f", dist);
|
|
sy += dy;
|
|
|
|
if ( aip->targeted_subsys != NULL ) {
|
|
sprintf(outstr, "Subsys: %s", aip->targeted_subsys->system_info->subobj_name);
|
|
gr_printf_no_resize(sx, sy, "%s", outstr);
|
|
}
|
|
sy += dy;
|
|
}
|
|
|
|
// print out energy transfer information on the ship
|
|
sy = gr_screen.center_offset_y + 70;
|
|
|
|
sprintf(outstr,"MAX G/E: %.0f/%.0f",shipp->weapon_energy,shipp->current_max_speed);
|
|
gr_printf_no_resize(sx, sy, "%s", outstr);
|
|
sy += dy;
|
|
|
|
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]);
|
|
gr_printf_no_resize(sx, sy, "%s", outstr);
|
|
sy += dy;
|
|
|
|
// Show information about attacker.
|
|
{
|
|
int found = 0;
|
|
|
|
if (Enemy_attacker != NULL)
|
|
if (Enemy_attacker->type == OBJ_SHIP) {
|
|
ship *eshipp;
|
|
ai_info *eaip;
|
|
float dot, dist;
|
|
vec3d v2t;
|
|
|
|
eshipp = &Ships[Enemy_attacker->instance];
|
|
eaip = &Ai_info[eshipp->ai_index];
|
|
|
|
if (eaip->target_objnum == OBJ_INDEX(Player_obj)) {
|
|
found = 1;
|
|
dist = vm_vec_dist_quick(&Enemy_attacker->pos, &Player_obj->pos);
|
|
vm_vec_normalized_dir(&v2t,&Objects[eaip->target_objnum].pos, &Enemy_attacker->pos);
|
|
|
|
dot = vm_vec_dot(&v2t, &Enemy_attacker->orient.vec.fvec);
|
|
|
|
gr_printf_no_resize(sx, sy, "#%i: %s", OBJ_INDEX(Enemy_attacker), Ships[Enemy_attacker->instance].get_display_string());
|
|
sy += dy;
|
|
gr_printf_no_resize(sx, sy, "Targ dist: %5.1f", dist);
|
|
sy += dy;
|
|
gr_printf_no_resize(sx, sy, "Targ dot: %3.2f", dot);
|
|
sy += dy;
|
|
}
|
|
}
|
|
|
|
if (Player_ai->target_objnum == Enemy_attacker - Objects)
|
|
found = 0;
|
|
|
|
if (!found) {
|
|
int i;
|
|
|
|
Enemy_attacker = NULL;
|
|
for (i=0; i<MAX_OBJECTS; i++)
|
|
if (Objects[i].type == OBJ_SHIP) {
|
|
int enemy;
|
|
|
|
if (i != Player_ai->target_objnum) {
|
|
enemy = Ai_info[Ships[Objects[i].instance].ai_index].target_objnum;
|
|
|
|
if (enemy == Player_obj-Objects) {
|
|
Enemy_attacker = &Objects[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show target size
|
|
// hud_target_w
|
|
gr_printf_no_resize(sx, sy, "Targ size: %dx%d", Hud_target_w, Hud_target_h );
|
|
sy += dy;
|
|
|
|
polymodel *pm = model_get(sip->model_num);
|
|
gr_printf_no_resize(sx, sy, "POF:%s", pm->filename );
|
|
sy += dy;
|
|
|
|
gr_printf_no_resize(sx, sy, "Mass: %.2f\n", pm->mass);
|
|
sy += dy;
|
|
}
|
|
}
|
|
|
|
// display the weapons for the target on the HUD. Include ammo counts.
|
|
if ( Show_target_weapons && (is_ship == 1) ) {
|
|
int sx, sy, dy, i;
|
|
ship_weapon *swp;
|
|
|
|
swp = &shipp->weapons;
|
|
sx = gr_screen.center_offset_x + 400;
|
|
sy = gr_screen.center_offset_y + 100;
|
|
dy = gr_get_font_height();
|
|
|
|
sprintf(outstr,"Num primaries: %d", swp->num_primary_banks);
|
|
gr_printf_no_resize(sx,sy,"%s", outstr);
|
|
sy += dy;
|
|
for ( i = 0; i < swp->num_primary_banks; i++ ) {
|
|
sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->primary_bank_weapons[i]].get_display_string());
|
|
gr_printf_no_resize(sx,sy,"%s", outstr);
|
|
sy += dy;
|
|
}
|
|
|
|
sy += dy;
|
|
sprintf(outstr,"Num secondaries: %d", swp->num_secondary_banks);
|
|
gr_printf_no_resize(sx,sy,"%s", outstr);
|
|
sy += dy;
|
|
for ( i = 0; i < swp->num_secondary_banks; i++ ) {
|
|
sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->secondary_bank_weapons[i]].get_display_string());
|
|
gr_printf_no_resize(sx,sy,"%s", outstr);
|
|
sy += dy;
|
|
}
|
|
}
|
|
//XSTR:ON
|
|
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Called at the start of each level
|
|
*/
|
|
void hud_init_target_static()
|
|
{
|
|
Target_static_next = 0;
|
|
Target_static_playing = 0;
|
|
}
|
|
|
|
/**
|
|
* Determine if we should draw static on top of the target box
|
|
*/
|
|
void hud_update_target_static()
|
|
{
|
|
float sensors_str;
|
|
|
|
// on lowest skill level, don't show static on target monitor
|
|
if ( Game_skill_level == 0 )
|
|
return;
|
|
|
|
// if multiplayer observer, don't show static
|
|
if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER))
|
|
return;
|
|
|
|
sensors_str = ship_get_subsystem_strength( Player_ship, SUBSYSTEM_SENSORS );
|
|
|
|
if ( ship_subsys_disrupted(Player_ship, SUBSYSTEM_SENSORS) ) {
|
|
sensors_str = SENSOR_STR_TARGET_NO_EFFECTS-1;
|
|
}
|
|
|
|
if ( sensors_str > SENSOR_STR_TARGET_NO_EFFECTS ) {
|
|
Target_static_playing = 0;
|
|
Target_static_next = 0;
|
|
} else {
|
|
if ( Target_static_next == 0 )
|
|
Target_static_next = 1;
|
|
}
|
|
|
|
if ( timestamp_elapsed(Target_static_next) ) {
|
|
Target_static_playing ^= 1;
|
|
Target_static_next = timestamp_rand(50, 750);
|
|
}
|
|
|
|
if ( Target_static_playing ) {
|
|
if (!Target_static_looping.isValid()) {
|
|
Target_static_looping = snd_play_looping(gamesnd_get_game_sound(GameSounds::STATIC));
|
|
}
|
|
} else {
|
|
if (Target_static_looping.isValid()) {
|
|
snd_stop(Target_static_looping);
|
|
Target_static_looping = sound_handle::invalid();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the HUD status description of a particular ship
|
|
*
|
|
* Checks for disabled or ships with disrupted engines, as well as damage levels
|
|
* of the target ship. If status has changed, then the HUD will flash
|
|
*
|
|
* @param targetp Instance of the ship target -- note the targetp->instance cannot be negative
|
|
*
|
|
*/
|
|
void hud_update_ship_status(object *targetp)
|
|
{
|
|
Assert( targetp != NULL );
|
|
Assert( (targetp->instance >= 0) && (targetp->instance < MAX_SHIPS) );
|
|
|
|
if ( (targetp->instance >= 0) && (targetp->instance < MAX_SHIPS) ) {
|
|
// print out status of ship for the targetbox
|
|
if ( (Ships[targetp->instance].flags[Ship::Ship_Flags::Disabled]) || (ship_subsys_disrupted(&Ships[targetp->instance], SUBSYSTEM_ENGINE)) ) {
|
|
Current_ts = TS_DIS;
|
|
} else {
|
|
if ( Pl_target_integrity > 0.9 ) {
|
|
Current_ts = TS_OK;
|
|
} else if ( Pl_target_integrity > 0.2 ) {
|
|
Current_ts = TS_DMG;
|
|
} else {
|
|
Current_ts = TS_CRT;
|
|
}
|
|
}
|
|
|
|
if ( Last_ts != -1 && Current_ts != Last_ts ) {
|
|
hud_targetbox_start_flash(TBOX_FLASH_STATUS);
|
|
}
|
|
}
|
|
|
|
Last_ts = Current_ts;
|
|
}
|
|
|
|
/**
|
|
* Start the targetbox item flashing for duration ms
|
|
*
|
|
* @param index TBOX_FLASH_ define
|
|
* @param duration optional param (default value TBOX_FLASH_DURATION), how long to flash in ms
|
|
*/
|
|
void hud_targetbox_start_flash(int index, int duration)
|
|
{
|
|
Targetbox_flash_timers[index] = timestamp(duration);
|
|
}
|
|
|
|
/**
|
|
* Stop flashing a specific targetbox item
|
|
*/
|
|
void hud_targetbox_end_flash(int index)
|
|
{
|
|
Targetbox_flash_timers[index] = timestamp(0);
|
|
}
|
|
|
|
void HudGaugeTargetBox::pageIn()
|
|
{
|
|
bm_page_in_aabitmap( Monitor_frame.first_frame, Monitor_frame.num_frames);
|
|
|
|
bm_page_in_aabitmap( Integrity_bar.first_frame, Integrity_bar.num_frames );
|
|
}
|