2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Hud/HUDshield.cpp $
15 * C file for the display and management of the HUD shield
18 * Revision 1.5 2005/10/01 22:04:58 taylor
19 * fix FS1 (de)briefing voices, the directory names are different in FS1
20 * hard code the table values so that the fs1.vp file isn't needed
21 * hard code a mission fix for sm2-08a since a have no idea how to fix it otherwise
22 * generally cleanup some FS1 code
23 * fix volume sliders in the options screen that never went all the way up
25 * Revision 1.4 2002/07/13 06:46:48 theoddone33
28 * Revision 1.3 2002/06/09 04:41:21 relnev
29 * added copyright header
31 * Revision 1.2 2002/05/07 03:16:45 theoddone33
32 * The Great Newline Fix
34 * Revision 1.1.1.1 2002/05/03 03:28:09 root
38 * 12 8/27/99 10:36a Dave
39 * Impose a 2% penalty for hitting the shield balance key.
41 * 11 8/23/99 11:34a Dave
42 * Fixed shield intensity rendering problems.
44 * 10 8/01/99 12:39p Dave
45 * Added HUD contrast control key (for nebula).
47 * 9 7/22/99 4:00p Dave
48 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
50 * 8 6/10/99 3:43p Dave
51 * Do a better job of syncing text colors to HUD gauges.
53 * 7 1/07/99 9:06a Jasen
56 * 6 12/30/98 8:57a Jasen
57 * updated coords for hi res
59 * 5 12/28/98 3:17p Dave
60 * Support for multiple hud bitmap filenames for hi-res mode.
62 * 4 12/21/98 5:02p Dave
63 * Modified all hud elements to be multi-resolution friendly.
65 * 3 12/14/98 1:15p Jasen
66 * added new HUD shield gauges
68 * 2 10/07/98 10:53a Dave
71 * 1 10/07/98 10:49a Dave
73 * 35 9/19/98 3:11p Adam
74 * Added new hardcoded values for Hud_shield_filenames
76 * 34 8/25/98 1:48p Dave
77 * First rev of EMP effect. Player side stuff basically done. Next comes
80 * 33 5/17/98 3:32p Lawrance
81 * Make shield gauge more readable when flashing
83 * 32 4/25/98 5:39p Dave
84 * Removed an unneeded assert.
86 * 31 4/25/98 3:56p Mike
87 * Make player's shield icon flash when Fred tells it to.
89 * 30 4/25/98 2:00p Dave
90 * Installed a bunch of multiplayer context help screens. Reworked ingame
91 * join ship select screen. Fix places where network timestamps get hosed.
93 * 29 4/21/98 12:19a Allender
94 * only play equalize shield sound if player equalizes shields
96 * 28 3/26/98 5:26p John
97 * added new paging code. nonfunctional.
99 * 27 3/21/98 3:35p Lawrance
100 * Tweak position of numeric integrity for target
102 * 26 3/14/98 4:59p Lawrance
103 * Flash shield/ship icons when ships are hit
105 * 25 3/02/98 5:42p John
106 * Removed WinAVI stuff from Freespace. Made all HUD gauges wriggle from
107 * afterburner. Made gr_set_clip work good with negative x &y. Made
108 * model_caching be on by default. Made each cached model have it's own
109 * bitmap id. Made asteroids not rotate when model_caching is on.
111 * 24 2/22/98 12:19p John
112 * Externalized some strings
114 * 23 2/12/98 4:58p Lawrance
115 * Change to new flashing method.
117 * 22 1/12/98 11:16p Lawrance
118 * Wonderful HUD config.
120 * 21 1/08/98 4:36p Lawrance
121 * Fix bug in shield drawing code.
123 * 20 1/05/98 9:38p Lawrance
124 * Implement flashing HUD gauges.
126 * 19 1/02/98 9:10p Lawrance
127 * Big changes to how colors get set on the HUD.
129 * 18 12/29/97 9:48p Mike
130 * Prevent indexing before array start when quadrant_num = -1.
132 * 17 12/01/97 12:27a Lawrance
133 * redo default alpha color for HUD, make it easy to modify in the future
135 * 16 11/18/97 5:58p Lawrance
136 * flash escort view info when that ship is taking hits
138 * 15 11/18/97 1:21p Mitri
139 * ALAN: be sure to only draw shield icons for targets that are ships
141 * 14 11/17/97 6:37p Lawrance
142 * new gauges: extended target view, new lock triangles, support ship view
144 * 13 11/13/97 10:46p Lawrance
145 * implemented new escort view, damage view and weapons
147 * 12 11/12/97 9:42a Lawrance
148 * show player ship integrity above shield icon
150 * 11 11/11/97 5:06p Lawrance
151 * fix bug with flashing frequency of hull
153 * 10 11/09/97 11:27p Lawrance
154 * move target shield icon closer to center
156 * 9 11/09/97 4:39p Lawrance
157 * don't draw mini ship icon anymore
159 * 8 11/08/97 11:08p Lawrance
160 * implement new "mini-shield" view that sits near bottom of reticle
162 * 7 11/05/97 11:21p Lawrance
163 * implement dynamic alpha on the shields
165 * 6 11/04/97 8:34p Lawrance
166 * fix warning: remove unused variable
168 * 5 11/04/97 7:49p Lawrance
169 * integrating new HUD reticle and shield icons
171 * 4 10/24/97 5:51p Lawrance
172 * don't show shield % if ship has no shields
174 * 3 9/03/97 4:32p John
175 * changed bmpman to only accept ani and pcx's. made passing .pcx or .ani
176 * to bm_load functions not needed. Made bmpman keep track of palettes
177 * for bitmaps not mapped into game palettes.
179 * 2 8/25/97 12:24a Lawrance
180 * implemented HUD shield management
182 * 1 8/24/97 10:31p Lawrance
190 #include "hudtarget.h"
191 #include "hudtargetbox.h"
195 #include "freespace.h"
198 #include "hudshield.h"
199 #include "hudescort.h"
203 #define NUM_SHIELD_LEVELS 8
205 #define SHIELD_TRANSFER_PERCENT 0.083f // 1/12 total shield strength
207 #define SHIELD_HIT_DURATION_SHORT 300 // time a shield quadrant flashes after being hit
208 #define SHIELD_FLASH_INTERVAL_FAST 200 // time between shield quadrant flashes
210 // now read in from hud.tbl
211 #define MAX_SHIELD_ICONS 40
212 int Hud_shield_filename_count = 0;
213 char Hud_shield_filenames[MAX_SHIELD_ICONS][MAX_FILENAME_LEN];
215 char Shield_mini_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
220 hud_frames Shield_gauges[MAX_SHIELD_ICONS];
222 static int Player_shield_coords[GR_NUM_RESOLUTIONS][2] =
232 static int Target_shield_coords[GR_NUM_RESOLUTIONS][2] =
242 static int Hud_shield_inited = 0;
244 int Shield_mini_coords[GR_NUM_RESOLUTIONS][2] = {
253 // draw on the mini shield icon what the ship integrity is
254 int Hud_mini_3digit[GR_NUM_RESOLUTIONS][3] = {
262 int Hud_mini_2digit[GR_NUM_RESOLUTIONS][3] = {
270 int Hud_mini_1digit[GR_NUM_RESOLUTIONS][3] = {
278 int Hud_mini_base[GR_NUM_RESOLUTIONS][2] = {
287 int Shield_mini_loaded = 0;
288 hud_frames Shield_mini_gauge;
290 #define SHIELD_HIT_PLAYER 0
291 #define SHIELD_HIT_TARGET 1
292 static shield_hit_info Shield_hit_data[2];
294 // translate between clockwise-from-top shield quadrant ordering to way quadrants are numbered in the game
295 ubyte Quadrant_xlate[4] = {1,0,2,3};
297 void hud_shield_game_init()
300 char name[MAX_FILENAME_LEN+1] = "";
304 read_file_text("hud.tbl");
307 Hud_shield_filename_count = 0;
308 required_string("#Shield Icons Begin");
309 while(!optional_string("#End")){
310 required_string("$Shield:");
312 stuff_string(name, F_NAME, NULL);
315 SDL_assert(Hud_shield_filename_count < MAX_SHIELD_ICONS);
316 if(Hud_shield_filename_count < MAX_SHIELD_ICONS){
317 SDL_strlcpy(Hud_shield_filenames[Hud_shield_filename_count++], name, MAX_FILENAME_LEN);
320 } catch (parse_error_t rval) {
321 Error(LOCATION, "Unable to parse hud.tbl! Code = %i.\n", (int)rval);
324 // hardcoded FS1 table values
327 Hud_shield_filename_count = 0;
330 for (i = 1; i < 14; i++) {
331 SDL_snprintf(Hud_shield_filenames[Hud_shield_filename_count++], MAX_FILENAME_LEN, "shield-f%02d", i);
332 SDL_assert(Hud_shield_filename_count < MAX_SHIELD_ICONS);
336 for (i = 1; i < 11; i++) {
337 SDL_snprintf(Hud_shield_filenames[Hud_shield_filename_count++], MAX_FILENAME_LEN, "shield-b%02d", i);
338 SDL_assert(Hud_shield_filename_count < MAX_SHIELD_ICONS);
343 // called at the start of each level from HUD_init. Use Hud_shield_init so we only init Shield_gauges[] once.
344 void hud_shield_level_init()
348 hud_shield_hit_reset(1); // reset for the player
350 if ( Hud_shield_inited ) {
354 for ( i = 0; i < MAX_SHIELD_ICONS; i++ ) {
355 Shield_gauges[i].first_frame = -1;
356 Shield_gauges[i].num_frames = 0;
359 Hud_shield_inited = 1;
361 if ( !Shield_mini_loaded ) {
362 Shield_mini_gauge.first_frame = bm_load_animation(Shield_mini_fname[gr_screen.res], &Shield_mini_gauge.num_frames);
363 if ( Shield_mini_gauge.first_frame == -1 ) {
364 Warning(LOCATION, "Could not load in the HUD shield ani: Shield_mini_fname[gr_screen.res]\n");
367 Shield_mini_loaded = 1;
371 int hud_shield_maybe_flash(int gauge, int target_index, int shield_offset)
374 shield_hit_info *shi;
376 shi = &Shield_hit_data[target_index];
378 if ( !timestamp_elapsed(shi->shield_hit_timers[shield_offset]) ) {
379 if ( timestamp_elapsed(shi->shield_hit_next_flash[shield_offset]) ) {
380 shi->shield_hit_next_flash[shield_offset] = timestamp(SHIELD_FLASH_INTERVAL_FAST);
381 shi->shield_show_bright ^= (1<<shield_offset); // toggle between default and bright frames
384 if ( shi->shield_show_bright & (1<<shield_offset) ) {
385 // hud_set_bright_color();
386 hud_set_gauge_color(gauge, HUD_C_BRIGHT);
389 hud_set_gauge_color(gauge, HUD_C_NORMAL);
390 // hud_set_default_color();
397 // ------------------------------------------------------------------
400 // Show the players shield strength and integrity
402 void hud_shield_show(object *objp)
405 int hud_color_index, range;
411 if ( objp->type != OBJ_SHIP )
414 sp = &Ships[objp->instance];
415 sip = &Ship_info[sp->ship_info_index];
417 if ( sip->shield_icon_index == 255 ) {
421 if (objp == Player_obj) {
422 hud_set_gauge_color(HUD_PLAYER_SHIELD_ICON);
424 hud_set_gauge_color(HUD_TARGET_SHIELD_ICON);
427 // load in shield frames if not already loaded
428 // DDOI - shield_icon_index is unsigned
429 // SDL_assert(sip->shield_icon_index >= 0 && sip->shield_icon_index < Hud_shield_filename_count);
430 SDL_assert(sip->shield_icon_index < Hud_shield_filename_count);
432 sgp = &Shield_gauges[sip->shield_icon_index];
434 if ( sgp->first_frame == -1 ) {
435 sgp->first_frame = bm_load_animation(Hud_shield_filenames[sip->shield_icon_index], &sgp->num_frames);
436 if ( sgp->first_frame == -1 ) {
437 Warning(LOCATION, "Could not load in the HUD shield ani: %s\n", Hud_shield_filenames[sip->shield_icon_index]);
442 if ( objp == Player_obj ) {
443 sx = Player_shield_coords[gr_screen.res][0];
444 sy = Player_shield_coords[gr_screen.res][1];
446 sx = Target_shield_coords[gr_screen.res][0];
447 sy = Target_shield_coords[gr_screen.res][1];
450 sx += fl2i(HUD_offset_x);
451 sy += fl2i(HUD_offset_y);
453 // draw the ship first
454 if ( objp == Player_obj ) {
455 hud_shield_maybe_flash(HUD_PLAYER_SHIELD_ICON, SHIELD_HIT_PLAYER, HULL_HIT_OFFSET);
457 hud_shield_maybe_flash(HUD_TARGET_SHIELD_ICON, SHIELD_HIT_TARGET, HULL_HIT_OFFSET);
460 GR_AABITMAP(sgp->first_frame, sx, sy);
462 // draw the four quadrants
464 // Draw shield quadrants at one of NUM_SHIELD_LEVELS
465 max_shield = sip->shields/4.0f;
467 for ( i = 0; i < 4; i++ ) {
469 if ( objp->flags & OF_NO_SHIELDS ) {
473 if ( objp->shields[Quadrant_xlate[i]] < 0.1f ) {
477 range = max(HUD_COLOR_ALPHA_MAX, HUD_color_alpha + 4);
478 hud_color_index = fl2i( (objp->shields[Quadrant_xlate[i]] / max_shield) * range + 0.5);
479 SDL_assert(hud_color_index >= 0 && hud_color_index <= range);
481 if ( hud_color_index < 0 ) {
484 if ( hud_color_index >= HUD_NUM_COLOR_LEVELS ) {
485 hud_color_index = HUD_NUM_COLOR_LEVELS - 1;
489 if ( objp == Player_obj ) {
490 flash = hud_shield_maybe_flash(HUD_PLAYER_SHIELD_ICON, SHIELD_HIT_PLAYER, i);
492 flash = hud_shield_maybe_flash(HUD_TARGET_SHIELD_ICON, SHIELD_HIT_TARGET, i);
496 // gr_set_color_fast(&HUD_color_defaults[hud_color_index]);
497 if ( objp == Player_obj ) {
498 hud_set_gauge_color(HUD_PLAYER_SHIELD_ICON, hud_color_index);
500 hud_set_gauge_color(HUD_TARGET_SHIELD_ICON, hud_color_index);
503 GR_AABITMAP(sgp->first_frame+i+1, sx, sy);
507 // hud_set_default_color();
510 // called at beginning of level to page in all ship icons
511 // used in this level
512 void hud_ship_icon_page_in(ship_info *sip)
516 if ( sip->shield_icon_index == 255 ) {
520 // load in shield frames if not already loaded
521 // DDOI - shield_icon_index is unsigned
522 // SDL_assert(sip->shield_icon_index >= 0 && sip->shield_icon_index < Hud_shield_filename_count);
523 SDL_assert(sip->shield_icon_index < Hud_shield_filename_count);
524 sgp = &Shield_gauges[sip->shield_icon_index];
526 if ( sgp->first_frame == -1 ) {
527 sgp->first_frame = bm_load_animation(Hud_shield_filenames[sip->shield_icon_index], &sgp->num_frames);
528 if ( sgp->first_frame == -1 ) {
529 Warning(LOCATION, "Could not load in the HUD shield ani: %s\n", Hud_shield_filenames[sip->shield_icon_index]);
535 for (i=0; i<sgp->num_frames; i++ ) {
536 bm_page_in_aabitmap(sgp->first_frame+i);
541 // ------------------------------------------------------------------
542 // hud_shield_equalize()
544 // Equalize the four shield quadrants for an object
546 void hud_shield_equalize(object *objp, player *pl)
552 SDL_assert(objp != NULL);
556 SDL_assert(pl != NULL);
560 SDL_assert(objp->type == OBJ_SHIP);
561 if(objp->type != OBJ_SHIP){
565 // are all quadrants equal?
566 for(idx=0; idx<MAX_SHIELD_SECTIONS-1; idx++){
567 if(objp->shields[idx] != objp->shields[idx+1]){
575 strength = get_shield_strength(objp);
576 if ( strength != 0 ) {
577 // maybe impose a 2% penalty - server side and single player only
578 if(!MULTIPLAYER_CLIENT && ((pl->shield_penalty_stamp < 0) || timestamp_elapsed_safe(pl->shield_penalty_stamp, 1000)) ){
581 // reset the penalty timestamp
582 pl->shield_penalty_stamp = timestamp(1000);
585 set_shield_strength(objp, strength);
590 if ( objp == Player_obj ){
591 snd_play( &Snds[SND_SHIELD_XFER_OK] );
595 // ------------------------------------------------------------------
596 // hud_augment_shield_quadrant()
598 // Transfer shield energy to a shield quadrant from the three other
599 // quadrants. Works by trying to transfer a fixed amount of shield
600 // energy from the other three quadrants, taking the same percentage
601 // from each quadrant.
603 // input: objp => object to perform shield transfer on
604 // direction => which quadrant to augment:
610 void hud_augment_shield_quadrant(object *objp, int direction)
612 float full_shields, xfer_amount, energy_avail, percent_to_take, delta;
613 float max_quadrant_val;
616 SDL_assert(direction >= 0 && direction < 4);
617 SDL_assert(objp->type == OBJ_SHIP);
618 full_shields = Ship_info[Ships[objp->instance].ship_info_index].shields;
620 xfer_amount = full_shields * SHIELD_TRANSFER_PERCENT;
621 max_quadrant_val = full_shields/4.0f;
623 if ( (objp->shields[direction] + xfer_amount) > max_quadrant_val )
624 xfer_amount = max_quadrant_val - objp->shields[direction];
626 SDL_assert(xfer_amount >= 0);
627 if ( xfer_amount == 0 ) {
628 // TODO: provide a feedback sound
632 snd_play( &Snds[SND_SHIELD_XFER_OK] );
636 for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
637 if ( i == direction )
639 energy_avail += objp->shields[i];
642 percent_to_take = xfer_amount/energy_avail;
643 if ( percent_to_take > 1.0f )
644 percent_to_take = 1.0f;
646 for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
647 if ( i == direction )
649 delta = percent_to_take * objp->shields[i];
650 objp->shields[i] -= delta;
651 SDL_assert(objp->shields[i] >= 0 );
652 objp->shields[direction] += delta;
653 if ( objp->shields[direction] > max_quadrant_val )
654 objp->shields[direction] = max_quadrant_val;
658 // Try to find a match between filename and the names inside
659 // of Hud_shield_filenames. This will provide us with an
660 // association of ship class to shield icon information.
661 void hud_shield_assign_info(ship_info *sip, char *filename)
665 for ( i = 0; i < Hud_shield_filename_count; i++ ) {
666 if ( !SDL_strcasecmp(filename, Hud_shield_filenames[i]) ) {
667 sip->shield_icon_index = i;
672 void hud_show_mini_ship_integrity(object *objp, int x_force, int y_force)
674 char text_integrity[64];
675 int numeric_integrity;
676 float p_target_integrity,initial_hull;
679 initial_hull = Ship_info[Ships[objp->instance].ship_info_index].initial_hull_strength;
680 if ( initial_hull <= 0 ) {
681 Int3(); // illegal initial hull strength
682 p_target_integrity = 0.0f;
684 p_target_integrity = objp->hull_strength / initial_hull;
685 if (p_target_integrity < 0){
686 p_target_integrity = 0.0f;
690 numeric_integrity = fl2i(p_target_integrity*100 + 0.5f);
691 if(numeric_integrity > 100){
692 numeric_integrity = 100;
694 // SDL_assert(numeric_integrity <= 100);
697 nx = (x_force == -1) ? Hud_mini_base[gr_screen.res][0] : x_force;
698 ny = (y_force == -1) ? Hud_mini_base[gr_screen.res][1] : y_force;
700 // 3 digit hull strength
701 if ( numeric_integrity == 100 ) {
702 nx += Hud_mini_3digit[gr_screen.res][2];
704 // 2 digit hull strength
705 else if ( numeric_integrity < 10 ) {
706 nx += Hud_mini_1digit[gr_screen.res][2];
708 // 1 digit hull strength
710 nx += Hud_mini_2digit[gr_screen.res][2];
713 if ( numeric_integrity == 0 ) {
714 if ( p_target_integrity > 0 ) {
715 numeric_integrity = 1;
719 nx += fl2i( HUD_offset_x );
720 ny += fl2i( HUD_offset_y );
722 SDL_snprintf(text_integrity, SDL_arraysize(text_integrity), "%d", numeric_integrity);
723 if ( numeric_integrity < 100 ) {
724 hud_num_make_mono(text_integrity);
727 gr_string(nx, ny, text_integrity);
730 // Draw the miniature shield icon that is drawn near the reticle
731 void hud_shield_show_mini(object *objp, int x_force, int y_force, int x_hull_offset, int y_hull_offset)
734 int hud_color_index, range, frame_offset;
739 if ( objp->type != OBJ_SHIP ) {
743 sp = &Ships[objp->instance];
744 sip = &Ship_info[sp->ship_info_index];
746 hud_set_gauge_color(HUD_TARGET_MINI_ICON);
748 if (!Shield_mini_loaded)
751 sx = (x_force == -1) ? Shield_mini_coords[gr_screen.res][0]+fl2i(HUD_offset_x) : x_force;
752 sy = (y_force == -1) ? Shield_mini_coords[gr_screen.res][1]+fl2i(HUD_offset_y) : y_force;
754 // draw the ship first
755 hud_shield_maybe_flash(HUD_TARGET_MINI_ICON, SHIELD_HIT_TARGET, HULL_HIT_OFFSET);
756 hud_show_mini_ship_integrity(objp,x_force + x_hull_offset,y_force + y_hull_offset);
758 // draw the four quadrants
759 // Draw shield quadrants at one of NUM_SHIELD_LEVELS
760 max_shield = sip->shields/4.0f;
762 for ( i = 0; i < 4; i++ ) {
764 if ( objp->flags & OF_NO_SHIELDS ) {
768 if ( objp->shields[Quadrant_xlate[i]] < 0.1f ) {
772 if ( hud_shield_maybe_flash(HUD_TARGET_MINI_ICON, SHIELD_HIT_TARGET, i) ) {
778 range = HUD_color_alpha;
779 hud_color_index = fl2i( (objp->shields[Quadrant_xlate[i]] / max_shield) * range + 0.5);
780 SDL_assert(hud_color_index >= 0 && hud_color_index <= range);
782 if ( hud_color_index < 0 ) {
785 if ( hud_color_index >= HUD_NUM_COLOR_LEVELS ) {
786 hud_color_index = HUD_NUM_COLOR_LEVELS - 1;
789 if ( hud_gauge_maybe_flash(HUD_TARGET_MINI_ICON) == 1) {
790 // hud_set_bright_color();
791 hud_set_gauge_color(HUD_TARGET_MINI_ICON, HUD_C_BRIGHT);
793 // gr_set_color_fast(&HUD_color_defaults[hud_color_index]);
794 hud_set_gauge_color(HUD_TARGET_MINI_ICON, hud_color_index);
797 GR_AABITMAP(Shield_mini_gauge.first_frame + frame_offset, sx, sy);
800 // hud_set_default_color();
803 // reset the shield_hit_info data structure
804 void shield_info_reset(shield_hit_info *shi)
808 shi->shield_hit_status = 0;
809 shi->shield_show_bright = 0;
810 for ( i = 0; i < NUM_SHIELD_HIT_MEMBERS; i++ ) {
811 shi->shield_hit_timers[i] = 1;
812 shi->shield_hit_next_flash[i] = 1;
816 // reset the timers and hit flags for the shield gauges
818 // This needs to be called whenever the player selects a new target
820 // input: player => optional parameter (default value 0). This is to indicate that player shield hit
821 // info should be reset. This is normally not the case.
822 // is for the player's current target
823 void hud_shield_hit_reset(int player)
825 shield_hit_info *shi;
828 shi = &Shield_hit_data[SHIELD_HIT_PLAYER];
830 shi = &Shield_hit_data[SHIELD_HIT_TARGET];
833 shield_info_reset(shi);
836 // called once per frame to update the state of Shield_hit_status based on the Shield_hit_timers[]
837 void hud_shield_hit_update()
842 if ( Player_ai->target_objnum >= 0 ) {
846 for ( i = 0; i < limit; i++ ) {
847 for ( j = 0; j < NUM_SHIELD_HIT_MEMBERS; j++ ) {
848 if ( timestamp_elapsed(Shield_hit_data[i].shield_hit_timers[j]) ) {
849 Shield_hit_data[i].shield_hit_status &= ~(1<<j);
850 Shield_hit_data[i].shield_show_bright &= ~(1<<j);
856 // called when a shield quadrant is struct, so we can update the timer that will draw the quadrant
860 // objp => object pointer for ship that has been hit
861 // quadrant => quadrant of shield getting hit (-1 if no shield is present)
862 void hud_shield_quadrant_hit(object *objp, int quadrant)
864 shield_hit_info *shi;
867 if ( objp->type != OBJ_SHIP )
870 hud_escort_ship_hit(objp, quadrant);
871 hud_gauge_popup_start(HUD_TARGET_MINI_ICON);
873 if ( OBJ_INDEX(objp) == Player_ai->target_objnum ) {
874 shi = &Shield_hit_data[SHIELD_HIT_TARGET];
875 } else if ( objp == Player_obj ) {
876 shi = &Shield_hit_data[SHIELD_HIT_PLAYER];
881 if ( quadrant >= 0 ) {
882 num = Quadrant_xlate[quadrant];
883 shi->shield_hit_timers[num] = timestamp(300);
885 shi->shield_hit_timers[HULL_HIT_OFFSET] = timestamp(SHIELD_HIT_DURATION_SHORT);
886 hud_targetbox_start_flash(TBOX_FLASH_HULL);
891 void hudshield_page_in()
893 bm_page_in_aabitmap( Shield_mini_gauge.first_frame, Shield_mini_gauge.num_frames );