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