]> icculus.org git repositories - taylor/freespace2.git/blob - src/hud/hudets.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / hud / hudets.cpp
1 /*
2  * $Logfile: /Freespace2/code/Hud/HUDets.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * C file that contains code to manage and display the Energy Transfer System (ETS)
8  *
9  * $Log$
10  * Revision 1.2  2002/05/07 03:16:45  theoddone33
11  * The Great Newline Fix
12  *
13  * Revision 1.1.1.1  2002/05/03 03:28:09  root
14  * Initial import.
15  *
16  * 
17  * 14    10/28/99 11:17p Jefff
18  * nudged German "A" on ETS
19  * 
20  * 13    10/26/99 11:02p Jefff
21  * changed german ets labels
22  * 
23  * 12    9/05/99 11:23p Jimb
24  * changed weapon and shield recharge rates for skill levels
25  * 
26  * 11    9/03/99 2:28p Mikek
27  * Slightly increase rate of weapon recharge at Medium and Hard.  Slightly
28  * decrease at Easy.
29  * 
30  * 10    8/01/99 12:39p Dave
31  * Added HUD contrast control key (for nebula).
32  * 
33  * 9     6/10/99 3:43p Dave
34  * Do a better job of syncing text colors to HUD gauges.
35  * 
36  * 8     2/23/99 8:11p Dave
37  * Tidied up dogfight mode. Fixed TvT ship type problems for alpha wing.
38  * Small pass over todolist items.
39  * 
40  * 7     1/07/99 9:06a Jasen
41  * coords updated
42  * 
43  * 6     12/28/98 3:17p Dave
44  * Support for multiple hud bitmap filenames for hi-res mode.
45  * 
46  * 5     12/21/98 5:02p Dave
47  * Modified all hud elements to be multi-resolution friendly.
48  * 
49  * 4     11/05/98 4:18p Dave
50  * First run nebula support. Beefed up localization a bit. Removed all
51  * conditional compiles for foreign versions. Modified mission file
52  * format.
53  * 
54  * 3     10/13/98 9:28a Dave
55  * Started neatening up freespace.h. Many variables renamed and
56  * reorganized. Added AlphaColors.[h,cpp]
57  * 
58  * 2     10/07/98 10:53a Dave
59  * Initial checkin.
60  * 
61  * 1     10/07/98 10:49a Dave
62  * 
63  * 60    8/28/98 3:28p Dave
64  * EMP effect done. AI effects may need some tweaking as required.
65  * 
66  * 59    8/25/98 1:48p Dave
67  * First rev of EMP effect. Player side stuff basically done. Next comes
68  * AI code.
69  * 
70  * 58    6/19/98 3:49p Lawrance
71  * localization tweaks
72  * 
73  * 57    4/07/98 1:53p Lawrance
74  * Make energy system matter more.
75  * 
76  * 56    3/26/98 5:26p John
77  * added new paging code. nonfunctional.
78  * 
79  * 55    2/23/98 6:49p Lawrance
80  * Use gr_aabitmap_ex() instead of clipping regions
81  * 
82  * 54    2/22/98 4:17p John
83  * More string externalization classification... 190 left to go!
84  * 
85  * 53    2/12/98 4:58p Lawrance
86  * Change to new flashing method.
87  * 
88  * 52    1/19/98 11:37p Lawrance
89  * Fixing Optimization build warnings
90  * 
91  * 51    1/05/98 9:38p Lawrance
92  * Implement flashing HUD gauges.
93  * 
94  * 50    1/02/98 9:10p Lawrance
95  * Big changes to how colors get set on the HUD.
96  * 
97  * 49    12/30/97 4:28p Lawrance
98  * remove .ani extensions from filenames
99  * 
100  * 48    12/01/97 12:27a Lawrance
101  * redo default alpha color for HUD, make it easy to modify in the future
102  * 
103  * 47    11/15/97 6:10p Lawrance
104  * make ship speed less dependant on engine damage
105  * 
106  * 46    11/11/97 12:58a Lawrance
107  * deal with situation where ship has no shields
108  * 
109  * 45    11/10/97 2:58p Lawrance
110  * fix bug that was preventing engine damage from affecting AI ships
111  * 
112  * 44    11/09/97 3:25p Lawrance
113  * increase default alpha color
114  * 
115  * 43    11/06/97 10:32a Lawrance
116  * brighten up energy management bars
117  * 
118  * 42    11/05/97 11:19p Lawrance
119  * implement new ETS gauge
120  * 
121  * 41    11/05/97 4:04p Lawrance
122  * engine speed not affected on Trainee ONLY for player ship
123  * 
124  * 40    10/28/97 3:35p Lawrance
125  * subsystems will not be affected when playing on lowest skill level
126  *
127  * $NoKeywords: $
128  */
129
130
131 #include "hudets.h"
132 #include "hud.h"
133 #include "ship.h"
134 #include "freespace.h"
135 #include "player.h"
136 #include "2d.h"
137 #include "timer.h"
138 #include "sound.h"
139 #include "gamesnd.h"
140 #include "bmpman.h"
141 #include "emp.h"
142 #include "localize.h"
143         
144 #define ENERGY_DIVERT_DELTA                             0.2f    // percentage of energy transferred in a shield->weapon or weapon->shield energy transfer
145 #define INTIAL_SHIELD_RECHARGE_INDEX    4               // default shield charge rate (index in Energy_levels[])
146 #define INTIAL_WEAPON_RECHARGE_INDEX    4               // default weapon charge rate (index in Energy_levels[])
147 #define INTIAL_ENGINE_RECHARGE_INDEX    4               // default engine charge rate (index in Energy_levels[])
148
149 #define MAX_SHIELD_REGEN_PER_SECOND             0.02f   //      max percent/100 of shield energy regenerated per second
150 #define MAX_WEAPON_REGEN_PER_SECOND             0.04f   // max percent/100 of weapon energy regenerated per second
151
152 #define NUM_ENERGY_LEVELS       13              
153 #define MAX_ENERGY_INDEX        (NUM_ENERGY_LEVELS - 1)
154 float Energy_levels[NUM_ENERGY_LEVELS] = {0.0f,  0.0833f, 0.167f, 0.25f, 0.333f, 0.417f, 0.5f, 0.583f, 0.667f, 0.75f, 0.833f, 0.9167f, 1.0f};
155
156 #define AI_MODIFY_ETS_INTERVAL 500      // time between ets modifications for ai's (in milliseconds)
157
158 int Weapon_energy_cheat = 0;
159
160 // skill level scaling of the amount of energy that is allocated to the weapons and 
161 // shields
162 float   Skill_level_weapon_energy_scale[NUM_SKILL_LEVELS] = {10.0f, 4.0f, 2.5f, 2.0f, 1.5f};
163 float Skill_level_shield_energy_scale[NUM_SKILL_LEVELS] = {4.0f, 2.0f, 1.5f, 1.25f, 1.0f};
164
165 #define ZERO_INDEX                      0
166 #define ONE_THIRD_INDEX         4
167 #define ONE_HALF_INDEX          6
168 #define ALL_INDEX                               12
169
170 #define HAS_ENGINES                     (1<<0)
171 #define HAS_SHIELDS                     (1<<1)
172 #define HAS_WEAPONS                     (1<<2)
173
174 int ETS_bar_h[GR_NUM_RESOLUTIONS] = {
175         41,
176         41
177 };
178
179 typedef struct ets_gauge_info
180 {
181         char    letter;
182         int     letter_coords[2];
183         int     top_coords[2];
184         int     bottom_coords[2];
185 } ets_gauge_info;
186
187 ets_gauge_info Ets_gauge_info_german[GR_NUM_RESOLUTIONS][3] =
188 {
189         { // GR_640
190                 'G', {525,422}, {523,380}, {523,430},
191                 'S', {542,422}, {540,380}, {540,430},
192                 'A', {559,422}, {557,380}, {557,430}
193         },
194         { // GR_1024
195                 'G', {882,690}, {880,648}, {880,698},
196                 'S', {900,690}, {898,648}, {898,698},
197                 'A', {917,690}, {916,648}, {916,698}
198         }
199 };
200 ets_gauge_info Ets_gauge_info_french[GR_NUM_RESOLUTIONS][3] =
201 {
202         { // GR_640
203                 'C', {525,422}, {523,380}, {523,430},
204                 'B', {542,422}, {540,380}, {540,430},
205                 'M', {560,422}, {557,380}, {557,430}
206         }, 
207         { // GR_1024
208                 'C', {882,690}, {880,648}, {880,698},
209                 'B', {900,690}, {898,648}, {898,698},
210                 'M', {918,690}, {916,648}, {916,698}
211         },
212 };
213 ets_gauge_info Ets_gauge_info_english[GR_NUM_RESOLUTIONS][3] =
214 {
215         { // GR_640
216                 'G', {525,422}, {523,380}, {523,430},
217                 'S', {542,422}, {540,380}, {540,430},
218                 'E', {560,422}, {557,380}, {557,430}
219         },
220         { // GR_1024
221                 'G', {882,690}, {880,648}, {880,698},
222                 'S', {900,690}, {898,648}, {898,698},
223                 'E', {918,690}, {916,648}, {916,698}
224         }
225 };
226 ets_gauge_info *Ets_gauge_info = NULL;
227
228 char Ets_fname[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN] = {
229         "energy1",
230         "energy1"
231 };
232
233 hud_frames Ets_gauge;
234
235 static int Hud_ets_inited = 0;
236
237 void hud_init_ets()
238 {
239         if ( Hud_ets_inited )
240                 return;
241
242         Ets_gauge.first_frame = bm_load_animation(Ets_fname[gr_screen.res], &Ets_gauge.num_frames);
243         if ( Ets_gauge.first_frame < 0 ) {
244                 Warning(LOCATION,"Cannot load hud ani: Ets_fname[gr_screen.res]\n");
245         }
246
247         if(Lcl_gr){
248                 Ets_gauge_info = Ets_gauge_info_german[gr_screen.res];
249         } else if(Lcl_fr){
250                 Ets_gauge_info = Ets_gauge_info_french[gr_screen.res];
251         } else {
252                 Ets_gauge_info = Ets_gauge_info_english[gr_screen.res];
253         }
254         
255         Hud_ets_inited = 1;
256 }
257
258 // -------------------------------------------------------------------------------------------------
259 // ets_init_ship() is called by a ship when it is created (effectively, for every ship at the start
260 // of a mission).  This will set the default charge rates for the different systems and initalialize
261 // the weapon energy reserve.
262 //
263 void ets_init_ship(object* obj)
264 {
265         ship* sp;
266
267         // fred should bail here
268         if(Fred_running){
269                 return;
270         }
271
272         Assert(obj->type == OBJ_SHIP);
273         sp = &Ships[obj->instance];
274         
275         sp->weapon_energy = Ship_info[sp->ship_info_index].max_weapon_reserve;
276         sp->next_manage_ets = timestamp(AI_MODIFY_ETS_INTERVAL);
277         set_default_recharge_rates(obj);
278 }
279
280 // -------------------------------------------------------------------------------------------------
281 // update_ets() is called once per frame for every OBJ_SHIP in the game.  The amount of energy
282 // to send to the weapons and shields is calculated, and the top ship speed is calculated.  The
283 // amount of time elapsed from the previous call is passed in as the parameter fl_frametime.
284 //
285 // parameters:   obj          ==> object that is updating their energy system
286 //               fl_frametime ==> game frametime (in seconds)
287 //
288 void update_ets(object* objp, float fl_frametime)
289 {
290         float max_new_shield_energy, max_new_weapon_energy, _ss;
291
292         if ( fl_frametime <= 0 ){
293                 return;
294         }
295
296         ship* ship_p = &Ships[objp->instance];
297         ship_info* sinfo_p = &Ship_info[ship_p->ship_info_index];
298
299         if ( ship_p->flags & SF_DYING ){
300                 return;
301         }
302
303         if ( sinfo_p->power_output == 0 ){
304                 return;
305         }
306
307 //      new_energy = fl_frametime * sinfo_p->power_output;
308
309         // update weapon energy
310         max_new_weapon_energy = fl_frametime * MAX_WEAPON_REGEN_PER_SECOND * sinfo_p->max_weapon_reserve;
311         if ( objp->flags & OF_PLAYER_SHIP ) {
312                 ship_p->weapon_energy += Energy_levels[ship_p->weapon_recharge_index] * max_new_weapon_energy * Skill_level_weapon_energy_scale[Game_skill_level];
313         } else {
314                 ship_p->weapon_energy += Energy_levels[ship_p->weapon_recharge_index] * max_new_weapon_energy;
315         }
316
317         if ( ship_p->weapon_energy > sinfo_p->max_weapon_reserve ){
318                 ship_p->weapon_energy = sinfo_p->max_weapon_reserve;
319         }
320
321         float shield_delta;
322         max_new_shield_energy = fl_frametime * MAX_SHIELD_REGEN_PER_SECOND * sinfo_p->shields;
323         if ( objp->flags & OF_PLAYER_SHIP ) {
324                 shield_delta = Energy_levels[ship_p->shield_recharge_index] * max_new_shield_energy * Skill_level_shield_energy_scale[Game_skill_level];
325         } else {
326                 shield_delta = Energy_levels[ship_p->shield_recharge_index] * max_new_shield_energy;
327         }
328
329         add_shield_strength(objp, shield_delta);
330
331         if ( (_ss = get_shield_strength(objp)) > sinfo_p->shields ){
332                 for (int i=0; i<MAX_SHIELD_SECTIONS; i++){
333                         objp->shields[i] *= sinfo_p->shields/ _ss;
334                 }
335         }
336
337         // calculate the top speed of the ship based on the energy flow to engines
338         float y = Energy_levels[ship_p->engine_recharge_index];
339
340         // check for a shortcuts first before doing linear interpolation
341         if ( y == Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX] ){
342                 ship_p->current_max_speed = sinfo_p->max_speed;
343         } else if ( y == 0.0f ){
344                 ship_p->current_max_speed = 0.5f * sinfo_p->max_speed;
345         } else if ( y == 1.0f ){
346                 ship_p->current_max_speed = sinfo_p->max_overclocked_speed;
347         } else {
348                 // do a linear interpolation to find the current max speed, using points (0,1/2 default_max_speed) (.333,default_max_speed)
349                 // x = x1 + (y-y1) * (x2-x1) / (y2-y1);
350                 if ( y < Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX] ){
351                         ship_p->current_max_speed =  0.5f*sinfo_p->max_speed + (y  * (0.5f*sinfo_p->max_speed) ) / Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX];
352                 } else {
353                         // do a linear interpolation to find the current max speed, using points (.333,default_max_speed) (1,max_overclock_speed)
354                         ship_p->current_max_speed = sinfo_p->max_speed + (y - Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX]) * (sinfo_p->max_overclocked_speed - sinfo_p->max_speed) / (1.0f - Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX]);
355                 }
356         }
357
358         // AL 11-15-97: Rules for engine strength affecting max speed:
359         //                                              1. if strength >= 0.5 no affect 
360         //                                              2. if strength < 0.5 then max_speed = sqrt(strength)
361         //                                       
362         //                                       This will translate to 71% max speed at 50% engines, and 31% max speed at 10% engines
363         //
364         float strength = ship_get_subsystem_strength(ship_p, SUBSYSTEM_ENGINE);
365
366         // don't let engine strength affect max speed when playing on lowest skill level
367         if ( (objp != Player_obj) || (Game_skill_level > 0) ) {
368                 if ( strength < 0.5 ) {
369                         ship_p->current_max_speed *= fl_sqrt(strength);
370                 }
371         }
372
373         if ( timestamp_elapsed(ship_p->next_manage_ets) ) {
374                 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
375                         ai_manage_ets(objp);
376                         ship_p->next_manage_ets = timestamp(AI_MODIFY_ETS_INTERVAL);
377                 }
378                 else {
379                         if ( Weapon_energy_cheat ){
380                                 ship_p->weapon_energy = sinfo_p->max_weapon_reserve;
381                         }
382                 }
383         }
384 }
385
386
387 // -------------------------------------------------------------------------------------------------
388 // ai_manage_ets() will determine if a ship should modify it's energy transfer percentages, or 
389 // transfer energy from shields->weapons or from weapons->shields
390 //
391
392 // minimum level rule constants
393 #define SHIELDS_MIN_LEVEL_PERCENT       0.3f
394 #define WEAPONS_MIN_LEVEL_PERCENT       0.3f
395
396 // maximum level rule constants
397 #define SHIELDS_MAX_LEVEL_PERCENT       0.8f
398 #define WEAPONS_MAX_LEVEL_PERCENT       0.8f
399
400 // emergency rule constants
401 #define SHIELDS_EMERG_LEVEL_PERCENT     0.10f
402 #define WEAPONS_EMERG_LEVEL_PERCENT     0.05f
403
404 // need this, or ai's tend to totally eliminate engine power!
405 #define MIN_ENGINE_RECHARGE_INDEX       3
406
407 #define DEFAULT_CHARGE_INDEX                    4
408 #define NORMAL_TOLERANCE_PERCENT                .10f
409
410 void ai_manage_ets(object* obj)
411 {
412         ship* ship_p = &Ships[obj->instance];
413         ship_info* ship_info_p = &Ship_info[ship_p->ship_info_index];
414
415         if ( ship_info_p->power_output == 0 )
416                 return;
417
418         if (ship_p->flags & SF_DYING)
419                 return;
420
421         // check if any of the three systems are not being used.  If so, don't allow energy management.
422         if ( !ship_info_p->shields || !ship_info_p->max_speed || !ship_info_p->max_weapon_reserve)
423                 return;
424
425         float shield_left_percent = get_shield_strength(obj)/ship_info_p->shields;
426         float weapon_left_percent = ship_p->weapon_energy/ship_info_p->max_weapon_reserve;
427
428         // maximum level check
429         //      MK, changed these, might as well let them go up to 100% if nothing else needs the recharge ability.
430         if ( weapon_left_percent == 1.0f) {
431                 decrease_recharge_rate(obj, WEAPONS);
432         }
433
434         if (!(obj->flags & OF_NO_SHIELDS) && (shield_left_percent == 1.0f)) {
435                 decrease_recharge_rate(obj, SHIELDS);
436         }
437
438         // minimum check
439
440         if (!(obj->flags & OF_NO_SHIELDS) && (shield_left_percent < SHIELDS_MIN_LEVEL_PERCENT)) {
441                 if ( weapon_left_percent > WEAPONS_MIN_LEVEL_PERCENT )
442                         increase_recharge_rate(obj, SHIELDS);
443         }
444
445         if ( weapon_left_percent < WEAPONS_MIN_LEVEL_PERCENT ) {
446                 increase_recharge_rate(obj, WEAPONS);
447         }
448
449         if ( ship_p->engine_recharge_index < MIN_ENGINE_RECHARGE_INDEX ) {
450                 increase_recharge_rate(obj, ENGINES);
451         }
452
453         // emergency check
454         if (!(obj->flags & OF_NO_SHIELDS)) {
455                 if ( shield_left_percent < SHIELDS_EMERG_LEVEL_PERCENT ) {
456                         if (ship_p->target_shields_delta == 0.0f)
457                                 transfer_energy_to_shields(obj);
458                 } else if ( weapon_left_percent < WEAPONS_EMERG_LEVEL_PERCENT ) {
459                         if ( shield_left_percent > SHIELDS_MIN_LEVEL_PERCENT || weapon_left_percent <= 0.01 )   // dampen ai enthusiasm for sucking energy to weapons
460                                 transfer_energy_to_weapons(obj);
461                 }
462
463         
464                 // check for return to normal values
465                 if ( fl_abs( shield_left_percent - 0.5f ) < NORMAL_TOLERANCE_PERCENT ) {
466                         if ( ship_p->shield_recharge_index > DEFAULT_CHARGE_INDEX )
467                                 decrease_recharge_rate(obj, SHIELDS);
468                         else if ( ship_p->shield_recharge_index < DEFAULT_CHARGE_INDEX )
469                                 increase_recharge_rate(obj, SHIELDS);
470                 }
471         }
472
473
474         if ( fl_abs( weapon_left_percent - 0.5f ) < NORMAL_TOLERANCE_PERCENT ) {
475                 if ( ship_p->weapon_recharge_index > DEFAULT_CHARGE_INDEX )
476                         decrease_recharge_rate(obj, WEAPONS);
477                 else if ( ship_p->weapon_recharge_index < DEFAULT_CHARGE_INDEX )
478                         increase_recharge_rate(obj, WEAPONS);
479         }
480 }
481
482 // -------------------------------------------------------------------------------------------------
483 // hud_show_ets() will display the charge rates for the three systems, and the reserve
484 // energy for shields and weapons.  hud_show_ets() is called once per frame.
485 //
486 void hud_show_ets()
487 {
488         int i, j, index, y_start, y_end, clip_h, w, h, x, y;
489
490         ship* ship_p = &Ships[Player_obj->instance];    
491
492         if ( Ets_gauge.first_frame < 0 ) {
493                 return;
494         }
495
496         hud_set_gauge_color(HUD_ETS_GAUGE);
497
498         // draw the letters for the gauges first, before any clipping occurs
499         i = 0;
500         for ( j = 0; j < 3; j++ ) {
501                 if ( j == 1 && Player_obj->flags & OF_NO_SHIELDS ) {
502                         continue;
503                 }
504                 Assert(Ets_gauge_info != NULL);
505                 gr_printf(Ets_gauge_info[i].letter_coords[0], Ets_gauge_info[i].letter_coords[1], NOX("%c"), Ets_gauge_info[j].letter); 
506                 i++;
507         }
508
509         // draw the three energy gauges
510         i = 0;
511         index = 0;
512         for ( j = 0; j < 3; j++ ) {
513                 switch (j) {
514                 case 0:
515                         index = ship_p->weapon_recharge_index;
516                         break;
517                 case 1:
518                         index = ship_p->shield_recharge_index;
519                         if ( Player_obj->flags & OF_NO_SHIELDS ) {
520                                 continue;
521                         }
522                         break;
523                 case 2:
524                         index = ship_p->engine_recharge_index;
525                         break;
526                 }
527
528                 clip_h = fl2i( (1 - Energy_levels[index]) * ETS_bar_h[gr_screen.res] );
529
530                 bm_get_info(Ets_gauge.first_frame,&w,&h);
531
532                 if ( index < NUM_ENERGY_LEVELS-1 ) {
533                         // some portion of dark needs to be drawn
534
535                         hud_set_gauge_color(HUD_ETS_GAUGE);
536
537                         // draw the top portion
538
539                         Assert(Ets_gauge_info != NULL);
540                         x = Ets_gauge_info[i].top_coords[0];
541                         y = Ets_gauge_info[i].top_coords[1];
542                         
543                         GR_AABITMAP_EX(Ets_gauge.first_frame,x,y,w,clip_h,0,0);                 
544
545                         // draw the bottom portion
546                         Assert(Ets_gauge_info != NULL);
547                         x = Ets_gauge_info[i].bottom_coords[0];
548                         y = Ets_gauge_info[i].bottom_coords[1];
549
550                         y_start = y + (ETS_bar_h[gr_screen.res] - clip_h);
551                         y_end = y + ETS_bar_h[gr_screen.res];
552                         
553                         GR_AABITMAP_EX(Ets_gauge.first_frame, x, y_start, w, y_end-y_start, 0, ETS_bar_h[gr_screen.res]-clip_h);                        
554                 }
555
556                 if ( index > 0 ) {
557                         if ( hud_gauge_maybe_flash(HUD_ETS_GAUGE) == 1 ) {
558                                 hud_set_gauge_color(HUD_ETS_GAUGE, HUD_C_DIM);
559                                 // hud_set_dim_color();
560                         } else {
561                                 hud_set_gauge_color(HUD_ETS_GAUGE, HUD_C_BRIGHT);
562                                 // hud_set_bright_color();
563                         }
564                         // some portion of recharge needs to be drawn
565
566                         // draw the top portion
567                         Assert(Ets_gauge_info != NULL);
568                         x = Ets_gauge_info[i].top_coords[0];
569                         y = Ets_gauge_info[i].top_coords[1];
570
571                         y_start = y + clip_h;
572                         y_end = y + ETS_bar_h[gr_screen.res];
573                         
574                         GR_AABITMAP_EX(Ets_gauge.first_frame+1, x, y_start, w, y_end-y_start, 0, clip_h);                       
575
576                         // draw the bottom portion
577                         Assert(Ets_gauge_info != NULL);
578                         x = Ets_gauge_info[i].bottom_coords[0];
579                         y = Ets_gauge_info[i].bottom_coords[1];
580                         
581                         GR_AABITMAP_EX(Ets_gauge.first_frame+2, x,y,w,ETS_bar_h[gr_screen.res]-clip_h,0,0);                     
582                 }
583                 i++;
584         }
585
586         // hud_set_default_color();
587 }
588
589 // -------------------------------------------------------------------------------------------------
590 // set_default_recharge_rates() will set the charge levels for the weapons, shields and
591 // engines to their default levels
592 void set_default_recharge_rates(object* obj)
593 {
594         int ship_properties;
595
596         ship* ship_p = &Ships[obj->instance];
597         ship_info* ship_info_p = &Ship_info[ship_p->ship_info_index];
598
599         if ( ship_info_p->power_output == 0 )
600                 return;
601
602         ship_properties = 0;    
603         if ( ship_info_p->max_weapon_reserve )
604                 ship_properties |= HAS_WEAPONS;
605         
606         if (!(obj->flags & OF_NO_SHIELDS))
607                 ship_properties |= HAS_SHIELDS;
608
609         if ( ship_info_p->max_speed )
610                 ship_properties |= HAS_ENGINES;
611
612         // the default charge rate depends on what systems are on each ship
613         switch ( ship_properties ) {
614                 case HAS_ENGINES | HAS_WEAPONS | HAS_SHIELDS:
615                         ship_p->shield_recharge_index = INTIAL_SHIELD_RECHARGE_INDEX;
616                         ship_p->weapon_recharge_index = INTIAL_WEAPON_RECHARGE_INDEX;
617                         ship_p->engine_recharge_index = INTIAL_ENGINE_RECHARGE_INDEX;
618                         break;
619
620                 case HAS_ENGINES | HAS_SHIELDS:
621                         ship_p->shield_recharge_index = ONE_HALF_INDEX;
622                         ship_p->weapon_recharge_index = ZERO_INDEX;
623                         ship_p->engine_recharge_index = ONE_HALF_INDEX;
624                         break;
625
626                 case HAS_WEAPONS | HAS_SHIELDS:
627                         ship_p->shield_recharge_index = ONE_HALF_INDEX;
628                         ship_p->weapon_recharge_index = ONE_HALF_INDEX;
629                         ship_p->engine_recharge_index = ZERO_INDEX;
630                         break;
631
632                 case HAS_ENGINES | HAS_WEAPONS:
633                         ship_p->shield_recharge_index = ZERO_INDEX;
634                         ship_p->weapon_recharge_index = ONE_HALF_INDEX;
635                         ship_p->engine_recharge_index = ONE_HALF_INDEX;
636                         break;
637
638                 case HAS_SHIELDS:
639                         ship_p->shield_recharge_index = ALL_INDEX;
640                         ship_p->weapon_recharge_index = ZERO_INDEX;
641                         ship_p->engine_recharge_index = ZERO_INDEX;
642                         break;
643
644                 case HAS_ENGINES:
645                         ship_p->shield_recharge_index = ZERO_INDEX;
646                         ship_p->weapon_recharge_index = ZERO_INDEX;
647                         ship_p->engine_recharge_index = ALL_INDEX;
648                         break;
649
650                 case HAS_WEAPONS:
651                         ship_p->shield_recharge_index = ZERO_INDEX;
652                         ship_p->weapon_recharge_index = ALL_INDEX;
653                         ship_p->engine_recharge_index = ZERO_INDEX;
654                         break;
655
656                 default:
657                         Int3(); // if no systems, power output should be zero, and this funtion shouldn't be called
658                         break;
659         } // end switch
660 }
661
662 // -------------------------------------------------------------------------------------------------
663 // increase_recharge_rate() will increase the energy flow to the specified system (one of
664 // WEAPONS, SHIELDS or ENGINES).  The increase in energy will result in a decrease to
665 // the other two systems.
666 void increase_recharge_rate(object* obj, SYSTEM_TYPE ship_system) 
667 {
668         int     *gain_index=NULL, *lose_index1=NULL, *lose_index2=NULL, *tmp=NULL;
669         int     count=0;
670         ship    *ship_p = &Ships[obj->instance];
671
672         switch ( ship_system ) {
673                 case WEAPONS:
674                         gain_index = &ship_p->weapon_recharge_index;
675                         lose_index1 = &ship_p->engine_recharge_index;
676                         if ( obj->flags & OF_NO_SHIELDS ) {
677                                 lose_index2 = NULL;
678                         } else {
679                                 lose_index2 = &ship_p->shield_recharge_index;
680                         }
681                         break;
682
683                 case SHIELDS:
684                         if ( obj->flags & OF_NO_SHIELDS ) {
685                                 return;
686                         }
687                         gain_index = &ship_p->shield_recharge_index;
688                         lose_index1 = &ship_p->weapon_recharge_index;
689                         lose_index2 = &ship_p->engine_recharge_index;
690                         break;
691
692                 case ENGINES:
693                         gain_index = &ship_p->engine_recharge_index;
694                         lose_index1 = &ship_p->weapon_recharge_index;
695                         if ( obj->flags & OF_NO_SHIELDS ) {
696                                 lose_index2 = NULL;
697                         } else {
698                                 lose_index2 = &ship_p->shield_recharge_index;
699                         }
700                         break;
701
702         } // end switch
703
704         // already full, nothing to do 
705         count = MAX_ENERGY_INDEX - *gain_index;
706         if ( count > 2 ) 
707                 count = 2;
708
709         if ( count <= 0 ) {
710                 if ( obj == Player_obj ) {
711                         snd_play( &Snds[SND_ENERGY_TRANS_FAIL], 0.0f );
712                 }
713                 return;
714         }
715
716         *gain_index += count;
717
718         // ensure that the highest lose index takes the first decrease
719         if ( lose_index1 && lose_index2 ) {
720                 if ( *lose_index1 < *lose_index2 ) {
721                         tmp = lose_index1;
722                         lose_index1 = lose_index2;
723                         lose_index2 = tmp;
724                 }
725         }
726
727         int sanity = 0;
728         while(count > 0) {
729                 if ( lose_index1 && *lose_index1 > 0 ) {
730                         *lose_index1 -= 1;
731                         count--;
732                 }
733
734                 if ( count <= 0 ) 
735                         break;
736
737                 if ( lose_index2 && *lose_index2 > 0 ) {
738                         *lose_index2 -= 1;
739                         count--;
740                 }
741
742                 if ( sanity++ > 10 ) {
743                         Int3(); // get Alan
744                         break;
745                 }
746         }
747
748         if ( obj == Player_obj )
749                 snd_play( &Snds[SND_ENERGY_TRANS], 0.0f );
750 }
751
752 // -------------------------------------------------------------------------------------------------
753 // decrease_recharge_rate() will decrease the energy flow to the specified system (one of
754 // WEAPONS, SHIELDS or ENGINES).  The decrease in energy will result in an increase to
755 // the other two systems.
756 void decrease_recharge_rate(object* obj, SYSTEM_TYPE ship_system) 
757 {
758         int     *lose_index=NULL, *gain_index1=NULL, *gain_index2=NULL, *tmp=NULL;
759         int     count;
760         ship    *ship_p = &Ships[obj->instance];
761
762         switch ( ship_system ) {
763                 case WEAPONS:
764                         lose_index = &ship_p->weapon_recharge_index;
765
766                         if ( obj->flags & OF_NO_SHIELDS ) {
767                                 gain_index1 = NULL;
768                         } else {
769                                 gain_index1 = &ship_p->shield_recharge_index;
770                         }
771
772                         gain_index2 = &ship_p->engine_recharge_index;
773                         break;
774
775                 case SHIELDS:
776                         if ( obj->flags & OF_NO_SHIELDS ) {
777                                 return;
778                         }
779                         lose_index = &ship_p->shield_recharge_index;
780                         gain_index1 = &ship_p->weapon_recharge_index;
781                         gain_index2 = &ship_p->engine_recharge_index;
782                         break;
783
784                 case ENGINES:
785                         lose_index = &ship_p->engine_recharge_index;
786
787                         if ( obj->flags & OF_NO_SHIELDS ) {
788                                 gain_index1 = NULL;
789                         } else {
790                                 gain_index1 = &ship_p->shield_recharge_index;
791                         }
792
793                         gain_index2 = &ship_p->weapon_recharge_index;
794                         break;
795         } // end switch
796
797         // check how much there is to lose
798         count = min(2, *lose_index);
799         if ( count <= 0 ) {
800                 if ( obj == Player_obj ) {
801                         snd_play( &Snds[SND_ENERGY_TRANS_FAIL], 0.0f );
802                 }
803                 return;
804         }
805
806         *lose_index -= count;
807
808         // make sure that the gain starts with the system which needs it most
809         if ( gain_index1 && gain_index2 ) {
810                 if ( *gain_index1 > *gain_index2 ) {
811                         tmp = gain_index1;
812                         gain_index1 = gain_index2;
813                         gain_index2 = tmp;
814                 }
815         }
816
817         int sanity=0;
818         while(count > 0) {
819                 if ( gain_index1 && *gain_index1 < MAX_ENERGY_INDEX ) {
820                         *gain_index1 += 1;
821                         count--;
822                 }
823
824                 if ( count <= 0 ) 
825                         break;
826
827                 if ( gain_index2 && *gain_index2 < MAX_ENERGY_INDEX ) {
828                         *gain_index2 += 1;
829                         count--;
830                 }
831
832                 if ( sanity++ > 10 ) {
833                         Int3(); // get Alan
834                         break;
835                 }
836         }
837
838         if ( obj == Player_obj )
839                 snd_play( &Snds[SND_ENERGY_TRANS], 0.0f );
840 }
841
842 void transfer_energy_weapon_common(object *objp, float from_field, float to_field, float *from_delta, float *to_delta, float max, float scale)
843 {
844         float   delta;
845
846         delta = from_field * ENERGY_DIVERT_DELTA * scale;
847
848         if (to_field + *to_delta + delta > max)
849                 delta = max - to_field - *to_delta;
850
851         if ( delta > 0 ) {
852                 if ( objp == Player_obj )
853                         snd_play( &Snds[SND_ENERGY_TRANS], 0.0f );
854
855                 if (delta > from_field)
856                         delta = from_field;
857
858                 *to_delta += delta;
859                 *from_delta -= delta;
860         } else
861                 if ( objp == Player_obj )
862                         snd_play( &Snds[SND_ENERGY_TRANS_FAIL], 0.0f );
863 }
864
865 // -------------------------------------------------------------------------------------------------
866 // transfer_energy_to_shields() will transfer ENERGY_DIVERT_DELTA percent of weapon energy
867 // to shield energy.
868 void transfer_energy_to_shields(object* obj)
869 {
870         ship*                   ship_p = &Ships[obj->instance];
871         ship_info*      sinfo_p = &Ship_info[ship_p->ship_info_index];
872
873         if (ship_p->flags & SF_DYING)
874                 return;
875
876         if ( obj->flags & OF_NO_SHIELDS ) {
877                 return;
878         }
879
880         transfer_energy_weapon_common(obj, ship_p->weapon_energy, get_shield_strength(obj), &ship_p->target_weapon_energy_delta, &ship_p->target_shields_delta, sinfo_p->shields, 0.5f);
881 }
882
883 // -------------------------------------------------------------------------------------------------
884 // transfer_energy_to_weapons() will transfer ENERGY_DIVERT_DELTA percent of shield energy
885 // to weapon energy.
886 void transfer_energy_to_weapons(object* obj)
887 {
888         ship*                   ship_p = &Ships[obj->instance];
889         ship_info*      sinfo_p = &Ship_info[ship_p->ship_info_index];
890
891         if (ship_p->flags & SF_DYING)
892                 return;
893
894         transfer_energy_weapon_common(obj, get_shield_strength(obj), ship_p->weapon_energy, &ship_p->target_shields_delta, &ship_p->target_weapon_energy_delta, sinfo_p->max_weapon_reserve, 1.0f);
895 }
896
897 void hudets_page_in()
898 {
899         bm_page_in_aabitmap( Ets_gauge.first_frame, Ets_gauge.num_frames );
900 }
901