]> icculus.org git repositories - taylor/freespace2.git/blob - src/hud/hudshield.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / hud / hudshield.cpp
1 /*
2  * $Logfile: /Freespace2/code/Hud/HUDshield.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * C file for the display and management of the HUD shield
8  *
9  * $Log$
10  * Revision 1.2  2002/05/07 03:16:45  theoddone33
11  * The Great Newline Fix
12  *
13  * Revision 1.1.1.1  2002/05/03 03:28:09  root
14  * Initial import.
15  *
16  * 
17  * 12    8/27/99 10:36a Dave
18  * Impose a 2% penalty for hitting the shield balance key.
19  * 
20  * 11    8/23/99 11:34a Dave
21  * Fixed shield intensity rendering problems.
22  * 
23  * 10    8/01/99 12:39p Dave
24  * Added HUD contrast control key (for nebula).
25  * 
26  * 9     7/22/99 4:00p Dave
27  * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
28  * 
29  * 8     6/10/99 3:43p Dave
30  * Do a better job of syncing text colors to HUD gauges.
31  * 
32  * 7     1/07/99 9:06a Jasen
33  * coords...
34  * 
35  * 6     12/30/98 8:57a Jasen
36  * updated coords for hi res
37  * 
38  * 5     12/28/98 3:17p Dave
39  * Support for multiple hud bitmap filenames for hi-res mode.
40  * 
41  * 4     12/21/98 5:02p Dave
42  * Modified all hud elements to be multi-resolution friendly.
43  * 
44  * 3     12/14/98 1:15p Jasen
45  * added new HUD shield gauges
46  * 
47  * 2     10/07/98 10:53a Dave
48  * Initial checkin.
49  * 
50  * 1     10/07/98 10:49a Dave
51  * 
52  * 35    9/19/98 3:11p Adam
53  * Added new hardcoded values for Hud_shield_filenames
54  * 
55  * 34    8/25/98 1:48p Dave
56  * First rev of EMP effect. Player side stuff basically done. Next comes
57  * AI code.
58  * 
59  * 33    5/17/98 3:32p Lawrance
60  * Make shield gauge more readable when flashing
61  * 
62  * 32    4/25/98 5:39p Dave
63  * Removed an unneeded assert.
64  * 
65  * 31    4/25/98 3:56p Mike
66  * Make player's shield icon flash when Fred tells it to.
67  * 
68  * 30    4/25/98 2:00p Dave
69  * Installed a bunch of multiplayer context help screens. Reworked ingame
70  * join ship select screen. Fix places where network timestamps get hosed.
71  * 
72  * 29    4/21/98 12:19a Allender
73  * only play equalize shield sound if player equalizes shields
74  * 
75  * 28    3/26/98 5:26p John
76  * added new paging code. nonfunctional.
77  * 
78  * 27    3/21/98 3:35p Lawrance
79  * Tweak position of numeric integrity for target
80  * 
81  * 26    3/14/98 4:59p Lawrance
82  * Flash shield/ship icons when ships are hit
83  * 
84  * 25    3/02/98 5:42p John
85  * Removed WinAVI stuff from Freespace.  Made all HUD gauges wriggle from
86  * afterburner.  Made gr_set_clip work good with negative x &y.  Made
87  * model_caching be on by default.  Made each cached model have it's own
88  * bitmap id.  Made asteroids not rotate when model_caching is on.  
89  * 
90  * 24    2/22/98 12:19p John
91  * Externalized some strings
92  * 
93  * 23    2/12/98 4:58p Lawrance
94  * Change to new flashing method.
95  * 
96  * 22    1/12/98 11:16p Lawrance
97  * Wonderful HUD config.
98  * 
99  * 21    1/08/98 4:36p Lawrance
100  * Fix bug in shield drawing code.
101  * 
102  * 20    1/05/98 9:38p Lawrance
103  * Implement flashing HUD gauges.
104  * 
105  * 19    1/02/98 9:10p Lawrance
106  * Big changes to how colors get set on the HUD.
107  * 
108  * 18    12/29/97 9:48p Mike
109  * Prevent indexing before array start when quadrant_num = -1.
110  * 
111  * 17    12/01/97 12:27a Lawrance
112  * redo default alpha color for HUD, make it easy to modify in the future
113  * 
114  * 16    11/18/97 5:58p Lawrance
115  * flash escort view info when that ship is taking hits
116  * 
117  * 15    11/18/97 1:21p Mitri
118  * ALAN: be sure to only draw shield icons for targets that are ships
119  * 
120  * 14    11/17/97 6:37p Lawrance
121  * new gauges: extended target view, new lock triangles, support ship view
122  * 
123  * 13    11/13/97 10:46p Lawrance
124  * implemented new escort view, damage view and weapons
125  * 
126  * 12    11/12/97 9:42a Lawrance
127  * show player ship integrity above shield icon
128  * 
129  * 11    11/11/97 5:06p Lawrance
130  * fix bug with flashing frequency of hull
131  * 
132  * 10    11/09/97 11:27p Lawrance
133  * move target shield icon closer to center
134  * 
135  * 9     11/09/97 4:39p Lawrance
136  * don't draw mini ship icon anymore
137  * 
138  * 8     11/08/97 11:08p Lawrance
139  * implement new "mini-shield" view that sits near bottom of reticle
140  * 
141  * 7     11/05/97 11:21p Lawrance
142  * implement dynamic alpha on the shields
143  * 
144  * 6     11/04/97 8:34p Lawrance
145  * fix warning: remove unused variable
146  * 
147  * 5     11/04/97 7:49p Lawrance
148  * integrating new HUD reticle and shield icons
149  * 
150  * 4     10/24/97 5:51p Lawrance
151  * don't show shield % if ship has no shields
152  * 
153  * 3     9/03/97 4:32p John
154  * changed bmpman to only accept ani and pcx's.  made passing .pcx or .ani
155  * to bm_load functions not needed.   Made bmpman keep track of palettes
156  * for bitmaps not mapped into game palettes.
157  * 
158  * 2     8/25/97 12:24a Lawrance
159  * implemented HUD shield management
160  * 
161  * 1     8/24/97 10:31p Lawrance
162  *
163  * $NoKeywords: $
164  */
165
166 #include "2d.h"
167 #include "object.h"
168 #include "hud.h"
169 #include "hudtarget.h"
170 #include "hudtargetbox.h"
171 #include "hudets.h"
172 #include "player.h"
173 #include "gamesnd.h"
174 #include "freespace.h"
175 #include "bmpman.h"
176 #include "timer.h"
177 #include "hudshield.h"
178 #include "hudescort.h"
179 #include "emp.h"
180 #include "multi.h"
181
182 #define NUM_SHIELD_LEVELS               8
183
184 #define SHIELD_TRANSFER_PERCENT 0.083f          // 1/12 total shield strength
185
186 #define SHIELD_HIT_DURATION_SHORT       300     // time a shield quadrant flashes after being hit
187 #define SHIELD_FLASH_INTERVAL_FAST      200     // time between shield quadrant flashes
188
189 // now read in from hud.tbl
190 #define MAX_SHIELD_ICONS                40
191 int Hud_shield_filename_count = 0;
192 char Hud_shield_filenames[MAX_SHIELD_ICONS][MAX_FILENAME_LEN];
193
194 char Shield_mini_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
195         "targhit1",
196         "targhit1"
197 };
198
199 hud_frames Shield_gauges[MAX_SHIELD_ICONS];
200
201 static int Player_shield_coords[GR_NUM_RESOLUTIONS][2] = 
202 {
203         { // GR_640
204                 396, 379
205         },
206         { // GR_1024
207                 634, 670
208         }
209 };
210
211 static int Target_shield_coords[GR_NUM_RESOLUTIONS][2] = 
212 {
213         { // GR_640
214                 142, 379
215         },
216         { // GR_1024
217                 292, 670
218         }
219 };
220
221 static int Hud_shield_inited = 0;
222
223 int Shield_mini_coords[GR_NUM_RESOLUTIONS][2] = {
224         { // GR_640
225                 305, 291
226         },
227         { // GR_1024
228                 497, 470
229         }
230 };
231
232 // draw on the mini shield icon what the ship integrity is
233 int Hud_mini_3digit[GR_NUM_RESOLUTIONS][3] = {
234         { // GR_640
235                 310, 298, 0
236         },
237         { // GR_1024
238                 502, 477, 0
239         }
240 };
241 int Hud_mini_2digit[GR_NUM_RESOLUTIONS][3] = {
242         { // GR_640
243                 213, 298, 2
244         },
245         { // GR_1024
246                 346, 477, 2
247         }
248 };
249 int Hud_mini_1digit[GR_NUM_RESOLUTIONS][3] = {
250         { // GR_640
251                 316, 298, 6
252         },
253         { // GR_1024
254                 511, 477, 6
255         }
256 };
257 int Hud_mini_base[GR_NUM_RESOLUTIONS][2] = {
258         { // GR_640
259                 310, 298
260         },
261         { // GR_1024
262                 502, 477
263         }
264 };
265         
266 int Shield_mini_loaded = 0;
267 hud_frames Shield_mini_gauge;
268
269 #define SHIELD_HIT_PLAYER               0
270 #define SHIELD_HIT_TARGET               1
271 static shield_hit_info  Shield_hit_data[2];
272
273 // translate between clockwise-from-top shield quadrant ordering to way quadrants are numbered in the game
274 ubyte Quadrant_xlate[4] = {1,0,2,3};
275
276 void hud_shield_game_init()
277 {
278         char name[MAX_FILENAME_LEN+1] = "";
279
280         // read in hud.tbl
281         read_file_text("hud.tbl");
282         reset_parse();
283
284         Hud_shield_filename_count = 0;
285         required_string("#Shield Icons Begin");
286         while(!optional_string("#End")){
287                 required_string("$Shield:");
288
289                 stuff_string(name, F_NAME, NULL);
290
291                 // maybe store
292                 Assert(Hud_shield_filename_count < MAX_SHIELD_ICONS);
293                 if(Hud_shield_filename_count < MAX_SHIELD_ICONS){
294                         strcpy(Hud_shield_filenames[Hud_shield_filename_count++], name);
295                 }
296         }
297 }
298
299 // called at the start of each level from HUD_init.  Use Hud_shield_init so we only init Shield_gauges[] once.
300 void hud_shield_level_init()
301 {
302         int i;  
303
304         hud_shield_hit_reset(1);        // reset for the player
305
306         if ( Hud_shield_inited ) {
307                 return;
308         }       
309
310         for ( i = 0; i < MAX_SHIELD_ICONS; i++ ) {
311                 Shield_gauges[i].first_frame = -1;
312                 Shield_gauges[i].num_frames  = 0;
313         }
314
315         Hud_shield_inited = 1;
316
317         if ( !Shield_mini_loaded ) {
318                 Shield_mini_gauge.first_frame = bm_load_animation(Shield_mini_fname[gr_screen.res], &Shield_mini_gauge.num_frames);
319                 if ( Shield_mini_gauge.first_frame == -1 ) {
320                         Warning(LOCATION, "Could not load in the HUD shield ani: Shield_mini_fname[gr_screen.res]\n");
321                         return;
322                 }
323                 Shield_mini_loaded = 1;
324         }
325 }
326
327 int hud_shield_maybe_flash(int gauge, int target_index, int shield_offset)
328 {
329         int                                     flashed = 0;
330         shield_hit_info *shi;
331
332         shi = &Shield_hit_data[target_index];
333
334         if ( !timestamp_elapsed(shi->shield_hit_timers[shield_offset]) ) {
335                 if ( timestamp_elapsed(shi->shield_hit_next_flash[shield_offset]) ) {
336                         shi->shield_hit_next_flash[shield_offset] = timestamp(SHIELD_FLASH_INTERVAL_FAST);
337                         shi->shield_show_bright ^= (1<<shield_offset);  // toggle between default and bright frames
338                 }
339
340                 if ( shi->shield_show_bright & (1<<shield_offset) ) {
341                         // hud_set_bright_color();
342                         hud_set_gauge_color(gauge, HUD_C_BRIGHT);
343                         flashed = 1;
344                 } else {
345                         hud_set_gauge_color(gauge, HUD_C_NORMAL);
346                         // hud_set_default_color();
347                 }
348         }
349
350         return flashed;
351 }
352
353 // ------------------------------------------------------------------
354 // hud_shield_show()
355 //
356 // Show the players shield strength and integrity
357 //
358 void hud_shield_show(object *objp)
359 {
360         float                   max_shield;
361         int                     hud_color_index, range;
362         int                     sx, sy, i;
363         ship                    *sp;
364         ship_info       *sip;
365         hud_frames      *sgp;
366
367         if ( objp->type != OBJ_SHIP )
368                 return;
369
370         sp = &Ships[objp->instance];
371         sip = &Ship_info[sp->ship_info_index];
372
373         if ( sip->shield_icon_index == 255 ) {
374                 return;
375         }
376
377         if (objp == Player_obj) {
378                 hud_set_gauge_color(HUD_PLAYER_SHIELD_ICON);
379         } else {
380                 hud_set_gauge_color(HUD_TARGET_SHIELD_ICON);
381         }
382
383         // load in shield frames if not already loaded
384         Assert(sip->shield_icon_index >= 0 && sip->shield_icon_index < Hud_shield_filename_count);
385         sgp = &Shield_gauges[sip->shield_icon_index];
386
387         if ( sgp->first_frame == -1 ) {
388                 sgp->first_frame = bm_load_animation(Hud_shield_filenames[sip->shield_icon_index], &sgp->num_frames);
389                 if ( sgp->first_frame == -1 ) {
390                         Warning(LOCATION, "Could not load in the HUD shield ani: %s\n", Hud_shield_filenames[sip->shield_icon_index]);
391                         return;
392                 }
393         }
394
395         if ( objp == Player_obj ) {
396                 sx = Player_shield_coords[gr_screen.res][0];
397                 sy = Player_shield_coords[gr_screen.res][1];
398         } else {
399                 sx = Target_shield_coords[gr_screen.res][0];
400                 sy = Target_shield_coords[gr_screen.res][1];
401         }
402
403         sx += fl2i(HUD_offset_x);
404         sy += fl2i(HUD_offset_y);
405
406         // draw the ship first
407         if ( objp == Player_obj ) {
408                 hud_shield_maybe_flash(HUD_PLAYER_SHIELD_ICON, SHIELD_HIT_PLAYER, HULL_HIT_OFFSET);
409         } else {
410                 hud_shield_maybe_flash(HUD_TARGET_SHIELD_ICON, SHIELD_HIT_TARGET, HULL_HIT_OFFSET);
411         }
412
413         GR_AABITMAP(sgp->first_frame, sx, sy);  
414
415         // draw the four quadrants
416         //
417         // Draw shield quadrants at one of NUM_SHIELD_LEVELS
418         max_shield = sip->shields/4.0f;
419
420         for ( i = 0; i < 4; i++ ) {
421
422                 if ( objp->flags & OF_NO_SHIELDS ) {
423                         break;
424                 }
425
426                 if ( objp->shields[Quadrant_xlate[i]] < 0.1f ) {
427                         continue;
428                 }
429
430                 range = max(HUD_COLOR_ALPHA_MAX, HUD_color_alpha + 4);
431                 hud_color_index = fl2i( (objp->shields[Quadrant_xlate[i]] / max_shield) * range + 0.5);
432                 Assert(hud_color_index >= 0 && hud_color_index <= range);
433
434                 if ( hud_color_index < 0 ) {
435                         hud_color_index = 0;
436                 }
437                 if ( hud_color_index >= HUD_NUM_COLOR_LEVELS ) {
438                         hud_color_index = HUD_NUM_COLOR_LEVELS - 1;
439                 }
440
441                 int flash=0;
442                 if ( objp == Player_obj ) {
443                         flash = hud_shield_maybe_flash(HUD_PLAYER_SHIELD_ICON, SHIELD_HIT_PLAYER, i);
444                 } else {
445                         flash = hud_shield_maybe_flash(HUD_TARGET_SHIELD_ICON, SHIELD_HIT_TARGET, i);
446                 }
447                                 
448                 if ( !flash ) {
449                         // gr_set_color_fast(&HUD_color_defaults[hud_color_index]);
450                         if ( objp == Player_obj ) {
451                                 hud_set_gauge_color(HUD_PLAYER_SHIELD_ICON, hud_color_index);
452                         } else {
453                                 hud_set_gauge_color(HUD_TARGET_SHIELD_ICON, hud_color_index);
454                         }
455
456                         GR_AABITMAP(sgp->first_frame+i+1, sx, sy);                      
457                 }
458         }
459
460         // hud_set_default_color();
461 }
462
463 // called at beginning of level to page in all ship icons
464 // used in this level
465 void hud_ship_icon_page_in(ship_info *sip)
466 {
467         hud_frames      *sgp;
468
469         if ( sip->shield_icon_index == 255 ) {
470                 return;
471         }
472
473         // load in shield frames if not already loaded
474         Assert(sip->shield_icon_index >= 0 && sip->shield_icon_index < Hud_shield_filename_count);
475         sgp = &Shield_gauges[sip->shield_icon_index];
476
477         if ( sgp->first_frame == -1 ) {
478                 sgp->first_frame = bm_load_animation(Hud_shield_filenames[sip->shield_icon_index], &sgp->num_frames);
479                 if ( sgp->first_frame == -1 ) {
480                         Warning(LOCATION, "Could not load in the HUD shield ani: %s\n", Hud_shield_filenames[sip->shield_icon_index]);
481                         return;
482                 }
483         }
484
485         int i;
486         for (i=0; i<sgp->num_frames; i++ )      {
487                 bm_page_in_aabitmap(sgp->first_frame+i);
488         }
489
490 }
491
492 // ------------------------------------------------------------------
493 // hud_shield_equalize()
494 //
495 // Equalize the four shield quadrants for an object
496 //
497 void hud_shield_equalize(object *objp, player *pl)
498 {
499         float   strength;
500         int idx;
501         int all_equal = 1;
502
503         Assert(objp != NULL);
504         if(objp == NULL){
505                 return;
506         }
507         Assert(pl != NULL);
508         if(pl == NULL){
509                 return;
510         }
511         Assert(objp->type == OBJ_SHIP);
512         if(objp->type != OBJ_SHIP){
513                 return;
514         }
515
516         // are all quadrants equal?
517         for(idx=0; idx<MAX_SHIELD_SECTIONS-1; idx++){
518                 if(objp->shields[idx] != objp->shields[idx+1]){
519                         all_equal = 0;
520                         break;
521                 }
522         }
523
524         // not all equal
525         if(!all_equal){
526                 strength = get_shield_strength(objp);
527                 if ( strength != 0 ) {
528                         // maybe impose a 2% penalty - server side and single player only
529                         if(!MULTIPLAYER_CLIENT &&  (pl->shield_penalty_stamp < 0) || timestamp_elapsed_safe(pl->shield_penalty_stamp, 1000) ){
530                                 strength *= 0.98f;
531
532                                 // reset the penalty timestamp
533                                 pl->shield_penalty_stamp = timestamp(1000);
534                         }
535                         
536                         set_shield_strength(objp, strength);                                    
537                 }
538         }
539
540         // beep
541         if ( objp == Player_obj ){
542                 snd_play( &Snds[SND_SHIELD_XFER_OK] );
543         }
544 }
545
546 // ------------------------------------------------------------------
547 // hud_augment_shield_quadrant()
548 //
549 // Transfer shield energy to a shield quadrant from the three other
550 //      quadrants.  Works by trying to transfer a fixed amount of shield
551 //      energy from the other three quadrants, taking the same percentage
552 // from each quadrant.
553 //
554 //      input:  objp                    =>              object to perform shield transfer on
555 //                              direction       =>              which quadrant to augment:
556 //                                                                              0 - right
557 //                                                                              1 - top
558 //                                                                              2 - bottom
559 //                                                                              3 - left
560 //
561 void hud_augment_shield_quadrant(object *objp, int direction)
562 {
563         float   full_shields, xfer_amount, energy_avail, percent_to_take, delta;
564         float   max_quadrant_val;
565         int     i;
566
567         Assert(direction >= 0 && direction < 4);
568         Assert(objp->type == OBJ_SHIP);
569         full_shields = Ship_info[Ships[objp->instance].ship_info_index].shields;
570         
571         xfer_amount = full_shields * SHIELD_TRANSFER_PERCENT;
572         max_quadrant_val = full_shields/4.0f;
573
574         if ( (objp->shields[direction] + xfer_amount) > max_quadrant_val )
575                 xfer_amount = max_quadrant_val - objp->shields[direction];
576
577         Assert(xfer_amount >= 0);
578         if ( xfer_amount == 0 ) {
579                 // TODO: provide a feedback sound
580                 return;
581         }
582         else {
583                 snd_play( &Snds[SND_SHIELD_XFER_OK] );
584         }
585
586         energy_avail = 0.0f;
587         for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
588                 if ( i == direction )
589                         continue;
590                 energy_avail += objp->shields[i];
591         }
592
593         percent_to_take = xfer_amount/energy_avail;
594         if ( percent_to_take > 1.0f )
595                 percent_to_take = 1.0f;
596
597         for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
598                 if ( i == direction )
599                         continue;
600                 delta = percent_to_take * objp->shields[i];
601                 objp->shields[i] -= delta;
602                 Assert(objp->shields[i] >= 0 );
603                 objp->shields[direction] += delta;
604                 if ( objp->shields[direction] > max_quadrant_val )
605                         objp->shields[direction] = max_quadrant_val;
606         }
607 }
608
609 // Try to find a match between filename and the names inside
610 // of Hud_shield_filenames.  This will provide us with an 
611 // association of ship class to shield icon information.
612 void hud_shield_assign_info(ship_info *sip, char *filename)
613 {
614         ubyte i;
615
616         for ( i = 0; i < Hud_shield_filename_count; i++ ) {
617                 if ( !stricmp(filename, Hud_shield_filenames[i]) ) {
618                         sip->shield_icon_index = i;
619                 }
620         }               
621 }
622
623 void hud_show_mini_ship_integrity(object *objp, int x_force, int y_force)
624 {
625         char    text_integrity[64];
626         int     numeric_integrity;
627         float p_target_integrity,initial_hull;
628         int     nx, ny;
629
630         initial_hull = Ship_info[Ships[objp->instance].ship_info_index].initial_hull_strength;
631         if (  initial_hull <= 0 ) {
632                 Int3(); // illegal initial hull strength
633                 p_target_integrity = 0.0f;
634         } else {
635                 p_target_integrity = objp->hull_strength / initial_hull;
636                 if (p_target_integrity < 0){
637                         p_target_integrity = 0.0f;
638                 }
639         }
640
641         numeric_integrity = fl2i(p_target_integrity*100 + 0.5f);
642         if(numeric_integrity > 100){
643                 numeric_integrity = 100;
644         }
645         // Assert(numeric_integrity <= 100);
646
647         // base coords
648         nx = (x_force == -1) ? Hud_mini_base[gr_screen.res][0] : x_force;
649         ny = (y_force == -1) ? Hud_mini_base[gr_screen.res][1] : y_force;
650
651         // 3 digit hull strength
652         if ( numeric_integrity == 100 ) {
653                 nx += Hud_mini_3digit[gr_screen.res][2];
654         } 
655         // 2 digit hull strength
656         else if ( numeric_integrity < 10 ) {
657                 nx += Hud_mini_1digit[gr_screen.res][2];                
658         }
659         // 1 digit hull strength
660         else {
661                 nx += Hud_mini_2digit[gr_screen.res][2];                
662         }       
663
664         if ( numeric_integrity == 0 ) {
665                 if ( p_target_integrity > 0 ) {
666                         numeric_integrity = 1;
667                 }
668         }
669
670         nx += fl2i( HUD_offset_x );
671         ny += fl2i( HUD_offset_y );
672
673         sprintf(text_integrity, "%d", numeric_integrity);
674         if ( numeric_integrity < 100 ) {
675                 hud_num_make_mono(text_integrity);
676         }       
677
678         gr_string(nx, ny, text_integrity);
679 }
680
681 // Draw the miniature shield icon that is drawn near the reticle
682 void hud_shield_show_mini(object *objp, int x_force, int y_force, int x_hull_offset, int y_hull_offset)
683 {
684         float                   max_shield;
685         int                     hud_color_index, range, frame_offset;
686         int                     sx, sy, i;
687         ship                    *sp;
688         ship_info       *sip;
689         shield_hit_info *shi;
690
691         shi = &Shield_hit_data[SHIELD_HIT_TARGET];
692
693         if ( objp->type != OBJ_SHIP ) {
694                 return;
695         }
696
697         sp = &Ships[objp->instance];
698         sip = &Ship_info[sp->ship_info_index];
699
700         hud_set_gauge_color(HUD_TARGET_MINI_ICON);
701
702         if (!Shield_mini_loaded)
703                 return;
704
705         sx = (x_force == -1) ? Shield_mini_coords[gr_screen.res][0]+fl2i(HUD_offset_x) : x_force;
706         sy = (y_force == -1) ? Shield_mini_coords[gr_screen.res][1]+fl2i(HUD_offset_y) : y_force;
707
708         // draw the ship first
709         hud_shield_maybe_flash(HUD_TARGET_MINI_ICON, SHIELD_HIT_TARGET, HULL_HIT_OFFSET);
710         hud_show_mini_ship_integrity(objp,x_force + x_hull_offset,y_force + y_hull_offset);
711
712         // draw the four quadrants
713         // Draw shield quadrants at one of NUM_SHIELD_LEVELS
714         max_shield = sip->shields/4.0f;
715
716         for ( i = 0; i < 4; i++ ) {
717
718                 if ( objp->flags & OF_NO_SHIELDS ) {
719                         break;
720                 }
721
722                 if ( objp->shields[Quadrant_xlate[i]] < 0.1f ) {
723                         continue;
724                 }
725
726                 if ( hud_shield_maybe_flash(HUD_TARGET_MINI_ICON, SHIELD_HIT_TARGET, i) ) {
727                         frame_offset = i+4;
728                 } else {
729                         frame_offset = i;
730                 }
731                                 
732                 range = HUD_color_alpha;
733                 hud_color_index = fl2i( (objp->shields[Quadrant_xlate[i]] / max_shield) * range + 0.5);
734                 Assert(hud_color_index >= 0 && hud_color_index <= range);
735         
736                 if ( hud_color_index < 0 ) {
737                         hud_color_index = 0;
738                 }
739                 if ( hud_color_index >= HUD_NUM_COLOR_LEVELS ) {
740                         hud_color_index = HUD_NUM_COLOR_LEVELS - 1;
741                 }
742
743                 if ( hud_gauge_maybe_flash(HUD_TARGET_MINI_ICON) == 1) {
744                         // hud_set_bright_color();
745                         hud_set_gauge_color(HUD_TARGET_MINI_ICON, HUD_C_BRIGHT);
746                 } else {
747                         // gr_set_color_fast(&HUD_color_defaults[hud_color_index]);
748                         hud_set_gauge_color(HUD_TARGET_MINI_ICON, hud_color_index);
749                 }                                        
750
751                 GR_AABITMAP(Shield_mini_gauge.first_frame + frame_offset, sx, sy);              
752         }
753         
754         // hud_set_default_color();
755 }
756
757 // reset the shield_hit_info data structure
758 void shield_info_reset(shield_hit_info *shi)
759 {
760         int i;
761
762         shi->shield_hit_status = 0;
763         shi->shield_show_bright = 0;
764         for ( i = 0; i < NUM_SHIELD_HIT_MEMBERS; i++ ) {
765                 shi->shield_hit_timers[i] = 1;
766                 shi->shield_hit_next_flash[i] = 1;
767         }
768 }
769
770 // reset the timers and hit flags for the shield gauges
771 //
772 // This needs to be called whenever the player selects a new target
773 //
774 // input:       player  =>      optional parameter (default value 0).  This is to indicate that player shield hit
775 //                                                              info should be reset.  This is normally not the case.
776 //                                                              is for the player's current target
777 void hud_shield_hit_reset(int player)
778 {
779         shield_hit_info *shi;
780
781         if (player) {
782                 shi = &Shield_hit_data[SHIELD_HIT_PLAYER];
783         } else {
784                 shi = &Shield_hit_data[SHIELD_HIT_TARGET];
785         }
786
787         shield_info_reset(shi);
788 }
789
790 // called once per frame to update the state of Shield_hit_status based on the Shield_hit_timers[]
791 void hud_shield_hit_update()
792 {
793         int i, j, limit;                
794
795         limit = 1;
796         if ( Player_ai->target_objnum >= 0 ) {
797                 limit = 2;
798         }
799
800         for ( i = 0; i < limit; i++ ) {
801                 for ( j = 0; j < NUM_SHIELD_HIT_MEMBERS; j++ ) {
802                         if ( timestamp_elapsed(Shield_hit_data[i].shield_hit_timers[j]) ) {
803                                 Shield_hit_data[i].shield_hit_status &= ~(1<<j);
804                                 Shield_hit_data[i].shield_show_bright &= ~(1<<j);
805                         }
806                 }
807         }
808 }
809
810 // called when a shield quadrant is struct, so we can update the timer that will draw the quadrant
811 // as flashing
812 //
813 // input:
814 //                              objp            =>      object pointer for ship that has been hit
815 //                              quadrant        => quadrant of shield getting hit (-1 if no shield is present)
816 void hud_shield_quadrant_hit(object *objp, int quadrant)
817 {
818         shield_hit_info *shi;
819         int                                     num;
820
821         if ( objp->type != OBJ_SHIP )
822                 return;
823
824         hud_escort_ship_hit(objp, quadrant);
825         hud_gauge_popup_start(HUD_TARGET_MINI_ICON);
826
827         if ( OBJ_INDEX(objp) == Player_ai->target_objnum ) {
828                 shi = &Shield_hit_data[SHIELD_HIT_TARGET];
829         } else if ( objp == Player_obj ) {
830                 shi = &Shield_hit_data[SHIELD_HIT_PLAYER];
831         } else {
832                 return;
833         }
834
835         if ( quadrant >= 0 ) {
836                 num = Quadrant_xlate[quadrant];
837                 shi->shield_hit_timers[num] = timestamp(300);
838         } else {
839                 shi->shield_hit_timers[HULL_HIT_OFFSET] = timestamp(SHIELD_HIT_DURATION_SHORT);
840                 hud_targetbox_start_flash(TBOX_FLASH_HULL);
841         }
842 }
843
844
845 void hudshield_page_in()
846 {
847         bm_page_in_aabitmap( Shield_mini_gauge.first_frame, Shield_mini_gauge.num_frames );
848 }
849