/* * 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. * */ /* * $Logfile: /Freespace2/code/Hud/HUDtargetbox.cpp $ * $Revision: 2.72 $ * $Date: 2007-08-30 04:51:07 $ * $Author: Backslash $ * * C module for drawing the target monitor box on the HUD * * $Log: not supported by cvs2svn $ * Revision 2.71 2007/07/15 04:19:25 Goober5000 * partial commit of aldo's eyepoint feature * it will need a keystroke to be complete * * Revision 2.70 2007/02/20 04:20:10 Goober5000 * the great big duplicate model removal commit * * Revision 2.69 2007/02/11 21:26:34 Goober5000 * massive shield infrastructure commit * * Revision 2.68 2007/01/07 12:53:35 taylor * add position info for weapon energy text * make sure that we can't target a hidden jumpnode * rest of the weapon switch fix * * Revision 2.67 2006/08/03 01:33:56 Goober5000 * add a second method for specifying ship copies, plus allow the parser to recognize ship class copy names that aren't consistent with the table * --Goober5000 * * Revision 2.66 2006/07/17 01:12:19 taylor * fix some missile autocentering issues * - use MR_AUTOCENTER and MR_IS_MISSILE flags to generate an autocenter for a missile if one doesn't already exist * - don't try to autocenter loadout icons when rendered 3d * * Revision 2.65 2006/05/13 07:09:24 taylor * minor cleanup and a couple extra error checks * get rid of some wasteful math from the gr_set_proj_matrix() calls * * Revision 2.64 2006/04/12 22:23:41 taylor * compiler warning fixes to make GCC 4.1 shut the hell up * * Revision 2.63 2006/01/18 16:14:04 taylor * allow gr_render_buffer() to take TMAP flags * let gr_render_buffer() render untextured polys (OGL only until some D3D people fix it on their side) * add MR_SHOW_OUTLINE_HTL flag so we easily render using HTL mode for wireframe views * make Interp_verts/Interp_norms/etc. dynamic and get rid of the extra htl_* versions * * Revision 2.62 2006/01/13 03:30:59 Goober5000 * übercommit of custom IFF stuff :) * * Revision 2.61 2005/12/12 21:32:14 taylor * allow use of a specific LOD for ship and weapon rendering in the hud targetbox * * Revision 2.60 2005/10/10 17:21:04 taylor * remove NO_NETWORK * * Revision 2.59 2005/09/25 08:25:15 Goober5000 * Okay, everything should now work again. :p Still have to do a little more with the asteroids. * --Goober5000 * * Revision 2.58 2005/09/25 05:26:13 Goober5000 * bah * --Goober5000 * * Revision 2.57 2005/09/25 05:13:06 Goober5000 * hopefully complete species upgrade * --Goober5000 * * Revision 2.56 2005/07/25 05:24:16 Goober5000 * cleaned up some command line and mission flag stuff * --Goober5000 * * Revision 2.55 2005/07/22 10:18:38 Goober5000 * CVS header tweaks * --Goober5000 * * Revision 2.54 2005/07/18 03:44:01 taylor * cleanup hudtargetbox rendering from that total hack job that had been done on it (fixes wireframe view as well) * more non-standard res fixing * - I think everything should default to resize now (much easier than having to figure that crap out) * - new mouse_get_pos_unscaled() function to return 1024x768/640x480 relative values so we don't have to do it later * - lots of little cleanups which fix several strange offset/size problems * - fix gr_resize/unsize_screen_pos() so that it won't wrap on int (took too long to track this down) * * Revision 2.53 2005/07/13 03:15:52 Goober5000 * remove PreProcDefine #includes in FS2 * --Goober5000 * * Revision 2.52 2005/07/13 00:44:22 Goober5000 * improved species support and removed need for #define * --Goober5000 * * Revision 2.51 2005/05/11 22:15:49 phreak * added mission flag that will not show enemy wing names, just the ship class. * * Revision 2.50 2005/04/28 05:29:29 wmcoolmon * Removed FS2_DEMO defines that looked like they wouldn't cause the universe to collapse * * Revision 2.49 2005/04/05 05:53:17 taylor * s/vector/vec3d/g, better support for different compilers (Jens Granseuer) * * Revision 2.48 2005/03/27 12:28:33 Goober5000 * clarified max hull/shield strength names and added ship guardian thresholds * --Goober5000 * * Revision 2.47 2005/03/25 06:57:34 wmcoolmon * Big, massive, codebase commit. I have not removed the old ai files as the ones I uploaded aren't up-to-date (But should work with the rest of the codebase) * * Revision 2.46 2005/03/06 11:23:45 wmcoolmon * RE-fixed stuff. Ogg support. Briefings. * * Revision 2.45 2005/03/03 06:05:28 wmcoolmon * Merge of WMC's codebase. "Features and bugs, making Goober say "Grr!", as release would be stalled now for two months for sure" * * Revision 2.44 2005/03/02 21:24:44 taylor * more network/inferno goodness for Windows, takes care of a few warnings too * * Revision 2.43 2005/01/30 03:26:11 wmcoolmon * HUD updates * * Revision 2.42 2005/01/29 09:19:45 argv * Fixed compile errors due to several source files not having been updated to * reference "Min/Max_draw_distance" instead of "MIN/MAX_DRAW_DISTANCE". * * -- _argv[-1] * * Revision 2.41 2005/01/11 21:38:49 Goober5000 * multiple ship docking :) * don't tell anyone yet... check the SCP internal * --Goober500 * * Revision 2.40 2005/01/01 19:47:26 taylor * make use of MR_NO_FOGGING to render models without fog * * Revision 2.39 2004/08/01 02:30:52 phreak * -phreak command line changed to -dualscanlines * * Revision 2.38 2004/07/26 20:47:33 Kazan * remove MCD complete * * Revision 2.37 2004/07/12 16:32:49 Kazan * MCD - define _MCD_CHECK to use memory tracking * * Revision 2.36 2004/04/07 17:20:24 phreak * changed around the order of some function calls to get the target model * properly rendering in the hud targetbox * * Revision 2.35 2004/04/06 03:09:53 phreak * added a control config option for the wireframe hud targetbox i enabled ages ago * * Revision 2.34 2004/03/17 04:07:30 bobboau * new fighter beam code * fixed old after burner trails * had to bump a few limits, working on some dynamic solutions * a few fixed to background POF rendering * fixing asorted bugs * * Revision 2.33 2004/03/05 09:02:04 Goober5000 * Uber pass at reducing #includes * --Goober5000 * * Revision 2.32 2004/02/15 06:02:32 bobboau * fixed sevral asorted matrix errors, * OGL people make sure I didn't break anything, * most of what I did was replaceing falses with (if graphicts_mode == D3D) * * Revision 2.31 2004/02/10 05:07:38 matt * Fixed issue with ships being rendered off center * in the HUD target box. Much easier than I * thought * -- Sticks * * Revision 2.30 2004/02/07 05:11:08 Goober5000 * fix for undestroyable subsystems * --Goober5000 * * Revision 2.29 2004/02/06 23:17:43 Goober5000 * tweakage * --Goober5000 * * Revision 2.28 2004/02/04 09:02:45 Goober5000 * got rid of unnecessary double semicolons * --Goober5000 * * Revision 2.27 2004/02/04 08:41:04 Goober5000 * made code more uniform and simplified some things, * specifically shield percentage and quadrant stuff * --Goober5000 * * Revision 2.26 2004/01/30 07:39:07 Goober5000 * whew - I just went through all the code I ever added (or at least, that I could * find that I commented with a Goober5000 tag) and added a bunch of Asserts * and error-checking * --Goober5000 * * Revision 2.25 2003/12/16 20:46:37 phreak * made gr_set_proj_matrix use the MIN/MAX_DRAW_DISTANCE constants * * Revision 2.24 2003/12/04 20:39:09 randomtiger * Added DDS image support for D3D * Added new command flag '-ship_choice_3d' to activate 3D models instead of ani's in ship choice, feature now off by default * Hopefully have fixed D3D text batching bug that caused old values to appear * Added Hud_target_object_factor variable to control 3D object sizes of zoom in HUD target * Fixed jump nodes not showing * * Revision 2.23 2003/11/16 04:09:23 Goober5000 * language * * Revision 2.22 2003/11/11 03:56:11 bobboau * lots of bug fixing, much of it in nebula and bitmap drawing * * Revision 2.21 2003/11/09 06:31:39 Kazan * a couple of htl functions being called in nonhtl (ie NULL functions) problems fixed * conflicts in cmdline and timerbar.h log entries * cvs stopped acting like it was on crack obviously * * Revision 2.20 2003/11/06 22:47:02 phreak * added gr_start_**_matrix() and gr_end_**_matrix() around where ships are rendered * * Revision 2.19 2003/09/13 08:27:29 Goober5000 * added some minor things, such as code cleanup and the following: * --turrets will not fire at cargo * --MAX_SHIELD_SECTIONS substituted for the number 4 in many places * --supercaps have their own default message bitfields (distinguished from capships) * --turrets are allowed on fighters * --jump speed capped at 65m/s, to avoid ship travelling too far * --non-huge weapons now scale their damage, instead of arbitrarily cutting off * ----Goober5000 * * Revision 2.18 2003/09/13 06:02:05 Goober5000 * clean rollback of all of argv's stuff * --Goober5000 * * Revision 2.15 2003/08/21 08:31:24 Goober5000 * fixed turret text display for non-laser weapons * --Goober5000 * * Revision 2.14 2003/04/29 01:03:23 Goober5000 * implemented the custom hitpoints mod * --Goober5000 * * Revision 2.13 2003/01/27 07:46:33 Goober5000 * finished up my fighterbay code - ships will not be able to arrive from or depart into * fighterbays that have been destroyed (but you have to explicitly say in the tables * that the fighterbay takes damage in order to enable this) * --Goober5000 * * Revision 2.12 2003/01/17 07:59:09 Goober5000 * fixed some really strange behavior with strings not being truncated at the * # symbol * --Goober5000 * * Revision 2.11 2003/01/17 01:48:50 Goober5000 * added capability to the $Texture replace code to substitute the textures * without needing and extra model, however, this way you can't substitute * transparent or animated textures * --Goober5000 * * Revision 2.10 2003/01/15 20:49:10 Goober5000 * did the XSTR for the turret thing * --Goober5000 * * Revision 2.9 2003/01/15 16:52:27 Goober5000 * oops, that'll introduce a bug - naming it just plain "Turret" instead * --Goober5000 * * Revision 2.8 2003/01/15 16:48:59 Goober5000 * capship ballistic weapon displays "Cannon" on HUD instead of "Laser Turret" * --Goober5000 * * Revision 2.7 2003/01/15 07:09:09 Goober5000 * changed most references to modelnum to use ship instead of ship_info -- * this will help with the change-model sexp and any other instances of model * changing * --Goober5000 * * Revision 2.6 2002/12/14 17:09:28 Goober5000 * removed mission flag for fighterbay damage; instead made damage display contingent on whether the fighterbay subsystem is assigned a damage percentage in ships.tbl * --Goober5000 * * Revision 2.5 2002/12/14 01:55:04 Goober5000 * added mission flag to show subsystem damage for fighterbays * ~Goober5000~ * * Revision 2.4 2002/10/22 23:02:40 randomtiger * Made Phreaks alternative scanning style optional under the command line tag "-phreak" * Fixed bug that changes HUD colour when targetting debris in a full nebula. - RT * * Revision 2.3 2002/09/20 20:01:30 phreak * extra effects during cargo scan * * Revision 2.2 2002/08/06 16:50:44 phreak * added wireframe targetbox feature * * Revision 2.2 2002/08/04 23:17:40 phreak * Did the toggling code for wireframes -> CTRL+SHIFT+Q * * Revision 2.2 2002/08/04 21:53:13 phreak * Changed hud_render_target_asteroid, ...weapon, ...ship to render in wireframe * * Revision 2.1 2002/08/01 01:41:06 penguin * The big include file move * * Revision 2.0 2002/06/03 04:02:23 penguin * Warpcore CVS sync * * Revision 1.3 2002/05/13 21:09:28 mharris * I think the last of the networking code has ifndef NO_NETWORK... * * Revision 1.2 2002/05/03 22:07:08 mharris * got some stuff to compile * * Revision 1.1 2002/05/02 18:03:08 mharris * Initial checkin - converted filenames and includes to lower case * * * 31 11/02/99 3:22p Jefff * translation of targetbox text * * 30 10/29/99 10:41p Jefff * more subsystem fixes * * 29 10/28/99 11:17p Jefff * used escape seqs for some special German chars * * 28 10/28/99 2:02a Jefff * revised the subsystem localization * * 27 9/14/99 11:03p Jefff * dont draw target names from # on (weapons case) * * 26 9/04/99 5:17p Andsager * Make event log record name of destroyed subsytem, and use this name for * different types of turrets * * 25 8/25/99 11:35a Andsager * Move hud render ship subsystem target box for ships with Autocenter * * 24 8/17/99 7:32p Jefff * models use autocenter in target view * * 23 8/01/99 12:39p Dave * Added HUD contrast control key (for nebula). * * 22 7/31/99 4:15p Dave * Fixed supernova particle velocities. Handle OBJ_NONE in target * monitoring view. Properly use objectives notify gauge colors. * * 21 7/28/99 2:49p Andsager * Make hud target speed use vm_vec_mag (not vm_vec_mag_quick) * * 20 7/15/99 9:20a Andsager * FS2_DEMO initial checkin * * 19 7/02/99 10:56a Andsager * Put in big ship - big ship attack mode. Modify stealth sweep ai. * * 18 6/29/99 3:16p Andsager * Debug stuff. * * 17 6/10/99 3:43p Dave * Do a better job of syncing text colors to HUD gauges. * * 16 6/09/99 2:55p Andsager * Allow multiple asteroid subtypes (of large, medium, small) and follow * family. * * 15 6/07/99 4:20p Andsager * Add HUD color for tagged object. Apply to target and radar. * * 14 6/03/99 11:43a Dave * Added the ability to use a different model when rendering to the HUD * target box. * * 13 5/24/99 9:02a Andsager * Remove Int3() in turret subsys name code when turret has no weapon. * * 12 5/21/99 1:42p Andsager * Added error checking for HUD turret name * * 11 5/20/99 7:00p Dave * Added alternate type names for ships. Changed swarm missile table * entries. * * 10 5/19/99 3:50p Andsager * Show type of debris is debris field (species debris or asteroid). Show * type of subsystem turret targeted (laser, missile, flak, beam). * * 9 5/14/99 4:22p Andsager * Modify hud_render_target_ship to show damaged subsystems in their * actual state. Now also shows rotation of subsystems. * * 8 4/16/99 5:54p Dave * Support for on/off style "stream" weapons. Real early support for * target-painting lasers. * * 7 1/07/99 9:08a Jasen * HUD coords * * 6 12/28/98 3:17p Dave * Support for multiple hud bitmap filenames for hi-res mode. * * 5 12/21/98 5:03p Dave * Modified all hud elements to be multi-resolution friendly. * * 4 11/05/98 4:18p Dave * First run nebula support. Beefed up localization a bit. Removed all * conditional compiles for foreign versions. Modified mission file * format. * * 3 10/13/98 9:28a Dave * Started neatening up freespace.h. Many variables renamed and * reorganized. Added AlphaColors.[h,cpp] * * 2 10/07/98 10:53a Dave * Initial checkin. * * 1 10/07/98 10:49a Dave * * 108 8/28/98 3:28p Dave * EMP effect done. AI effects may need some tweaking as required. * * 107 8/25/98 1:48p Dave * First rev of EMP effect. Player side stuff basically done. Next comes * AI code. * * 106 6/19/98 3:49p Lawrance * localization tweaks * * 105 6/17/98 11:04a Lawrance * localize subsystem names that appear on the HUD * * 104 6/09/98 5:18p Lawrance * French/German localization * * 103 6/09/98 10:31a Hoffoss * Created index numbers for all xstr() references. Any new xstr() stuff * added from here on out should be added to the end if the list. The * current list count can be found in FreeSpace.cpp (search for * XSTR_SIZE). * * 102 6/01/98 11:43a John * JAS & MK: Classified all strings for localization. * * 101 5/20/98 3:52p Allender * fixed compiler warnings * * 100 5/20/98 12:59p John * Turned optimizations on for debug builds. Also turning on automatic * function inlining. Turned off the unreachable code warning. * * 99 5/15/98 8:36p Lawrance * Add 'target ship that last sent transmission' target key * * 98 5/14/98 11:26a Lawrance * ensure fighter bays are drawn with correct bracket color * * 97 5/08/98 5:32p Lawrance * Allow cargo scanning even if target gauge is disabled * * 96 5/04/98 10:51p Lawrance * remove unused local * * 95 5/04/98 9:17p Lawrance * Truncate ship class names at # char when displaying debris on target * moniter * * 94 5/04/98 6:12p Lawrance * Write generic function hud_end_string_at_first_hash_symbol(), to use in * various spots on the HUD * * 93 4/15/98 12:55a Lawrance * Show time to impact for bombs * * 92 4/02/98 6:31p Lawrance * remove asteroid references if DEMO defined * * 91 3/31/98 5:18p John * Removed demo/save/restore. Made NDEBUG defined compile. Removed a * bunch of debug stuff out of player file. Made model code be able to * unload models and malloc out only however many models are needed. * * * 90 3/30/98 1:08a Lawrance * Implement "blast" icon. Blink HUD icon when player ship is hit by a * blast. * * $NoKeywords: $ */ #include "hud/hudtargetbox.h" #include "object/object.h" #include "hud/hud.h" #include "hud/hudbrackets.h" #include "model/model.h" #include "mission/missionparse.h" #include "debris/debris.h" #include "playerman/player.h" #include "gamesnd/gamesnd.h" #include "freespace2/freespace.h" #include "io/timer.h" #include "ship/subsysdamage.h" #include "graphics/font.h" #include "asteroid/asteroid.h" #include "jumpnode/jumpnode.h" #include "weapon/emp.h" #include "localization/localize.h" #include "cmdline/cmdline.h" #include "ship/ship.h" #include "weapon/weapon.h" #include "parse/parselo.h" #include "object/objectdock.h" #include "species_defs/species_defs.h" #include "iff_defs/iff_defs.h" #include "network/multi.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; int Target_static_looping; #ifndef NDEBUG extern int Show_target_debug_info; extern int Show_target_weapons; #endif // used to print out + or - after target distance and speed char* modifiers[] = { //XSTR:OFF "+", "-", "" //XSTR:ON }; char Target_view_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = { "targetview1", "targetview1" }; char Target_integ_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = { "targetview2", "targetview2" }; char Target_extra_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = { "targetview3", "targetview3" }; // animation frames for the target view monitor // frames: 0 => background of target monitor // 1 => foreground of target monitor hud_frames Target_view_gauge; int Target_view_gauge_loaded = 0; // animation frames for the extended target information // frames: 0 => normal gague hud_frames Target_view_extra; int Target_view_extra_loaded = 0; // animation frames for the target view monitor integrity bar // frames: 0 => dark bar // 1 => bright bar hud_frames Target_view_integrity_gauge; int Target_view_integrity_gauge_loaded = 0; #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 int Targetbox_coords[GR_NUM_RESOLUTIONS][NUM_TBOX_COORDS][2] = { { // GR_640 {5,319}, {13,316}, {13,325}, {13,337}, {90,337}, {13,349}, {139,361}, {5,283}, {13,280}, {13,290}, {13,299} }, { // GR_1024 {5,590}, {13,587}, {13,597}, {13,608}, {90,608}, {13,620}, {139,632}, {5,555}, {13,552}, {13,561}, {13,570} } }; int Integrity_bar_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 138, 371, 4, 88 }, { // GR_1024 138, 642, 4, 88 } }; int Integrity_string_coords[GR_NUM_RESOLUTIONS][2] = { { // GR_640 112, 372 }, { // GR_1024 112, 643 } }; // 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, second element is time of next flash int Targetbox_flash_timers[NUM_TBOX_FLASH_TIMERS][2]; int Targetbox_flash_flags; // flag to indicate whether to show the extra information about a target // The HUD_config controls whether this can be shown... but the player can still toggle it on/off // during the game. int Targetbox_show_extra_info = 1; int Targetbox_wire=0; // 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 Last_ts; // holds last target status. void hud_blit_target_integrity(int disabled,int force_obj_num = -1); // cut down long subsystem names to a more manageable length char *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 ( strstr(outstr, XSTR( "communication", 333))) { strcpy( outstr, XSTR( "comm", 334) ); } else if ( strstr(outstr, XSTR( "navigation", 335))) { strcpy( outstr, XSTR( "nav", 336) ); } else if (!stricmp(outstr, "Gas Collector")) { strcpy(outstr, "collector"); } } return outstr; } //swich through the valid targetbox modes void hud_targetbox_switch_wireframe_mode() { //0==standard //1==wireframe only //2==wireframe with textures 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][0] = 1; Targetbox_flash_timers[index][1] = 1; Targetbox_flash_flags &= ~(1< item to flash // flash_fast => optional param (default value 0), flash twice as fast // exit: 1 => set bright color // 0 => set default color int hud_targetbox_maybe_flash(int index, int flash_fast) { int draw_bright=0; // hud_set_default_color(); hud_set_gauge_color(HUD_TARGET_MONITOR); if ( !timestamp_elapsed(Targetbox_flash_timers[index][0]) ) { if ( timestamp_elapsed(Targetbox_flash_timers[index][1]) ) { if ( flash_fast ) { Targetbox_flash_timers[index][1] = timestamp(fl2i(TBOX_FLASH_INTERVAL/2.0f)); } else { Targetbox_flash_timers[index][1] = timestamp(TBOX_FLASH_INTERVAL); } Targetbox_flash_flags ^= (1< pointer to ship object that you want strength values for // shields => OUTPUT parameter: percentage value of shields (0->1.0) // integrity => OUTPUT parameter: percentage value of integrity (0->1.0) // // Goober5000 - simplified void hud_get_target_strength(object *objp, float *shields, float *integrity) { *shields = get_shield_pct(objp); *integrity = get_hull_pct(objp); } // maybe draw the extra targeted ship information above the target monitor void hud_targetbox_show_extra_ship_info(ship *target_shipp, object *target_objp) { char outstr[256], tmpbuf[256]; int has_orders = 0; int not_training; int extra_data_shown=0; hud_set_gauge_color(HUD_TARGET_MONITOR_EXTRA_DATA); not_training = !(The_mission.game_type & MISSION_TYPE_TRAINING); if ( not_training && (hud_gauge_active(HUD_TARGET_MONITOR_EXTRA_DATA)) && (Targetbox_show_extra_info) ) { // Print out current orders if the targeted ship is friendly // AL 12-26-97: only show orders and time to target for friendly ships if ( (Player_ship->team == target_shipp->team) && !(ship_get_SIF(target_shipp) & SIF_NOT_FLYABLE) ) { extra_data_shown=1; if ( ship_return_orders(outstr, target_shipp) ) { gr_force_fit_string(outstr, 255, 162); has_orders = 1; } else { strcpy(outstr, XSTR( "no orders", 337)); } emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_EXTRA_ORDERS][0], Targetbox_coords[gr_screen.res][TBOX_EXTRA_ORDERS][1], EG_TBOX_EXTRA1, outstr); } if ( has_orders ) { sprintf(outstr, XSTR( "time to: ", 338)); if ( ship_return_time_to_goal(tmpbuf, target_shipp) ) { strcat(outstr, tmpbuf); emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_EXTRA_TIME][0], Targetbox_coords[gr_screen.res][TBOX_EXTRA_TIME][1], EG_TBOX_EXTRA2, outstr); } } } // Print out dock status if ( object_is_docked(target_objp) ) { // count the objects directly docked to me int dock_count = dock_count_direct_docked_objects(target_objp); // docked to only one object if (dock_count == 1) { sprintf(outstr, XSTR("Docked: %s", 339), Ships[dock_get_first_docked_object(target_objp)->instance].ship_name); } // docked to multiple objects else { sprintf(outstr, XSTR("Docked: %d objects", -1), dock_count); } gr_force_fit_string(outstr, 255, 173); hud_targetbox_maybe_flash(TBOX_FLASH_DOCKED); emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_EXTRA_DOCK][0], Targetbox_coords[gr_screen.res][TBOX_EXTRA_DOCK][1], EG_TBOX_EXTRA3, outstr); extra_data_shown=1; } if ( extra_data_shown ) { // hud_set_default_color(); GR_AABITMAP(Target_view_extra.first_frame, Targetbox_coords[gr_screen.res][TBOX_EXTRA][0],Targetbox_coords[gr_screen.res][TBOX_EXTRA][1]); } } // Render a jump node on the target monitor void hud_render_target_jump_node(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; if ( target_objp->jnp->is_hidden() ) { 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 up_vector = Player_obj->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); hud_render_target_setup(&camera_eye, &camera_orient, 0.5f); target_objp->jnp->render( &obj_pos ); hud_render_target_close(); } HUD_reset_clip(); hud_blit_target_foreground(); hud_blit_target_integrity(1); // hud_set_default_color(); hud_set_gauge_color(HUD_TARGET_MONITOR); emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, target_objp->jnp->get_name_ptr()); dist = vm_vec_dist_quick(&target_objp->pos, &Player_obj->pos); // 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); gr_get_string_size(&w,&h,outstr); emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_DIST][0]+hx, Targetbox_coords[gr_screen.res][TBOX_DIST][1]+hy, EG_TBOX_DIST, outstr); } // ------------------------------------------------------------------------------------- // hud_render_target_asteroid() // // Render a piece of asteroid on the target monitor // void hud_render_target_asteroid(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; int target_team; float time_to_impact, factor; int pof; int flags=0; //draw flags for wireframe asteroidp = &Asteroids[target_objp->instance]; target_team = obj_team(target_objp); 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 up_vector = Player_obj->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); hud_render_target_setup(&camera_eye, &camera_orient, 0.5f); model_clear_instance(Asteroid_info[asteroidp->asteroid_type].model_num[pof]); if (Targetbox_wire!=0) { if (time_to_impact>=0) model_set_outline_color(255,255,255); else model_set_outline_color(64,64,0); flags = (Cmdline_nohtl) ? MR_SHOW_OUTLINE : MR_SHOW_OUTLINE_HTL; if (Targetbox_wire==1) flags |=MR_NO_POLYS; } model_render(Asteroid_info[asteroidp->asteroid_type].model_num[pof], &target_objp->orient, &obj_pos, flags |MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_NO_FOGGING ); hud_render_target_close(); } HUD_reset_clip(); hud_blit_target_foreground(); hud_blit_target_integrity(1); // hud_set_default_color(); hud_set_gauge_color(HUD_TARGET_MONITOR); // 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(hud_name, NOX("asteroid")); break; default: sprintf(hud_name, NOX("%s debris"), Species_info[(asteroidp->asteroid_type / NUM_DEBRIS_SIZES) - 1].species_name); break; } emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, hud_name); if ( time_to_impact >= 0.0f ) { emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, NOX("impact: %.1f sec"), time_to_impact); } } //from aicode.cpp. Less include...problems...this way. extern bool turret_weapon_has_flags(ship_weapon *swp, int flags); extern bool turret_weapon_has_flags2(ship_weapon *swp, int flags); 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 //Assert(system_info->type == SUBSYSTEM_TURRET); //WMC - find the first weapon, if there is one if (swp->num_primary_banks || swp->num_secondary_banks) { // check if beam or flak using weapon flags if (turret_weapon_has_flags(swp, WIF_BEAM)) { sprintf(outstr, "%s", XSTR("Beam turret", 1567)); }else if (turret_weapon_has_flags(swp, WIF_FLAK)) { sprintf(outstr, "%s", XSTR("Flak turret", 1566)); } else { if (!turret_weapon_has_subtype(swp, WP_MISSILE) && turret_weapon_has_subtype(swp, WP_LASER)) { // ballistic too! - Goober5000 if (turret_weapon_has_flags2(swp, WIF2_BALLISTIC)) { sprintf(outstr, "%s", XSTR("Turret", 1487)); } // the TVWP has some primaries flagged as bombs else if (turret_weapon_has_flags(swp, WIF_BOMB)) { sprintf(outstr, "%s", XSTR("Missile lnchr", 1569)); } else { sprintf(outstr, "%s", XSTR("Laser turret", 1568)); } } else if (turret_weapon_has_subtype(swp, WP_MISSILE)) { sprintf(outstr, "%s", XSTR("Missile lnchr", 1569)); } else { // Illegal subtype Int3(); 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")); } } // ------------------------------------------------------------------------------------- // hud_render_target_ship_info() // // Render the data for a ship on the target monitor. Called by hud_render_target_ship(). // void hud_render_target_ship_info(object *target_objp) { ship *target_shipp; ship_info *target_sip; int w, h, screen_integrity = 1; char outstr[256]; float ship_integrity, shield_strength; Assert(target_objp); // Goober5000 Assert(target_objp->type == OBJ_SHIP); target_shipp = &Ships[target_objp->instance]; target_sip = &Ship_info[target_shipp->ship_info_index]; if (Cmdline_wcsaga && (target_shipp->wingnum != -1) && (target_shipp->team != Player_ship->team)) { strcpy( outstr, ""); } else { strcpy( outstr, target_shipp->ship_name ); } if ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) { hud_set_iff_color(target_objp, 1); } else { // Print out ship name, with wing name if it exists if ( hud_targetbox_maybe_flash(TBOX_FLASH_NAME) ) { hud_set_iff_color(target_objp, 1); } else { hud_set_iff_color(target_objp); } } // maybe do some translation if (Lcl_gr) { lcl_translate_targetbox_name(outstr); } emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, outstr); // print out ship class char temp_name[NAME_LENGTH+2] = ""; // if this ship has an alternate type name if(target_shipp->alt_type_index >= 0){ mission_parse_lookup_alt_index(target_shipp->alt_type_index, temp_name); } else { strcpy(temp_name, Ship_info[target_shipp->ship_info_index].name); end_string_at_first_hash_symbol(temp_name); } if (Lcl_gr) { lcl_translate_targetbox_name(temp_name); } emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, temp_name); 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 = fl2i(ship_integrity+0.5f); 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 ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) { // hud_set_bright_color(); hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT); } else { hud_targetbox_maybe_flash(TBOX_FLASH_HULL); } emp_hud_printf(Targetbox_coords[gr_screen.res][TBOX_HULL][0]-w, Targetbox_coords[gr_screen.res][TBOX_HULL][1], EG_TBOX_HULL, "%s", outstr); hud_set_gauge_color(HUD_TARGET_MONITOR); // 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 = fl2i(shield_strength+0.5f); if ( screen_integrity < 0 ) { screen_integrity = 0; } if ( screen_integrity == 0 ) { if ( shield_strength > 0 ) { screen_integrity = 1; } } // Goober5000 - don't flash if this subsystem can't be destroyed if ( ship_subsys_takes_damage(Player_ai->targeted_subsys) ) { if ( screen_integrity <= 0 ){ hud_targetbox_start_flash(TBOX_FLASH_SUBSYS); // need to flash 0% continuously hud_targetbox_maybe_flash(TBOX_FLASH_SUBSYS); } } // PRINT SUBSYS NAME // hud_set_default_color(); // get turret subsys name if (Player_ai->targeted_subsys->system_info->type == SUBSYSTEM_TURRET) { get_turret_subsys_name(&Player_ai->targeted_subsys->weapons, outstr); } else { sprintf(outstr, "%s", Player_ai->targeted_subsys->system_info->name); } hud_targetbox_truncate_subsys_name(outstr); gr_printf(Target_window_coords[gr_screen.res][0]+2, Target_window_coords[gr_screen.res][1]+Target_window_coords[gr_screen.res][3]-h, outstr); // 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); gr_printf(Target_window_coords[gr_screen.res][0]+Target_window_coords[gr_screen.res][2]-w-1, Target_window_coords[gr_screen.res][1]+Target_window_coords[gr_screen.res][3] - h, "%s", outstr); } hud_set_gauge_color(HUD_TARGET_MONITOR); } // print out 'disabled' on the monitor if the target is disabled if ( (target_shipp->flags & SF_DISABLED) || (ship_subsys_disrupted(target_shipp, SUBSYSTEM_ENGINE)) ) { if ( target_shipp->flags & SF_DISABLED ) { sprintf(outstr, XSTR( "DISABLED", 342)); } else { sprintf(outstr, XSTR( "DISRUPTED", 343)); } gr_get_string_size(&w,&h,outstr); gr_printf(Target_window_coords[gr_screen.res][0]+Target_window_coords[gr_screen.res][2]/2 - w/2 - 1, Target_window_coords[gr_screen.res][1]+Target_window_coords[gr_screen.res][3] - 2*h, "%s", outstr); } hud_targetbox_show_extra_ship_info(target_shipp, target_objp); } // call to draw the integrity bar that is on the right of the target monitor void hud_blit_target_integrity(int disabled,int force_obj_num) { object *objp; int clip_h,w,h; char buf[16]; int current_ts; if ( Target_view_integrity_gauge.first_frame == -1 ) return; if ( disabled ) { GR_AABITMAP(Target_view_integrity_gauge.first_frame, Integrity_bar_coords[gr_screen.res][0], Integrity_bar_coords[gr_screen.res][1]); return; } if(force_obj_num == -1){ Assert(Player_ai->target_objnum >= 0 ); objp = &Objects[Player_ai->target_objnum]; } else { // Goober5000: what the... this probably should be changed //objp = &Objects[Player_ai->target_objnum]; objp = &Objects[force_obj_num]; } clip_h = fl2i( (1 - Pl_target_integrity) * Integrity_bar_coords[gr_screen.res][3] ); // print out status of ship if ( (Ships[objp->instance].flags & SF_DISABLED) || (ship_subsys_disrupted(&Ships[objp->instance], SUBSYSTEM_ENGINE)) ) { sprintf(buf,XSTR( "dis", 344)); current_ts = TS_DIS; } else { if ( Pl_target_integrity > 0.9 ) { sprintf(buf,XSTR( "ok", 345)); current_ts = TS_OK; } else if ( Pl_target_integrity > 0.2 ) { sprintf(buf,XSTR( "dmg", 346)); current_ts = TS_DMG; } else { sprintf(buf,XSTR( "crt", 347)); current_ts = TS_CRT; } } if ( Last_ts != -1 && current_ts != Last_ts ) { hud_targetbox_start_flash(TBOX_FLASH_STATUS); } Last_ts = current_ts; hud_targetbox_maybe_flash(TBOX_FLASH_STATUS); emp_hud_string(Integrity_string_coords[gr_screen.res][0], Integrity_string_coords[gr_screen.res][1], EG_TBOX_INTEG, buf); hud_set_gauge_color(HUD_TARGET_MONITOR); bm_get_info(Target_view_integrity_gauge.first_frame,&w,&h); if ( clip_h > 0 ) { // draw the dark portion GR_AABITMAP_EX(Target_view_integrity_gauge.first_frame, Integrity_bar_coords[gr_screen.res][0], Integrity_bar_coords[gr_screen.res][1], w, clip_h,0,0); } if ( clip_h <= Integrity_bar_coords[gr_screen.res][3] ) { // draw the bright portion GR_AABITMAP_EX(Target_view_integrity_gauge.first_frame+1, Integrity_bar_coords[gr_screen.res][0], Integrity_bar_coords[gr_screen.res][1]+clip_h,w,h-clip_h,0,clip_h); } } // determine if the subsystem is in line-of sight, without taking into accout 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 ) { vm_vec_unrotate(&subobj_pos, &subsys->system_info->pnt, &target_objp->orient); vm_vec_add2(&subobj_pos, &target_objp->pos); // 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.sx; *sy = (int) subobj_vertex.sy; gr_unsize_screen_pos( sx, sy ); } return rval; } 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 hud_maybe_render_cargo_scan(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; // hud_set_default_color(); hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT); // draw horizontal scan line x1 = Cargo_scan_coords[gr_screen.res][0]; y1 = fl2i(0.5f + Cargo_scan_coords[gr_screen.res][1] + ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_coords[gr_screen.res][3] )); x2 = x1 + Cargo_scan_coords[gr_screen.res][2]; gr_line(x1, y1, x2, y1); // RT Changed this to be optional if(Cmdline_dualscanlines) { // added 2nd horizontal scan line - phreak y1 = fl2i(Cargo_scan_coords[gr_screen.res][1] + Cargo_scan_coords[gr_screen.res][3] - ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_coords[gr_screen.res][3] )); gr_line(x1, y1, x2, y1); } // draw vertical scan line x1 = fl2i(0.5f + Cargo_scan_coords[gr_screen.res][0] + ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_coords[gr_screen.res][2] )); y1 = Cargo_scan_coords[gr_screen.res][1]; y2 = y1 + Cargo_scan_coords[gr_screen.res][3]; gr_line(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_coords[gr_screen.res][2] + Cargo_scan_coords[gr_screen.res][0] - ( (i2fl(Player->cargo_inspect_time) / scan_time) * Cargo_scan_coords[gr_screen.res][2] )); gr_line(x1, y1-3, x1, y2-1); } } // Get the eye position for an object at the origin, called from hud_render_target_ship() // input: eye_pos => Global pos for eye (output parameter) // orient => Orientation of object at the origin void hud_targetbox_get_eye(vec3d *eye_pos, matrix *orient, int ship_num) { polymodel *pm; eye *ep; vec3d origin = ZERO_VECTOR; pm = model_get(Ship_info[Ships[ship_num].ship_info_index].model_num); // If there is no eye, don't do anything if ( pm->n_view_positions == 0 ) { return; } ep = &(pm->view_positions[Ships[ship_num].current_viewpoint]); model_find_world_point( eye_pos, &ep->pnt, pm->id, ep->parent, orient, &origin ); } // ------------------------------------------------------------------------------------- // hud_render_target_ship() // // Render a ship to the target monitor // void hud_render_target_ship(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.xyz.z; // use the player's up vector, and construct the viewers orientation matrix up_vector = Player_obj->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); // set camera eye to eye of ship relative to origin // hud_targetbox_get_eye(&camera_eye, &camera_orient, Player_obj->instance); // RT, changed scaling here hud_render_target_setup(&camera_eye, &camera_orient, target_sip->closeup_zoom); // model_clear_instance(target_shipp->modelnum); ship_model_start( target_objp ); if (Targetbox_wire!=0) { int is_bright = 1; if (ship_is_tagged(target_objp)) model_set_outline_color_fast(iff_get_color(IFF_COLOR_TAGGED, is_bright)); else { model_set_outline_color_fast(iff_get_color_by_team(target_shipp->team, Player_ship->team, is_bright)); } flags = (Cmdline_nohtl) ? MR_SHOW_OUTLINE : MR_SHOW_OUTLINE_HTL; if (Targetbox_wire==1) flags |=MR_NO_POLYS; } if (target_sip->hud_target_lod >= 0) { model_set_detail_level(target_sip->hud_target_lod); } // maybe render a special hud-target-only model if(target_sip->model_num_hud >= 0){ model_render( target_sip->model_num_hud, &target_objp->orient, &obj_pos, flags | MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_AUTOCENTER | MR_NO_FOGGING); } else { model_render( target_sip->model_num, &target_objp->orient, &obj_pos, flags | MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_AUTOCENTER | MR_NO_FOGGING, -1, -1, target_shipp->replacement_textures); } ship_model_stop( target_objp ); sx = 0; sy = 0; // check if subsystem target has changed if ( Player_ai->targeted_subsys == Player_ai->last_subsys_target ) { vec3d save_pos; 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 ); } if ( subsys_in_view ) { draw_brackets_square_quick(sx - 10, sy - 10, sx + 10, sy + 10); } else { draw_brackets_diamond_quick(sx - 10, sy - 10, sx + 10, sy + 10); } } } hud_render_target_close(); } HUD_reset_clip(); hud_blit_target_foreground(); hud_blit_target_integrity(0,OBJ_INDEX(target_objp)); hud_set_gauge_color(HUD_TARGET_MONITOR); hud_render_target_ship_info(target_objp); hud_maybe_render_cargo_scan(target_sip); } // ------------------------------------------------------------------------------------- // hud_render_target_debris() // // Render a piece of debris on the target monitor // void hud_render_target_debris(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; int target_team; float factor; int flags=0; debrisp = &Debris[target_objp->instance]; //target_sip = &Ship_info[debrisp->ship_info_index]; target_team = obj_team(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 up_vector = Player_obj->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); if (Targetbox_wire!=0) { model_set_outline_color(255,255,255); flags = (Cmdline_nohtl) ? MR_SHOW_OUTLINE : MR_SHOW_OUTLINE_HTL; if (Targetbox_wire==1) flags |=MR_NO_POLYS; } hud_render_target_setup(&camera_eye, &camera_orient, 0.5f); model_clear_instance(debrisp->model_num); // This calls the colour that doesnt get reset submodel_render( debrisp->model_num, debrisp->submodel_num, &target_objp->orient, &obj_pos, flags | MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_NO_FOGGING ); hud_render_target_close(); } HUD_reset_clip(); hud_blit_target_foreground(); hud_blit_target_integrity(1); // print out ship class that debris came from char printable_ship_class[NAME_LENGTH]; strcpy(printable_ship_class, Ship_info[debrisp->ship_info_index].name); end_string_at_first_hash_symbol(printable_ship_class); emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, printable_ship_class); emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, XSTR( "debris", 348)); } // ------------------------------------------------------------------------------------- // hud_render_target_weapon() // // Render a missile or a missile view to the target monitor // void hud_render_target_weapon(object *target_objp) { vec3d obj_pos = ZERO_VECTOR; vec3d camera_eye = ZERO_VECTOR; matrix camera_orient = IDENTITY_MATRIX; vec3d orient_vec, up_vector; 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; float factor; 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]; is_homing = FALSE; if ( target_wip->wi_flags & WIF_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 ) { 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; if ( is_homing && is_player_missile ) { ship *homing_shipp = &Ships[wp->homing_object->instance]; ship_info *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->replacement_textures; hud_target_lod = homing_sip->hud_target_lod; } if (Targetbox_wire!=0) { int is_bright = 0; model_set_outline_color_fast(iff_get_color_by_team(target_team, Player_ship->team, is_bright)); flags = (Cmdline_nohtl) ? MR_SHOW_OUTLINE : MR_SHOW_OUTLINE_HTL; if (Targetbox_wire==1) flags |=MR_NO_POLYS; } // 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 == FALSE ) factor = 2*target_objp->radius; else factor = vm_vec_dist_quick(&viewer_obj->pos, &viewed_obj->pos); // use the viewer's up vector, and construct the viewers orientation matrix up_vector = viewer_obj->orient.vec.uvec; vm_vector_2_matrix(&camera_orient,&orient_vec,&up_vector,NULL); // normalize the vector from the viewer to the viwed target, and scale by a factor to calculate // the objects position vm_vec_copy_scale(&obj_pos,&orient_vec,factor); hud_render_target_setup(&camera_eye, &camera_orient, View_zoom/3); model_clear_instance(viewed_model_num); if (hud_target_lod >= 0) { model_set_detail_level(hud_target_lod); } model_render( viewed_model_num, &viewed_obj->orient, &obj_pos, flags | MR_NO_LIGHTING | MR_LOCK_DETAIL | MR_AUTOCENTER | MR_IS_MISSILE | MR_NO_FOGGING, -1, -1, replacement_textures); hud_render_target_close(); } HUD_reset_clip(); if ( is_homing == TRUE ) { hud_blit_target_foreground(); } else { hud_blit_target_foreground(); } hud_blit_target_integrity(1); // hud_set_default_color(); hud_set_gauge_color(HUD_TARGET_MONITOR); // print out the weapon class name sprintf( outstr,"%s", target_wip->name ); gr_get_string_size(&w,&h,outstr); // drop name past the # sign end_string_at_first_hash_symbol(outstr); emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_NAME][0], Targetbox_coords[gr_screen.res][TBOX_NAME][1], EG_TBOX_NAME, outstr); // If a homing weapon, show time to impact if ( is_homing ) { float dist, speed; dist = vm_vec_dist(&target_objp->pos, &wp->homing_object->pos); speed = vm_vec_mag(&target_objp->phys_info.vel); if ( speed > 0 ) { sprintf(outstr, NOX("impact: %.1f sec"), dist/speed); } else { sprintf(outstr, XSTR( "unknown", 349)); } emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_CLASS][0], Targetbox_coords[gr_screen.res][TBOX_CLASS][1], EG_TBOX_CLASS, outstr); } } // ------------------------------------------------------------------------------------- // hud_render_target_model() will render the target in the small targetting box. The box // is then shaded to give a monochrome effect // void hud_render_target_model() { object *target_objp; if ( !hud_gauge_active(HUD_TARGET_MONITOR) ) return; if ( Player_ai->target_objnum == -1) return; if ( Target_static_playing ) return; target_objp = &Objects[Player_ai->target_objnum]; // Draw the background frame hud_render_target_background(); switch ( target_objp->type ) { case OBJ_SHIP: hud_render_target_ship(target_objp); break; case OBJ_DEBRIS: hud_render_target_debris(target_objp); break; case OBJ_WEAPON: hud_render_target_weapon(target_objp); break; case OBJ_ASTEROID: hud_render_target_asteroid(target_objp); break; case OBJ_JUMP_NODE: hud_render_target_jump_node(target_objp); break; default: // Error(LOCATION, "Trying to show object type %d on target monitor\n", target_objp->type); hud_cease_targeting(); break; } // end switch } void hud_cargo_scan_update(object *targetp, float frametime) { char outstr[256]; // temp buffer for sprintf'ing hud output int hx, hy; // Account for HUD shaking hx = fl2i(HUD_offset_x); hy = fl2i(HUD_offset_y); // display cargo inspection status if ( targetp->type == OBJ_SHIP ) { if ( player_inspect_cargo(frametime, outstr) ) { if ( hud_gauge_active(HUD_TARGET_MONITOR) ) { if ( Player->cargo_inspect_time > 0 ) { hud_targetbox_start_flash(TBOX_FLASH_CARGO); } // Print out what the cargo is if ( hud_gauge_maybe_flash(HUD_TARGET_MONITOR) == 1 ) { // hud_set_bright_color(); hud_set_gauge_color(HUD_TARGET_MONITOR, HUD_C_BRIGHT); } else { hud_targetbox_maybe_flash(TBOX_FLASH_CARGO); } emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_CARGO][0]+hx, Targetbox_coords[gr_screen.res][TBOX_CARGO][1]+hy, EG_TBOX_CARGO, outstr); hud_set_gauge_color(HUD_TARGET_MONITOR); } } } // end if (is_ship) } // ----------------------------------------------------------------------------------- // hud_show_target_data() will display the data about the target in and // around the targetting window // void hud_show_target_data(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; hud_set_gauge_color(HUD_TARGET_MONITOR); 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); gr_get_string_size(&w,&h,outstr); emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_DIST][0]+hx, Targetbox_coords[gr_screen.res][TBOX_DIST][1]+hy, EG_TBOX_DIST, outstr); #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); // current_target_speed = target_objp->phys_info.fspeed; 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_unit_multiplier > 0.0f ) { // use a different displayed speed scale displayed_target_speed = current_target_speed * Hud_unit_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); emp_hud_string(Targetbox_coords[gr_screen.res][TBOX_SPEED][0]+hx, Targetbox_coords[gr_screen.res][TBOX_SPEED][1]+hy, EG_TBOX_SPEED, outstr); // // 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 = 5; dy = gr_get_font_height() + 1; sy = 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(outstr,"AI: %s",Submode_text[aip->submode]); sprintf(outstr2," / %s",Submode_text[aip->submode]); strcat(outstr,outstr2); break; case AIM_STRAFE: Assert(aip->submode <= AIS_STRAFE_POSITION); // Must be <= largest chase submode value. // sprintf(outstr,"AI: %s",Strafe_submode_text[aip->submode-AIS_STRAFE_ATTACK]); sprintf(outstr2," / %s",Strafe_submode_text[aip->submode-AIS_STRAFE_ATTACK]); strcat(outstr,outstr2); break; case AIM_WAYPOINTS: // gr_printf(sx, sy, "Wpnum: %i",aip->wp_index); sprintf(outstr2," / Wpnum: %i",aip->wp_index); strcat(outstr,outstr2); break; default: break; } gr_printf(sx, sy, outstr); sy += dy; gr_printf(sx, sy, "Max speed = %d, (%d%%)", (int) shipp->current_max_speed, (int) (100.0f * vm_vec_mag(&target_objp->phys_info.vel)/shipp->current_max_speed)); sy += dy; // data can be found in target montior // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+3, TARGET_WINDOW_Y1+5*h, "Shields: %d", (int) shield_get_strength(&Objects[Player_ai->target_objnum])); if (aip->target_objnum != -1) { char target_str[32]; float dot, dist; vec3d v2t; if (aip->target_objnum == Player_obj-Objects) strcpy(target_str, "Player!"); else sprintf(target_str, "%s", Ships[Objects[aip->target_objnum].instance].ship_name); // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+4*h, "Target: %s", target_str); gr_printf(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 montior // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+3, TARGET_WINDOW_Y1+6*h, "Targ dist: %5.1f", dist); // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+5*h, "Targ dot: %3.2f", dot); gr_printf(sx, sy, "Targ dot: %3.2f", dot); sy += dy; // gr_printf(TARGET_WINDOW_X1+TARGET_WINDOW_WIDTH+2, TARGET_WINDOW_Y1+6*h, "Targ dst: %3.2f", dist); gr_printf(sx, sy, "Targ dst: %3.2f", dist); sy += dy; if ( aip->targeted_subsys != NULL ) { sprintf(outstr, "Subsys: %s", aip->targeted_subsys->system_info->name); gr_printf(sx, sy, outstr); } sy += dy; } // print out energy transfer information on the ship sy = 70; sprintf(outstr,"MAX G/E: %.0f/%.0f",shipp->weapon_energy,shipp->current_max_speed); gr_printf(sx, sy, 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(sx, sy, 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 == Player_obj-Objects) { 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(sx, sy, "#%i: %s", Enemy_attacker-Objects, Ships[Enemy_attacker->instance].ship_name); sy += dy; gr_printf(sx, sy, "Targ dist: %5.1f", dist); sy += dy; gr_printf(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; itarget_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(sx, sy, "Targ size: %dx%d", Hud_target_w, Hud_target_h ); sy += dy; polymodel *pm = model_get(sip->model_num); gr_printf(sx, sy, "POF:%s", pm->filename ); sy += dy; gr_printf(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 = 400; sy = 100; dy = gr_get_font_height(); sprintf(outstr,"Num primaries: %d", swp->num_primary_banks); gr_printf(sx,sy,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]].name); gr_printf(sx,sy,outstr); sy += dy; } sy += dy; sprintf(outstr,"Num secondaries: %d", swp->num_secondary_banks); gr_printf(sx,sy,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]].name); gr_printf(sx,sy,outstr); sy += dy; } } //XSTR:ON #endif } // called at the start of each level void hud_targetbox_static_init() { Target_static_next = 0; Target_static_playing = 0; } // determine if we should draw static on top of the target box int hud_targetbox_static_maybe_blit(float frametime) { float sensors_str; // on lowest skill level, don't show static on target monitor if ( Game_skill_level == 0 ) return 0; // if multiplayer observer, don't show static if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){ return 0; } 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 ) { // hud_set_default_color(); hud_set_gauge_color(HUD_TARGET_MONITOR); hud_anim_render(&Target_static, frametime, 1); if ( Target_static_looping == -1 ) { Target_static_looping = snd_play_looping(&Snds[SND_STATIC]); } } else { if ( Target_static_looping != -1 ) { snd_stop(Target_static_looping); Target_static_looping = -1; } } return Target_static_playing; } // start the targetbox item flashing for duration ms // input: index => TBOX_FLASH_ #define // 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][0] = timestamp(duration); } // stop flashing a specific targetbox item void hud_targetbox_end_flash(int index) { Targetbox_flash_timers[index][0] = 1; } // determine if a given flashing index is bright or not int hud_targetbox_is_bright(int index) { return (Targetbox_flash_flags & (1<