]> icculus.org git repositories - taylor/freespace2.git/blob - src/hud/hudshield.cpp
use a better multi_sw_ok_to_commit() check
[taylor/freespace2.git] / src / hud / hudshield.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Hud/HUDshield.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C file for the display and management of the HUD shield
16  *
17  * $Log$
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
24  *
25  * Revision 1.4  2002/07/13 06:46:48  theoddone33
26  * Warning cleanups
27  *
28  * Revision 1.3  2002/06/09 04:41:21  relnev
29  * added copyright header
30  *
31  * Revision 1.2  2002/05/07 03:16:45  theoddone33
32  * The Great Newline Fix
33  *
34  * Revision 1.1.1.1  2002/05/03 03:28:09  root
35  * Initial import.
36  *
37  * 
38  * 12    8/27/99 10:36a Dave
39  * Impose a 2% penalty for hitting the shield balance key.
40  * 
41  * 11    8/23/99 11:34a Dave
42  * Fixed shield intensity rendering problems.
43  * 
44  * 10    8/01/99 12:39p Dave
45  * Added HUD contrast control key (for nebula).
46  * 
47  * 9     7/22/99 4:00p Dave
48  * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
49  * 
50  * 8     6/10/99 3:43p Dave
51  * Do a better job of syncing text colors to HUD gauges.
52  * 
53  * 7     1/07/99 9:06a Jasen
54  * coords...
55  * 
56  * 6     12/30/98 8:57a Jasen
57  * updated coords for hi res
58  * 
59  * 5     12/28/98 3:17p Dave
60  * Support for multiple hud bitmap filenames for hi-res mode.
61  * 
62  * 4     12/21/98 5:02p Dave
63  * Modified all hud elements to be multi-resolution friendly.
64  * 
65  * 3     12/14/98 1:15p Jasen
66  * added new HUD shield gauges
67  * 
68  * 2     10/07/98 10:53a Dave
69  * Initial checkin.
70  * 
71  * 1     10/07/98 10:49a Dave
72  * 
73  * 35    9/19/98 3:11p Adam
74  * Added new hardcoded values for Hud_shield_filenames
75  * 
76  * 34    8/25/98 1:48p Dave
77  * First rev of EMP effect. Player side stuff basically done. Next comes
78  * AI code.
79  * 
80  * 33    5/17/98 3:32p Lawrance
81  * Make shield gauge more readable when flashing
82  * 
83  * 32    4/25/98 5:39p Dave
84  * Removed an unneeded assert.
85  * 
86  * 31    4/25/98 3:56p Mike
87  * Make player's shield icon flash when Fred tells it to.
88  * 
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.
92  * 
93  * 29    4/21/98 12:19a Allender
94  * only play equalize shield sound if player equalizes shields
95  * 
96  * 28    3/26/98 5:26p John
97  * added new paging code. nonfunctional.
98  * 
99  * 27    3/21/98 3:35p Lawrance
100  * Tweak position of numeric integrity for target
101  * 
102  * 26    3/14/98 4:59p Lawrance
103  * Flash shield/ship icons when ships are hit
104  * 
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.  
110  * 
111  * 24    2/22/98 12:19p John
112  * Externalized some strings
113  * 
114  * 23    2/12/98 4:58p Lawrance
115  * Change to new flashing method.
116  * 
117  * 22    1/12/98 11:16p Lawrance
118  * Wonderful HUD config.
119  * 
120  * 21    1/08/98 4:36p Lawrance
121  * Fix bug in shield drawing code.
122  * 
123  * 20    1/05/98 9:38p Lawrance
124  * Implement flashing HUD gauges.
125  * 
126  * 19    1/02/98 9:10p Lawrance
127  * Big changes to how colors get set on the HUD.
128  * 
129  * 18    12/29/97 9:48p Mike
130  * Prevent indexing before array start when quadrant_num = -1.
131  * 
132  * 17    12/01/97 12:27a Lawrance
133  * redo default alpha color for HUD, make it easy to modify in the future
134  * 
135  * 16    11/18/97 5:58p Lawrance
136  * flash escort view info when that ship is taking hits
137  * 
138  * 15    11/18/97 1:21p Mitri
139  * ALAN: be sure to only draw shield icons for targets that are ships
140  * 
141  * 14    11/17/97 6:37p Lawrance
142  * new gauges: extended target view, new lock triangles, support ship view
143  * 
144  * 13    11/13/97 10:46p Lawrance
145  * implemented new escort view, damage view and weapons
146  * 
147  * 12    11/12/97 9:42a Lawrance
148  * show player ship integrity above shield icon
149  * 
150  * 11    11/11/97 5:06p Lawrance
151  * fix bug with flashing frequency of hull
152  * 
153  * 10    11/09/97 11:27p Lawrance
154  * move target shield icon closer to center
155  * 
156  * 9     11/09/97 4:39p Lawrance
157  * don't draw mini ship icon anymore
158  * 
159  * 8     11/08/97 11:08p Lawrance
160  * implement new "mini-shield" view that sits near bottom of reticle
161  * 
162  * 7     11/05/97 11:21p Lawrance
163  * implement dynamic alpha on the shields
164  * 
165  * 6     11/04/97 8:34p Lawrance
166  * fix warning: remove unused variable
167  * 
168  * 5     11/04/97 7:49p Lawrance
169  * integrating new HUD reticle and shield icons
170  * 
171  * 4     10/24/97 5:51p Lawrance
172  * don't show shield % if ship has no shields
173  * 
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.
178  * 
179  * 2     8/25/97 12:24a Lawrance
180  * implemented HUD shield management
181  * 
182  * 1     8/24/97 10:31p Lawrance
183  *
184  * $NoKeywords: $
185  */
186
187 #include "2d.h"
188 #include "object.h"
189 #include "hud.h"
190 #include "hudtarget.h"
191 #include "hudtargetbox.h"
192 #include "hudets.h"
193 #include "player.h"
194 #include "gamesnd.h"
195 #include "freespace.h"
196 #include "bmpman.h"
197 #include "timer.h"
198 #include "hudshield.h"
199 #include "hudescort.h"
200 #include "emp.h"
201 #include "multi.h"
202
203 #define NUM_SHIELD_LEVELS               8
204
205 #define SHIELD_TRANSFER_PERCENT 0.083f          // 1/12 total shield strength
206
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
209
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];
214
215 char Shield_mini_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
216         "targhit1",
217         "targhit1"
218 };
219
220 hud_frames Shield_gauges[MAX_SHIELD_ICONS];
221
222 static int Player_shield_coords[GR_NUM_RESOLUTIONS][2] = 
223 {
224         { // GR_640
225                 396, 379
226         },
227         { // GR_1024
228                 634, 670
229         }
230 };
231
232 static int Target_shield_coords[GR_NUM_RESOLUTIONS][2] = 
233 {
234         { // GR_640
235                 142, 379
236         },
237         { // GR_1024
238                 292, 670
239         }
240 };
241
242 static int Hud_shield_inited = 0;
243
244 int Shield_mini_coords[GR_NUM_RESOLUTIONS][2] = {
245         { // GR_640
246                 305, 291
247         },
248         { // GR_1024
249                 497, 470
250         }
251 };
252
253 // draw on the mini shield icon what the ship integrity is
254 int Hud_mini_3digit[GR_NUM_RESOLUTIONS][3] = {
255         { // GR_640
256                 310, 298, 0
257         },
258         { // GR_1024
259                 502, 477, 0
260         }
261 };
262 int Hud_mini_2digit[GR_NUM_RESOLUTIONS][3] = {
263         { // GR_640
264                 213, 298, 2
265         },
266         { // GR_1024
267                 346, 477, 2
268         }
269 };
270 int Hud_mini_1digit[GR_NUM_RESOLUTIONS][3] = {
271         { // GR_640
272                 316, 298, 6
273         },
274         { // GR_1024
275                 511, 477, 6
276         }
277 };
278 int Hud_mini_base[GR_NUM_RESOLUTIONS][2] = {
279         { // GR_640
280                 310, 298
281         },
282         { // GR_1024
283                 502, 477
284         }
285 };
286         
287 int Shield_mini_loaded = 0;
288 hud_frames Shield_mini_gauge;
289
290 #define SHIELD_HIT_PLAYER               0
291 #define SHIELD_HIT_TARGET               1
292 static shield_hit_info  Shield_hit_data[2];
293
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};
296
297 void hud_shield_game_init()
298 {
299 #ifndef MAKE_FS1
300         char name[MAX_FILENAME_LEN+1] = "";
301
302         try {
303                 // read in hud.tbl
304                 read_file_text("hud.tbl");
305                 reset_parse();
306
307                 Hud_shield_filename_count = 0;
308                 required_string("#Shield Icons Begin");
309                 while(!optional_string("#End")){
310                         required_string("$Shield:");
311
312                         stuff_string(name, F_NAME, NULL);
313
314                         // maybe store
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);
318                         }
319                 }
320         } catch (parse_error_t rval) {
321                 Error(LOCATION, "Unable to parse hud.tbl!  Code = %i.\n", (int)rval);
322         }
323 #else
324         // hardcoded FS1 table values
325         int i;
326
327         Hud_shield_filename_count = 0;
328
329         // for fighters
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);
333         }
334
335         // for bombers
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);
339         }
340 #endif
341 }
342
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()
345 {
346         int i;  
347
348         hud_shield_hit_reset(1);        // reset for the player
349
350         if ( Hud_shield_inited ) {
351                 return;
352         }       
353
354         for ( i = 0; i < MAX_SHIELD_ICONS; i++ ) {
355                 Shield_gauges[i].first_frame = -1;
356                 Shield_gauges[i].num_frames  = 0;
357         }
358
359         Hud_shield_inited = 1;
360
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");
365                         return;
366                 }
367                 Shield_mini_loaded = 1;
368         }
369 }
370
371 int hud_shield_maybe_flash(int gauge, int target_index, int shield_offset)
372 {
373         int                                     flashed = 0;
374         shield_hit_info *shi;
375
376         shi = &Shield_hit_data[target_index];
377
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
382                 }
383
384                 if ( shi->shield_show_bright & (1<<shield_offset) ) {
385                         // hud_set_bright_color();
386                         hud_set_gauge_color(gauge, HUD_C_BRIGHT);
387                         flashed = 1;
388                 } else {
389                         hud_set_gauge_color(gauge, HUD_C_NORMAL);
390                         // hud_set_default_color();
391                 }
392         }
393
394         return flashed;
395 }
396
397 // ------------------------------------------------------------------
398 // hud_shield_show()
399 //
400 // Show the players shield strength and integrity
401 //
402 void hud_shield_show(object *objp)
403 {
404         float                   max_shield;
405         int                     hud_color_index, range;
406         int                     sx, sy, i;
407         ship                    *sp;
408         ship_info       *sip;
409         hud_frames      *sgp;
410
411         if ( objp->type != OBJ_SHIP )
412                 return;
413
414         sp = &Ships[objp->instance];
415         sip = &Ship_info[sp->ship_info_index];
416
417         if ( sip->shield_icon_index == 255 ) {
418                 return;
419         }
420
421         if (objp == Player_obj) {
422                 hud_set_gauge_color(HUD_PLAYER_SHIELD_ICON);
423         } else {
424                 hud_set_gauge_color(HUD_TARGET_SHIELD_ICON);
425         }
426
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);
431         
432         sgp = &Shield_gauges[sip->shield_icon_index];
433
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]);
438                         return;
439                 }
440         }
441
442         if ( objp == Player_obj ) {
443                 sx = Player_shield_coords[gr_screen.res][0];
444                 sy = Player_shield_coords[gr_screen.res][1];
445         } else {
446                 sx = Target_shield_coords[gr_screen.res][0];
447                 sy = Target_shield_coords[gr_screen.res][1];
448         }
449
450         sx += fl2i(HUD_offset_x);
451         sy += fl2i(HUD_offset_y);
452
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);
456         } else {
457                 hud_shield_maybe_flash(HUD_TARGET_SHIELD_ICON, SHIELD_HIT_TARGET, HULL_HIT_OFFSET);
458         }
459
460         GR_AABITMAP(sgp->first_frame, sx, sy);  
461
462         // draw the four quadrants
463         //
464         // Draw shield quadrants at one of NUM_SHIELD_LEVELS
465         max_shield = sip->shields/4.0f;
466
467         for ( i = 0; i < 4; i++ ) {
468
469                 if ( objp->flags & OF_NO_SHIELDS ) {
470                         break;
471                 }
472
473                 if ( objp->shields[Quadrant_xlate[i]] < 0.1f ) {
474                         continue;
475                 }
476
477                 range = SDL_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);
480
481                 if ( hud_color_index < 0 ) {
482                         hud_color_index = 0;
483                 }
484                 if ( hud_color_index >= HUD_NUM_COLOR_LEVELS ) {
485                         hud_color_index = HUD_NUM_COLOR_LEVELS - 1;
486                 }
487
488                 int flash=0;
489                 if ( objp == Player_obj ) {
490                         flash = hud_shield_maybe_flash(HUD_PLAYER_SHIELD_ICON, SHIELD_HIT_PLAYER, i);
491                 } else {
492                         flash = hud_shield_maybe_flash(HUD_TARGET_SHIELD_ICON, SHIELD_HIT_TARGET, i);
493                 }
494                                 
495                 if ( !flash ) {
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);
499                         } else {
500                                 hud_set_gauge_color(HUD_TARGET_SHIELD_ICON, hud_color_index);
501                         }
502
503                         GR_AABITMAP(sgp->first_frame+i+1, sx, sy);                      
504                 }
505         }
506
507         // hud_set_default_color();
508 }
509
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)
513 {
514         hud_frames      *sgp;
515
516         if ( sip->shield_icon_index == 255 ) {
517                 return;
518         }
519
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];
525
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]);
530                         return;
531                 }
532         }
533
534         int i;
535         for (i=0; i<sgp->num_frames; i++ )      {
536                 bm_page_in_aabitmap(sgp->first_frame+i);
537         }
538
539 }
540
541 // ------------------------------------------------------------------
542 // hud_shield_equalize()
543 //
544 // Equalize the four shield quadrants for an object
545 //
546 void hud_shield_equalize(object *objp, player *pl)
547 {
548         float   strength;
549         int idx;
550         int all_equal = 1;
551
552         SDL_assert(objp != NULL);
553         if(objp == NULL){
554                 return;
555         }
556         SDL_assert(pl != NULL);
557         if(pl == NULL){
558                 return;
559         }
560         SDL_assert(objp->type == OBJ_SHIP);
561         if(objp->type != OBJ_SHIP){
562                 return;
563         }
564
565         // are all quadrants equal?
566         for(idx=0; idx<MAX_SHIELD_SECTIONS-1; idx++){
567                 if(objp->shields[idx] != objp->shields[idx+1]){
568                         all_equal = 0;
569                         break;
570                 }
571         }
572
573         // not all equal
574         if(!all_equal){
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)) ){
579                                 strength *= 0.98f;
580
581                                 // reset the penalty timestamp
582                                 pl->shield_penalty_stamp = timestamp(1000);
583                         }
584                         
585                         set_shield_strength(objp, strength);                                    
586                 }
587         }
588
589         // beep
590         if ( objp == Player_obj ){
591                 snd_play( &Snds[SND_SHIELD_XFER_OK] );
592         }
593 }
594
595 // ------------------------------------------------------------------
596 // hud_augment_shield_quadrant()
597 //
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.
602 //
603 //      input:  objp                    =>              object to perform shield transfer on
604 //                              direction       =>              which quadrant to augment:
605 //                                                                              0 - right
606 //                                                                              1 - top
607 //                                                                              2 - bottom
608 //                                                                              3 - left
609 //
610 void hud_augment_shield_quadrant(object *objp, int direction)
611 {
612         float   full_shields, xfer_amount, energy_avail, percent_to_take, delta;
613         float   max_quadrant_val;
614         int     i;
615
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;
619         
620         xfer_amount = full_shields * SHIELD_TRANSFER_PERCENT;
621         max_quadrant_val = full_shields/4.0f;
622
623         if ( (objp->shields[direction] + xfer_amount) > max_quadrant_val )
624                 xfer_amount = max_quadrant_val - objp->shields[direction];
625
626         SDL_assert(xfer_amount >= 0);
627         if ( xfer_amount == 0 ) {
628                 // TODO: provide a feedback sound
629                 return;
630         }
631         else {
632                 snd_play( &Snds[SND_SHIELD_XFER_OK] );
633         }
634
635         energy_avail = 0.0f;
636         for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
637                 if ( i == direction )
638                         continue;
639                 energy_avail += objp->shields[i];
640         }
641
642         percent_to_take = xfer_amount/energy_avail;
643         if ( percent_to_take > 1.0f )
644                 percent_to_take = 1.0f;
645
646         for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
647                 if ( i == direction )
648                         continue;
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;
655         }
656 }
657
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)
662 {
663         ubyte i;
664
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;
668                 }
669         }               
670 }
671
672 void hud_show_mini_ship_integrity(object *objp, int x_force, int y_force)
673 {
674         char    text_integrity[64];
675         int     numeric_integrity;
676         float p_target_integrity,initial_hull;
677         int     nx, ny;
678
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;
683         } else {
684                 p_target_integrity = objp->hull_strength / initial_hull;
685                 if (p_target_integrity < 0){
686                         p_target_integrity = 0.0f;
687                 }
688         }
689
690         numeric_integrity = fl2i(p_target_integrity*100 + 0.5f);
691         if(numeric_integrity > 100){
692                 numeric_integrity = 100;
693         }
694         // SDL_assert(numeric_integrity <= 100);
695
696         // base coords
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;
699
700         // 3 digit hull strength
701         if ( numeric_integrity == 100 ) {
702                 nx += Hud_mini_3digit[gr_screen.res][2];
703         } 
704         // 2 digit hull strength
705         else if ( numeric_integrity < 10 ) {
706                 nx += Hud_mini_1digit[gr_screen.res][2];                
707         }
708         // 1 digit hull strength
709         else {
710                 nx += Hud_mini_2digit[gr_screen.res][2];                
711         }       
712
713         if ( numeric_integrity == 0 ) {
714                 if ( p_target_integrity > 0 ) {
715                         numeric_integrity = 1;
716                 }
717         }
718
719         nx += fl2i( HUD_offset_x );
720         ny += fl2i( HUD_offset_y );
721
722         SDL_snprintf(text_integrity, SDL_arraysize(text_integrity), "%d", numeric_integrity);
723         if ( numeric_integrity < 100 ) {
724                 hud_num_make_mono(text_integrity);
725         }       
726
727         gr_string(nx, ny, text_integrity);
728 }
729
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)
732 {
733         float                   max_shield;
734         int                     hud_color_index, range, frame_offset;
735         int                     sx, sy, i;
736         ship                    *sp;
737         ship_info       *sip;
738
739         if ( objp->type != OBJ_SHIP ) {
740                 return;
741         }
742
743         sp = &Ships[objp->instance];
744         sip = &Ship_info[sp->ship_info_index];
745
746         hud_set_gauge_color(HUD_TARGET_MINI_ICON);
747
748         if (!Shield_mini_loaded)
749                 return;
750
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;
753
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);
757
758         // draw the four quadrants
759         // Draw shield quadrants at one of NUM_SHIELD_LEVELS
760         max_shield = sip->shields/4.0f;
761
762         for ( i = 0; i < 4; i++ ) {
763
764                 if ( objp->flags & OF_NO_SHIELDS ) {
765                         break;
766                 }
767
768                 if ( objp->shields[Quadrant_xlate[i]] < 0.1f ) {
769                         continue;
770                 }
771
772                 if ( hud_shield_maybe_flash(HUD_TARGET_MINI_ICON, SHIELD_HIT_TARGET, i) ) {
773                         frame_offset = i+4;
774                 } else {
775                         frame_offset = i;
776                 }
777                                 
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);
781         
782                 if ( hud_color_index < 0 ) {
783                         hud_color_index = 0;
784                 }
785                 if ( hud_color_index >= HUD_NUM_COLOR_LEVELS ) {
786                         hud_color_index = HUD_NUM_COLOR_LEVELS - 1;
787                 }
788
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);
792                 } else {
793                         // gr_set_color_fast(&HUD_color_defaults[hud_color_index]);
794                         hud_set_gauge_color(HUD_TARGET_MINI_ICON, hud_color_index);
795                 }                                        
796
797                 GR_AABITMAP(Shield_mini_gauge.first_frame + frame_offset, sx, sy);              
798         }
799         
800         // hud_set_default_color();
801 }
802
803 // reset the shield_hit_info data structure
804 void shield_info_reset(shield_hit_info *shi)
805 {
806         int i;
807
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;
813         }
814 }
815
816 // reset the timers and hit flags for the shield gauges
817 //
818 // This needs to be called whenever the player selects a new target
819 //
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)
824 {
825         shield_hit_info *shi;
826
827         if (player) {
828                 shi = &Shield_hit_data[SHIELD_HIT_PLAYER];
829         } else {
830                 shi = &Shield_hit_data[SHIELD_HIT_TARGET];
831         }
832
833         shield_info_reset(shi);
834 }
835
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()
838 {
839         int i, j, limit;                
840
841         limit = 1;
842         if ( Player_ai->target_objnum >= 0 ) {
843                 limit = 2;
844         }
845
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);
851                         }
852                 }
853         }
854 }
855
856 // called when a shield quadrant is struct, so we can update the timer that will draw the quadrant
857 // as flashing
858 //
859 // input:
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)
863 {
864         shield_hit_info *shi;
865         int                                     num;
866
867         if ( objp->type != OBJ_SHIP )
868                 return;
869
870         hud_escort_ship_hit(objp, quadrant);
871         hud_gauge_popup_start(HUD_TARGET_MINI_ICON);
872
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];
877         } else {
878                 return;
879         }
880
881         if ( quadrant >= 0 ) {
882                 num = Quadrant_xlate[quadrant];
883                 shi->shield_hit_timers[num] = timestamp(300);
884         } else {
885                 shi->shield_hit_timers[HULL_HIT_OFFSET] = timestamp(SHIELD_HIT_DURATION_SHORT);
886                 hud_targetbox_start_flash(TBOX_FLASH_HULL);
887         }
888 }
889
890
891 void hudshield_page_in()
892 {
893         bm_page_in_aabitmap( Shield_mini_gauge.first_frame, Shield_mini_gauge.num_frames );
894 }
895