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