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