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