FS2_Open
Open source remastering of the Freespace 2 engine
hudets.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include "freespace2/freespace.h"
14 #include "gamesnd/gamesnd.h"
15 #include "globalincs/systemvars.h"
16 #include "hud/hudets.h"
17 #include "io/timer.h"
18 #include "localization/localize.h"
19 #include "object/object.h"
20 #include "object/objectshield.h"
21 #include "ship/ship.h"
22 #include "ship/subsysdamage.h"
23 #include "weapon/emp.h"
24 #include "weapon/weapon.h"
25 
26 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};
28 
29 // -------------------------------------------------------------------------------------------------
30 // ets_init_ship() is called by a ship when it is created (effectively, for every ship at the start
31 // of a mission). This will set the default charge rates for the different systems and initialize
32 // the weapon energy reserve.
33 //
34 void ets_init_ship(object* obj)
35 {
36  ship* sp;
37 
38  // fred should bail here
39  if(Fred_running){
40  return;
41  }
42 
43  Assert(obj->type == OBJ_SHIP);
44  sp = &Ships[obj->instance];
45 
46  sp->weapon_energy = Ship_info[sp->ship_info_index].max_weapon_reserve;
47  if ((sp->flags2 & SF2_NO_ETS) == 0) {
49  } else {
50  sp->next_manage_ets = -1;
51  }
53 }
54 
55 // -------------------------------------------------------------------------------------------------
56 // update_ets() is called once per frame for every OBJ_SHIP in the game. The amount of energy
57 // to send to the weapons and shields is calculated, and the top ship speed is calculated. The
58 // amount of time elapsed from the previous call is passed in as the parameter fl_frametime.
59 //
60 // parameters: obj ==> object that is updating their energy system
61 // fl_frametime ==> game frametime (in seconds)
62 //
63 void update_ets(object* objp, float fl_frametime)
64 {
65  float max_new_shield_energy, max_new_weapon_energy, _ss;
66 
67  if ( fl_frametime <= 0 ){
68  return;
69  }
70 
71  ship* ship_p = &Ships[objp->instance];
72  ship_info* sinfo_p = &Ship_info[ship_p->ship_info_index];
73  float max_g=sinfo_p->max_weapon_reserve,
74  max_s=ship_p->ship_max_shield_strength;
75 
76  if ( ship_p->flags & SF_DYING ){
77  return;
78  }
79 
80  if ( sinfo_p->power_output == 0 ){
81  return;
82  }
83 
84 // new_energy = fl_frametime * sinfo_p->power_output;
85 
86  // update weapon energy
87  max_new_weapon_energy = fl_frametime * sinfo_p->max_weapon_regen_per_second * max_g;
88  if ( objp->flags & OF_PLAYER_SHIP ) {
90  } else {
91  ship_p->weapon_energy += Energy_levels[ship_p->weapon_recharge_index] * max_new_weapon_energy;
92  }
93 
94  if ( ship_p->weapon_energy > sinfo_p->max_weapon_reserve ){
95  ship_p->weapon_energy = sinfo_p->max_weapon_reserve;
96  }
97 
98  float shield_delta;
99  max_new_shield_energy = fl_frametime * sinfo_p->max_shield_regen_per_second * max_s;
100  if ( objp->flags & OF_PLAYER_SHIP ) {
101  shield_delta = Energy_levels[ship_p->shield_recharge_index] * max_new_shield_energy * The_mission.ai_profile->shield_energy_scale[Game_skill_level];
102  } else {
103  shield_delta = Energy_levels[ship_p->shield_recharge_index] * max_new_shield_energy;
104  }
105 
106  shield_add_strength(objp, shield_delta);
107 
108  if ( (_ss = shield_get_strength(objp)) > ship_p->ship_max_shield_strength ){
109  for (int i=0; i<objp->n_quadrants; i++){
110  objp->shield_quadrant[i] *= ship_p->ship_max_shield_strength / _ss;
111  }
112  }
113 
114  // calculate the top speed of the ship based on the energy flow to engines
115  float y = Energy_levels[ship_p->engine_recharge_index];
116 
117  ship_p->current_max_speed = ets_get_max_speed(objp, y);
118 
119  // AL 11-15-97: Rules for engine strength affecting max speed:
120  // 1. if strength >= 0.5 no affect
121  // 2. if strength < 0.5 then max_speed = sqrt(strength)
122  //
123  // This will translate to 71% max speed at 50% engines, and 31% max speed at 10% engines
124  //
125  float strength = ship_get_subsystem_strength(ship_p, SUBSYSTEM_ENGINE);
126 
127  // don't let engine strength affect max speed when playing on lowest skill level
128  if ( (objp != Player_obj) || (Game_skill_level > 0) ) {
129  if ( strength < SHIP_MIN_ENGINES_FOR_FULL_SPEED ) {
130  ship_p->current_max_speed *= fl_sqrt(strength);
131  }
132  }
133 
134  if ( timestamp_elapsed(ship_p->next_manage_ets) ) {
135  if ( !(objp->flags & OF_PLAYER_SHIP) ) {
136  ai_manage_ets(objp);
138  }
139  else {
140  if ( Weapon_energy_cheat ){
141  ship_p->weapon_energy = sinfo_p->max_weapon_reserve;
142  }
143  }
144  }
145 }
146 
147 float ets_get_max_speed(object* objp, float engine_energy)
148 {
149  Assertion(objp != NULL, "Invalid object pointer passed!");
150  Assertion(objp->type == OBJ_SHIP, "Object needs to be a ship object!");
151  Assertion(engine_energy >= 0.0f && engine_energy <= 1.0f, "Invalid float passed, needs to be in [0, 1], was %f!", engine_energy);
152 
153  ship* shipp = &Ships[objp->instance];
154 
155  ship_info* sip = &Ship_info[shipp->ship_info_index];
156 
157  // check for a shortcuts first before doing linear interpolation
158  if ( engine_energy == Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX] ){
159  return sip->max_speed;
160  } else if ( engine_energy == 0.0f ){
161  return 0.5f * sip->max_speed;
162  } else if ( engine_energy == 1.0f ){
163  return sip->max_overclocked_speed;
164  } else {
165  // do a linear interpolation to find the current max speed, using points (0,1/2 default_max_speed) (.333,default_max_speed)
166  // x = x1 + (y-y1) * (x2-x1) / (y2-y1);
167  if ( engine_energy < Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX] ){
168  return 0.5f*sip->max_speed + (engine_energy * (0.5f*sip->max_speed) ) / Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX];
169  } else {
170  // do a linear interpolation to find the current max speed, using points (.333,default_max_speed) (1,max_overclock_speed)
172  }
173  }
174 }
175 
176 
177 // -------------------------------------------------------------------------------------------------
178 // ai_manage_ets() will determine if a ship should modify it's energy transfer percentages, or
179 // transfer energy from shields->weapons or from weapons->shields
180 //
181 
182 // minimum level rule constants
183 #define SHIELDS_MIN_LEVEL_PERCENT 0.3f
184 #define WEAPONS_MIN_LEVEL_PERCENT 0.3f
185 
186 // maximum level rule constants
187 #define SHIELDS_MAX_LEVEL_PERCENT 0.8f
188 #define WEAPONS_MAX_LEVEL_PERCENT 0.8f
189 
190 // emergency rule constants
191 #define SHIELDS_EMERG_LEVEL_PERCENT 0.10f
192 #define WEAPONS_EMERG_LEVEL_PERCENT 0.05f
193 
194 // need this, or ai's tend to totally eliminate engine power!
195 #define MIN_ENGINE_RECHARGE_INDEX 3
196 
197 #define DEFAULT_CHARGE_INDEX 4
198 #define NORMAL_TOLERANCE_PERCENT .10f
199 
200 void ai_manage_ets(object* obj)
201 {
202  ship* ship_p = &Ships[obj->instance];
203  ship_info* ship_info_p = &Ship_info[ship_p->ship_info_index];
204 
205  if ( ship_info_p->power_output == 0 )
206  return;
207 
208  if (ship_p->flags & SF_DYING)
209  return;
210 
211  // check if any of the three systems are not being used. If so, don't allow energy management.
212  if ( !ship_p->ship_max_shield_strength || !ship_info_p->max_speed || !ship_info_p->max_weapon_reserve)
213  return;
214 
215  float shield_left_percent = get_shield_pct(obj);
216  float weapon_left_percent = ship_p->weapon_energy/ship_info_p->max_weapon_reserve;
217 
218  // maximum level check
219  // MK, changed these, might as well let them go up to 100% if nothing else needs the recharge ability.
220  if ( weapon_left_percent == 1.0f) {
222  }
223 
224  if (!(obj->flags & OF_NO_SHIELDS) && (shield_left_percent == 1.0f)) {
226  }
227 
228  // minimum check
229 
230  if (!(obj->flags & OF_NO_SHIELDS) && (shield_left_percent < SHIELDS_MIN_LEVEL_PERCENT)) {
231  if ( weapon_left_percent > WEAPONS_MIN_LEVEL_PERCENT )
233  }
234 
235  if ( weapon_left_percent < WEAPONS_MIN_LEVEL_PERCENT ) {
237  }
238 
241  }
242 
243  // emergency check
244  if (!(obj->flags & OF_NO_SHIELDS)) {
245  if ( shield_left_percent < SHIELDS_EMERG_LEVEL_PERCENT ) {
246  if (ship_p->target_shields_delta == 0.0f)
248  } else if ( weapon_left_percent < WEAPONS_EMERG_LEVEL_PERCENT ) {
249  if ( shield_left_percent > SHIELDS_MIN_LEVEL_PERCENT || weapon_left_percent <= 0.01 ) // dampen ai enthusiasm for sucking energy to weapons
251  }
252 
253 
254  // check for return to normal values
255  if ( fl_abs( shield_left_percent - 0.5f ) < NORMAL_TOLERANCE_PERCENT ) {
258  else if ( ship_p->shield_recharge_index < DEFAULT_CHARGE_INDEX )
260  }
261  }
262 
263 
264  if ( fl_abs( weapon_left_percent - 0.5f ) < NORMAL_TOLERANCE_PERCENT ) {
267  else if ( ship_p->weapon_recharge_index < DEFAULT_CHARGE_INDEX )
269  }
270 }
271 
272 // -------------------------------------------------------------------------------------------------
273 // set_default_recharge_rates() will set the charge levels for the weapons, shields and
274 // engines to their default levels
276 {
277  int ship_properties;
278 
279  ship* ship_p = &Ships[obj->instance];
280  ship_info* ship_info_p = &Ship_info[ship_p->ship_info_index];
281 
282  if ( ship_info_p->power_output == 0 )
283  return;
284 
285  ship_properties = 0;
286  if (ship_has_energy_weapons(ship_p))
287  ship_properties |= HAS_WEAPONS;
288 
289  if (!(obj->flags & OF_NO_SHIELDS))
290  ship_properties |= HAS_SHIELDS;
291 
292  if (ship_has_engine_power(ship_p))
293  ship_properties |= HAS_ENGINES;
294 
295  // the default charge rate depends on what systems are on each ship
296  switch ( ship_properties ) {
301  break;
302 
303  case HAS_ENGINES | HAS_SHIELDS:
307  break;
308 
309  case HAS_WEAPONS | HAS_SHIELDS:
313  break;
314 
315  case HAS_ENGINES | HAS_WEAPONS:
319  break;
320 
321  case HAS_SHIELDS:
325  break;
326 
327  case HAS_ENGINES:
331  break;
332 
333  case HAS_WEAPONS:
337  break;
338 
339  default:
340  Int3(); // if no systems, power output should be zero, and this funtion shouldn't be called
341  break;
342  } // end switch
343 }
344 
345 // -------------------------------------------------------------------------------------------------
346 // increase_recharge_rate() will increase the energy flow to the specified system (one of
347 // WEAPONS, SHIELDS or ENGINES). The increase in energy will result in a decrease to
348 // the other two systems.
349 void increase_recharge_rate(object* obj, SYSTEM_TYPE ship_system)
350 {
351  int *gain_index=NULL, *lose_index1=NULL, *lose_index2=NULL, *tmp=NULL;
352  int count=0;
353  ship *ship_p = &Ships[obj->instance];
354 
355  if (ship_p->flags2 & SF2_NO_ETS)
356  return;
357 
358  switch ( ship_system ) {
359  case WEAPONS:
360  if ( !ship_has_energy_weapons(ship_p) )
361  return;
362 
363  gain_index = &ship_p->weapon_recharge_index;
364 
365  if ( obj->flags & OF_NO_SHIELDS )
366  lose_index1 = NULL;
367  else
368  lose_index1 = &ship_p->shield_recharge_index;
369 
370  if ( !ship_has_engine_power(ship_p) )
371  lose_index2 = NULL;
372  else
373  lose_index2 = &ship_p->engine_recharge_index;
374 
375  break;
376 
377  case SHIELDS:
378  if ( obj->flags & OF_NO_SHIELDS )
379  return;
380 
381  gain_index = &ship_p->shield_recharge_index;
382 
383  if ( !ship_has_energy_weapons(ship_p) )
384  lose_index1 = NULL;
385  else
386  lose_index1 = &ship_p->weapon_recharge_index;
387 
388  if ( !ship_has_engine_power(ship_p) )
389  lose_index2 = NULL;
390  else
391  lose_index2 = &ship_p->engine_recharge_index;
392 
393  break;
394 
395  case ENGINES:
396  if ( !ship_has_engine_power(ship_p) )
397  return;
398 
399  gain_index = &ship_p->engine_recharge_index;
400 
401  if ( !ship_has_energy_weapons(ship_p) )
402  lose_index1 = NULL;
403  else
404  lose_index1 = &ship_p->weapon_recharge_index;
405 
406  if ( obj->flags & OF_NO_SHIELDS )
407  lose_index2 = NULL;
408  else
409  lose_index2 = &ship_p->shield_recharge_index;
410 
411  break;
412 
413  } // end switch
414 
415  // return if we can't transfer energy
416  if (!lose_index1 && !lose_index2)
417  return;
418 
419  // already full, nothing to do
420  count = MAX_ENERGY_INDEX - *gain_index;
421  if ( count > 2 )
422  count = 2;
423 
424  if ( count <= 0 )
425  {
426  if ( obj == Player_obj )
427  {
429  }
430  return;
431  }
432 
433  *gain_index += count;
434 
435  // ensure that the highest lose index takes the first decrease
436  if ( lose_index1 && lose_index2 ) {
437  if ( *lose_index1 < *lose_index2 ) {
438  tmp = lose_index1;
439  lose_index1 = lose_index2;
440  lose_index2 = tmp;
441  }
442  }
443 
444  int sanity = 0;
445  while(count > 0) {
446  if ( lose_index1 && *lose_index1 > 0 ) {
447  *lose_index1 -= 1;
448  count--;
449  }
450 
451  if ( count <= 0 )
452  break;
453 
454  if ( lose_index2 && *lose_index2 > 0 ) {
455  *lose_index2 -= 1;
456  count--;
457  }
458 
459  if ( sanity++ > 10 ) {
460  Int3(); // get Alan
461  break;
462  }
463  }
464 
465  if ( obj == Player_obj )
466  snd_play( &Snds[SND_ENERGY_TRANS], 0.0f );
467 }
468 
469 // -------------------------------------------------------------------------------------------------
470 // decrease_recharge_rate() will decrease the energy flow to the specified system (one of
471 // WEAPONS, SHIELDS or ENGINES). The decrease in energy will result in an increase to
472 // the other two systems.
473 void decrease_recharge_rate(object* obj, SYSTEM_TYPE ship_system)
474 {
475  int *lose_index=NULL, *gain_index1=NULL, *gain_index2=NULL, *tmp=NULL;
476  int count;
477  ship *ship_p = &Ships[obj->instance];
478 
479  if (ship_p->flags2 & SF2_NO_ETS)
480  return;
481 
482  switch ( ship_system ) {
483  case WEAPONS:
484  if ( !ship_has_energy_weapons(ship_p) )
485  return;
486 
487  lose_index = &ship_p->weapon_recharge_index;
488 
489  if ( obj->flags & OF_NO_SHIELDS )
490  gain_index1 = NULL;
491  else
492  gain_index1 = &ship_p->shield_recharge_index;
493 
494  if ( !ship_has_engine_power(ship_p) )
495  gain_index2 = NULL;
496  else
497  gain_index2 = &ship_p->engine_recharge_index;
498 
499  break;
500 
501  case SHIELDS:
502  if ( obj->flags & OF_NO_SHIELDS )
503  return;
504 
505  lose_index = &ship_p->shield_recharge_index;
506 
507  if ( !ship_has_energy_weapons(ship_p) )
508  gain_index1 = NULL;
509  else
510  gain_index1 = &ship_p->weapon_recharge_index;
511 
512  if ( !ship_has_engine_power(ship_p) )
513  gain_index2 = NULL;
514  else
515  gain_index2 = &ship_p->engine_recharge_index;
516 
517  break;
518 
519  case ENGINES:
520  if ( !ship_has_engine_power(ship_p) )
521  return;
522 
523  lose_index = &ship_p->engine_recharge_index;
524 
525  if ( !ship_has_energy_weapons(ship_p) )
526  gain_index1 = NULL;
527  else
528  gain_index1 = &ship_p->weapon_recharge_index;
529 
530  if ( obj->flags & OF_NO_SHIELDS )
531  gain_index2 = NULL;
532  else
533  gain_index2 = &ship_p->shield_recharge_index;
534 
535  break;
536 
537  } // end switch
538 
539  // return if we can't transfer energy
540  if (!gain_index1 && !gain_index2)
541  return;
542 
543  // check how much there is to lose
544  count = MIN(2, *lose_index);
545  if ( count <= 0 ) {
546  if ( obj == Player_obj ) {
548  }
549  return;
550  }
551 
552  *lose_index -= count;
553 
554  // make sure that the gain starts with the system which needs it most
555  if ( gain_index1 && gain_index2 ) {
556  if ( *gain_index1 > *gain_index2 ) {
557  tmp = gain_index1;
558  gain_index1 = gain_index2;
559  gain_index2 = tmp;
560  }
561  }
562 
563  int sanity=0;
564  while(count > 0) {
565  if ( gain_index1 && *gain_index1 < MAX_ENERGY_INDEX ) {
566  *gain_index1 += 1;
567  count--;
568  }
569 
570  if ( count <= 0 )
571  break;
572 
573  if ( gain_index2 && *gain_index2 < MAX_ENERGY_INDEX ) {
574  *gain_index2 += 1;
575  count--;
576  }
577 
578  if ( sanity++ > 10 ) {
579  Int3(); // get Alan
580  break;
581  }
582  }
583 
584  if ( obj == Player_obj )
585  snd_play( &Snds[SND_ENERGY_TRANS], 0.0f );
586 }
587 
588 void transfer_energy_weapon_common(object *objp, float from_field, float to_field, float *from_delta, float *to_delta, float max, float scale)
589 {
590  float delta;
591 
592  delta = from_field * ENERGY_DIVERT_DELTA * scale;
593 
594  if (to_field + *to_delta + delta > max)
595  delta = max - to_field - *to_delta;
596 
597  if ( delta > 0 ) {
598  if ( objp == Player_obj )
599  snd_play( &Snds[SND_ENERGY_TRANS], 0.0f );
600 
601  if (delta > from_field)
602  delta = from_field;
603 
604  *to_delta += delta;
605  *from_delta -= delta;
606  } else
607  if ( objp == Player_obj )
609 }
610 
611 // -------------------------------------------------------------------------------------------------
612 // transfer_energy_to_shields() will transfer ENERGY_DIVERT_DELTA percent of weapon energy
613 // to shield energy.
615 {
616  ship* ship_p = &Ships[obj->instance];
617 
618  if (ship_p->flags & SF_DYING)
619  return;
620 
621  if ( !ship_has_energy_weapons(ship_p) || obj->flags & OF_NO_SHIELDS )
622  {
623  return;
624  }
625 
627 }
628 
629 // -------------------------------------------------------------------------------------------------
630 // transfer_energy_to_weapons() will transfer ENERGY_DIVERT_DELTA percent of shield energy
631 // to weapon energy.
633 {
634  ship* ship_p = &Ships[obj->instance];
635  ship_info* sinfo_p = &Ship_info[ship_p->ship_info_index];
636 
637  if (ship_p->flags & SF_DYING)
638  return;
639 
640  if ( !ship_has_energy_weapons(ship_p) || obj->flags & OF_NO_SHIELDS )
641  {
642  return;
643  }
644 
646 }
647 
651 void zero_one_ets (int *reduce, int *add1, int *add2)
652 {
653  int *tmp;
654  // add to the smallest index 1st
655  if (*add1 > *add2) {
656  tmp = add1;
657  add1 = add2;
658  add2 = tmp;
659  }
660  while (*reduce > ZERO_INDEX) {
661  if (*add1 < ALL_INDEX) {
662  ++*add1;
663  --*reduce;
664  }
665 
666  if (*reduce <= ZERO_INDEX) {
667  break;
668  }
669 
670  if (*add2 < ALL_INDEX) {
671  ++*add2;
672  --*reduce;
673  }
674  }
675 }
676 
682  {
683  int i;
684  int ets_delta = MAX_ENERGY_INDEX - ets_indexes[ENGINES] - ets_indexes[SHIELDS] - ets_indexes[WEAPONS];
685  if ( ets_delta != 0 ) {
686  if ( ets_delta > 0) { // add to lowest indexes
687  while ( ets_delta != 0 ) {
688  int lowest_val = MAX_ENERGY_INDEX;
689  int lowest_idx = 0;
690 
691  for (i = 0; i < num_retail_ets_gauges; ++i) {
692  if (ets_indexes[i] <= lowest_val ) {
693  lowest_val = ets_indexes[i];
694  lowest_idx = i;
695  }
696  }
697  ++ets_indexes[lowest_idx];
698  --ets_delta;
699  }
700  } else { // remove from highest indexes
701  while ( ets_delta != 0 ) {
702  int highest_val = 0;
703  int highest_idx = 0;
704 
705  for (i = 0; i < num_retail_ets_gauges; ++i) {
706  if (ets_indexes[i] >= highest_val ) {
707  highest_val = ets_indexes[i];
708  highest_idx = i;
709  }
710  }
711  --ets_indexes[highest_idx];
712  ++ets_delta;
713  }
714  }
715  }
716  }
717 
722 bool validate_ship_ets_indxes(const int &ship_idx, int (&ets_indexes)[num_retail_ets_gauges])
723 {
724  if (ship_idx < 0) {
725  return false;
726  }
727  if (Ships[ship_idx].objnum < 0) {
728  return false;
729  }
730  ship *ship_p = &Ships[ship_idx];
731 
732  if (ship_p->flags2 & SF2_NO_ETS)
733  return false;
734 
735  // handle ships that are missing parts of the ETS
736  int ship_properties = 0;
737  if (ship_has_energy_weapons(ship_p)) {
738  ship_properties |= HAS_WEAPONS;
739  }
740 
741  if (!(Objects[ship_p->objnum].flags & OF_NO_SHIELDS)) {
742  ship_properties |= HAS_SHIELDS;
743  }
744 
745  if (ship_has_engine_power(ship_p)) {
746  ship_properties |= HAS_ENGINES;
747  }
748 
749  switch ( ship_properties ) {
751  // all present, don't change ets indexes
752  break;
753 
754  case HAS_ENGINES | HAS_SHIELDS:
755  zero_one_ets(&ets_indexes[WEAPONS], &ets_indexes[ENGINES], &ets_indexes[SHIELDS]);
756  break;
757 
758  case HAS_WEAPONS | HAS_SHIELDS:
759  zero_one_ets(&ets_indexes[ENGINES], &ets_indexes[SHIELDS], &ets_indexes[WEAPONS]);
760  break;
761 
762  case HAS_ENGINES | HAS_WEAPONS:
763  zero_one_ets(&ets_indexes[SHIELDS], &ets_indexes[ENGINES], &ets_indexes[WEAPONS]);
764  break;
765 
766  case HAS_ENGINES:
767  case HAS_SHIELDS:
768  case HAS_WEAPONS:
769  // can't change anything if only one is active on this ship
770  return false;
771  break;
772 
773  default:
774  Error(LOCATION, "Encountered a ship (%s) with a broken ETS", ship_p->ship_name);
775  break;
776  }
777  return true;
778 }
779 
782 System_type(0)
783 {
784 }
785 
786 HudGaugeEts::HudGaugeEts(int _gauge_object, int _system_type):
788 System_type(_system_type)
789 {
790 }
791 
793 {
794  ETS_bar_h = _ets_h;
795 }
796 
797 void HudGaugeEts::initLetterOffsets(int _x, int _y)
798 {
799  Letter_offsets[0] = _x;
800  Letter_offsets[1] = _y;
801 }
802 
803 void HudGaugeEts::initTopOffsets(int _x, int _y)
804 {
805  Top_offsets[0] = _x;
806  Top_offsets[1] = _y;
807 }
808 
809 void HudGaugeEts::initBottomOffsets(int _x, int _y)
810 {
811  Bottom_offsets[0] = _x;
812  Bottom_offsets[1] = _y;
813 }
814 
815 void HudGaugeEts::initLetter(char _letter)
816 {
817  Letter = _letter;
818 }
819 
820 void HudGaugeEts::initBitmaps(char *fname)
821 {
823  if ( Ets_bar.first_frame < 0 ) {
824  Warning(LOCATION,"Cannot load hud ani: %s\n", fname);
825  }
826 }
827 
828 void HudGaugeEts::render(float frametime)
829 {
830 }
831 
833 {
835 }
836 
841 {
842  int y_start, y_end, clip_h, w, h, x, y;
843 
844  clip_h = fl2i( (1 - Energy_levels[index]) * ETS_bar_h );
845 
847 
848  if ( index < NUM_ENERGY_LEVELS-1 ) {
849  // some portion of dark needs to be drawn
850 
851  setGaugeColor();
852 
853  // draw the top portion
854  x = position[0] + Top_offsets[0];
855  y = position[1] + Top_offsets[1];
856 
857  renderBitmapEx(Ets_bar.first_frame,x,y,w,clip_h,0,0);
858 
859  // draw the bottom portion
860  x = position[0] + Bottom_offsets[0];
861  y = position[1] + Bottom_offsets[1];
862 
863  y_start = y + (ETS_bar_h - clip_h);
864  y_end = y + ETS_bar_h;
865 
866  renderBitmapEx(Ets_bar.first_frame, x, y_start, w, y_end-y_start, 0, ETS_bar_h-clip_h);
867  }
868 
869  if ( index > 0 ) {
870  if ( maybeFlashSexp() == 1 ) {
872  // hud_set_dim_color();
873  } else {
875  // hud_set_bright_color();
876  }
877  // some portion of recharge needs to be drawn
878 
879  // draw the top portion
880  x = position[0] + Top_offsets[0];
881  y = position[1] + Top_offsets[1];
882 
883  y_start = y + clip_h;
884  y_end = y + ETS_bar_h;
885 
886  renderBitmapEx(Ets_bar.first_frame+1, x, y_start, w, y_end-y_start, 0, clip_h);
887 
888  // draw the bottom portion
889  x = position[0] + Bottom_offsets[0];
890  y = position[1] + Bottom_offsets[1];
891 
892  renderBitmapEx(Ets_bar.first_frame+2, x,y,w,ETS_bar_h-clip_h,0,0);
893  }
894 }
895 
902 {
903 }
904 
908 void HudGaugeEtsRetail::render(float frametime)
909 {
910  int i;
911  int initial_position;
912 
913  ship* ship_p = &Ships[Player_obj->instance];
914 
915  if ( Ets_bar.first_frame < 0 ) {
916  return;
917  }
918 
919  // if at least two gauges are not shown, don't show any
920  i = 0;
921  if (!ship_has_energy_weapons(ship_p)) i++;
922  if (Player_obj->flags & OF_NO_SHIELDS) i++;
923  if (!ship_has_engine_power(ship_p)) i++;
924  if (i >= 2) return;
925 
926  setGaugeColor();
927 
928  // draw the letters for the gauges first, before any clipping occurs
929  // skip letter for any missing gauges (max one, see check above)
930  initial_position = 0;
931  if (ship_has_energy_weapons(ship_p)) {
932  Letter = Letters[0];
933  position[0] = Gauge_positions[initial_position++];
935  }
936  if (!(Player_obj->flags & OF_NO_SHIELDS)) {
937  Letter = Letters[1];
938  position[0] = Gauge_positions[initial_position++];
940  }
941  if (ship_has_engine_power(ship_p)) {
942  Letter = Letters[2];
943  position[0] = Gauge_positions[initial_position++];
945  }
946 
947  // draw gauges, skipping any gauge that is missing
948  initial_position = 0;
949  if (ship_has_energy_weapons(ship_p)) {
950  Letter = Letters[0];
951  position[0] = Gauge_positions[initial_position++];
953  }
954  if (!(Player_obj->flags & OF_NO_SHIELDS)) {
955  Letter = Letters[1];
956  position[0] = Gauge_positions[initial_position++];
958  }
959  if (ship_has_engine_power(ship_p)) {
960  Letter = Letters[2];
961  position[0] = Gauge_positions[initial_position++];
963  }
964 }
965 
970 void HudGaugeEtsRetail::initLetters(char *_letters)
971 {
972  int i;
973  for ( i = 0; i < num_retail_ets_gauges; ++i)
974  Letters[i] = _letters[i];
975 }
976 
980 void HudGaugeEtsRetail::initGaugePositions(int *_gauge_positions)
981 {
982  int i;
983  for ( i = 0; i < num_retail_ets_gauges; ++i)
984  Gauge_positions[i] = _gauge_positions[i];
985 }
986 
989 {
990 }
991 
992 void HudGaugeEtsWeapons::render(float frametime)
993 {
994  int i;
995 
996  ship* ship_p = &Ships[Player_obj->instance];
997 
998  if ( Ets_bar.first_frame < 0 ) {
999  return;
1000  }
1001 
1002  // if at least two gauges are not shown, don't show any
1003  i = 0;
1004  if (!ship_has_energy_weapons(ship_p)) i++;
1005  if (Player_obj->flags & OF_NO_SHIELDS) i++;
1006  if (!ship_has_engine_power(ship_p)) i++;
1007  if (i >= 2) return;
1008 
1009  // no weapon energy, no weapon gauge
1010  if (!ship_has_energy_weapons(ship_p))
1011  {
1012  return;
1013  }
1014 
1015  setGaugeColor();
1016 
1017  // draw the letters for the gauge first, before any clipping occurs
1019 
1020  // draw the gauges for the weapon system
1022 }
1023 
1026 {
1027 }
1028 
1029 void HudGaugeEtsShields::render(float frametime)
1030 {
1031  int i;
1032 
1033  ship* ship_p = &Ships[Player_obj->instance];
1034 
1035  if ( Ets_bar.first_frame < 0 ) {
1036  return;
1037  }
1038 
1039  // if at least two gauges are not shown, don't show any
1040  i = 0;
1041  if (!ship_has_energy_weapons(ship_p)) i++;
1042  if (Player_obj->flags & OF_NO_SHIELDS) i++;
1043  if (!ship_has_engine_power(ship_p)) i++;
1044  if (i >= 2) return;
1045 
1046  // no shields, no shields gauge
1047  if (Player_obj->flags & OF_NO_SHIELDS) {
1048  return;
1049  }
1050 
1051  setGaugeColor();
1052 
1053  // draw the letters for the gauge first, before any clipping occurs
1055 
1056  // draw the gauge for the shield system
1058 }
1059 
1062 {
1063 }
1064 
1065 void HudGaugeEtsEngines::render(float frametime)
1066 {
1067  int i;
1068 
1069  ship* ship_p = &Ships[Player_obj->instance];
1070 
1071  if ( Ets_bar.first_frame < 0 ) {
1072  return;
1073  }
1074 
1075  // if at least two gauges are not shown, don't show any
1076  i = 0;
1077  if (!ship_has_energy_weapons(ship_p)) i++;
1078  if (Player_obj->flags & OF_NO_SHIELDS) i++;
1079  if (!ship_has_engine_power(ship_p)) i++;
1080  if (i >= 2) return;
1081 
1082  // no engines, no engine gauge
1083  if (!ship_has_engine_power(ship_p)) {
1084  return;
1085  }
1086 
1087  setGaugeColor();
1088 
1089  // draw the letters for the gauge first, before any clipping occurs
1091 
1092  // draw the gauge for the engine system
1094 }
#define DEFAULT_CHARGE_INDEX
Definition: hudets.cpp:197
#define ENERGY_DIVERT_DELTA
Definition: hudets.h:19
void initBottomOffsets(int _x, int _y)
Definition: hudets.cpp:809
int timestamp(int delta_ms)
Definition: timer.cpp:226
#define WEAPONS_EMERG_LEVEL_PERCENT
Definition: hudets.cpp:192
int i
Definition: multi_pxo.cpp:466
void renderBitmapEx(int frame, int x, int y, int w, int h, int sx, int sy)
Definition: hud.cpp:818
float ets_get_max_speed(object *objp, float engine_energy)
Definition: hudets.cpp:147
#define MIN(a, b)
Definition: pstypes.h:296
void decrease_recharge_rate(object *obj, SYSTEM_TYPE ship_system)
Definition: hudets.cpp:473
float max_weapon_reserve
Definition: ship.h:1276
#define HUD_C_BRIGHT
Definition: hud.h:162
float max_overclocked_speed
Definition: ship.h:1275
#define INTIAL_WEAPON_RECHARGE_INDEX
Definition: hudets.h:21
int objnum
Definition: ship.h:537
#define INTIAL_SHIELD_RECHARGE_INDEX
Definition: hudets.h:20
void render(float frametime)
Definition: hudets.cpp:908
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
energy transfer success
Definition: gamesnd.h:79
float shield_get_strength(object *objp)
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
GLuint index
Definition: Glext.h:5608
int Weapon_energy_cheat
Definition: hudets.cpp:27
#define VM_WARP_CHASE
Definition: systemvars.h:37
int Fred_running
Definition: fred.cpp:44
void setGaugeColor(int bright_index=-4)
Definition: hud.cpp:445
int ETS_bar_h
Definition: hudets.h:74
float ship_max_shield_strength
Definition: ship.h:596
void increase_recharge_rate(object *obj, SYSTEM_TYPE ship_system)
Definition: hudets.cpp:349
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
int weapon_recharge_index
Definition: ship.h:638
#define VM_EXTERNAL
Definition: systemvars.h:31
hud_frames Ets_bar
Definition: hudets.h:66
int bm_get_info(int handle, int *w, int *h, ubyte *flags, int *nframes, int *fps)
Gets info on the bitmap indexed by handle.
Definition: bmpman.cpp:769
void transfer_energy_to_weapons(object *obj)
Definition: hudets.cpp:632
GLclampf f
Definition: Glext.h:7097
void initLetterOffsets(int _x, int _y)
Definition: hudets.cpp:797
#define OF_NO_SHIELDS
Definition: object.h:110
#define Assertion(expr, msg,...)
Definition: clang.h:41
#define HUD_OBJECT_ETS_SHIELDS
Definition: hudparse.h:130
void set_default_recharge_rates(object *obj)
Definition: hudets.cpp:275
int n_quadrants
Definition: object.h:158
void update_ets(object *objp, float fl_frametime)
Definition: hudets.cpp:63
float weapon_energy
Definition: ship.h:640
uint flags
Definition: ship.h:644
bool validate_ship_ets_indxes(const int &ship_idx, int(&ets_indexes)[num_retail_ets_gauges])
Definition: hudets.cpp:722
#define OF_PLAYER_SHIP
Definition: object.h:109
object * objp
Definition: lua.cpp:3105
GLenum GLenum GLenum GLenum GLenum scale
Definition: Glext.h:8503
#define Int3()
Definition: pstypes.h:292
ship * shipp
Definition: lua.cpp:9162
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads a bitmap sequance so we can draw with it.
Definition: bmpman.cpp:1420
Definition: hud.h:201
#define INTIAL_ENGINE_RECHARGE_INDEX
Definition: hudets.h:22
#define HUD_OBJECT_ETS_ENGINES
Definition: hudparse.h:133
#define HUD_OBJECT_ETS_RETAIL
Definition: hudparse.h:217
#define HAS_SHIELDS
Definition: hudets.h:35
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int instance
Definition: object.h:150
void initGaugePositions(int *_gauge_positions)
Definition: hudets.cpp:980
float ship_get_subsystem_strength(ship *shipp, int type)
Definition: ship.cpp:13446
#define VM_DEAD_VIEW
Definition: systemvars.h:33
void render(float frametime)
Definition: hudets.cpp:1029
virtual void blitGauge(int index)
Definition: hudets.cpp:840
const int num_retail_ets_gauges
Definition: hudets.h:40
int Letter_offsets[2]
Definition: hudets.h:70
energy transfer fail
Definition: gamesnd.h:80
ai_profile_t * ai_profile
Definition: missionparse.h:168
int num_frames
Definition: hud.h:34
float target_shields_delta
Definition: ship.h:656
void zero_one_ets(int *reduce, int *add1, int *add2)
Definition: hudets.cpp:651
#define w(p)
Definition: modelsinc.h:68
float current_max_speed
Definition: ship.h:641
void ai_manage_ets(object *obj)
Definition: hudets.cpp:200
int snd_play(game_snd *gs, float pan, float vol_scale, int priority, bool is_voice_msg)
Definition: sound.cpp:517
int engine_recharge_index
Definition: ship.h:639
#define fl_abs(fl)
Definition: floating.h:31
void initTopOffsets(int _x, int _y)
Definition: hudets.cpp:803
char Letter
Definition: hudets.h:69
int Gauge_positions[num_retail_ets_gauges]
Definition: hudets.h:114
int ship_has_energy_weapons(ship *shipp)
Definition: ship.cpp:17611
Definition: ship.h:534
int Top_offsets[2]
Definition: hudets.h:71
#define delta
Definition: fvi.cpp:418
virtual void render(float frametime)
Definition: hudets.cpp:828
#define NORMAL_TOLERANCE_PERCENT
Definition: hudets.cpp:198
void render(float frametime)
Definition: hudets.cpp:992
void initBitmaps(char *fname)
Definition: hudets.cpp:820
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
#define MAX_ENERGY_INDEX
Definition: hudets.h:25
void ets_init_ship(object *obj)
Definition: hudets.cpp:34
void shield_add_strength(object *objp, float delta)
SYSTEM_TYPE
Definition: hudets.h:45
float weapon_energy_scale[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:105
float Energy_levels[NUM_ENERGY_LEVELS]
Definition: hudets.cpp:26
#define NOX(s)
Definition: pstypes.h:473
float target_weapon_energy_delta
Definition: ship.h:657
#define OBJ_SHIP
Definition: object.h:32
#define NUM_ENERGY_LEVELS
Definition: hudets.h:24
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
void render(float frametime)
Definition: hudets.cpp:1065
float max_speed
Definition: ship.h:1230
void sanity_check_ets_inputs(int(&ets_indexes)[num_retail_ets_gauges])
Definition: hudets.cpp:681
int maybeFlashSexp()
Definition: hud.cpp:617
int first_frame
Definition: hud.h:33
void initLetters(char *_letters)
Definition: hudets.cpp:970
#define ALL_INDEX
Definition: hudets.h:32
#define SUBSYSTEM_ENGINE
Definition: model.h:53
#define WEAPONS_MIN_LEVEL_PERCENT
Definition: hudets.cpp:184
Definition: hudets.h:45
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
int next_manage_ets
Definition: ship.h:642
float get_shield_pct(object *objp)
Definition: object.cpp:308
void initLetter(char _letter)
Definition: hudets.cpp:815
float power_output
Definition: ship.h:1274
void transfer_energy_to_shields(object *obj)
Definition: hudets.cpp:614
#define SF2_NO_ETS
Definition: ship.h:503
int position[2]
Definition: hud.h:204
#define SHIP_MIN_ENGINES_FOR_FULL_SPEED
Definition: subsysdamage.h:18
void bm_page_in_aabitmap(int bitmapnum, int nframes)
Marks a texture as being used for this level, and is anti-aliased.
Definition: bmpman.cpp:2354
#define fl2i(fl)
Definition: floating.h:33
#define HAS_WEAPONS
Definition: hudets.h:36
float max_weapon_regen_per_second
Definition: ship.h:1278
char Letters[num_retail_ets_gauges]
Definition: hudets.h:113
#define fl_sqrt(fl)
Definition: floating.h:29
int ship_info_index
Definition: ship.h:539
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
#define VM_PADLOCK_ANY
Definition: systemvars.h:46
#define timestamp_elapsed(stamp)
Definition: timer.h:102
SCP_vector< float > shield_quadrant
Definition: object.h:159
int Game_skill_level
Definition: fredstubs.cpp:170
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
float shield_energy_scale[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:106
void renderPrintf(int x, int y, const char *format,...)
Definition: hud.cpp:724
GLint GLsizei count
Definition: Gl.h:1491
#define AI_MODIFY_ETS_INTERVAL
Definition: hudets.h:27
object * Player_obj
Definition: object.cpp:56
#define ONE_HALF_INDEX
Definition: hudets.h:31
#define SHIELDS_MIN_LEVEL_PERCENT
Definition: hudets.cpp:183
uint flags2
Definition: ship.h:645
#define SF_DYING
Definition: ship.h:447
#define VM_OTHER_SHIP
Definition: systemvars.h:35
#define ZERO_INDEX
Definition: hudets.h:29
int ship_has_engine_power(ship *shipp)
Definition: ship.cpp:17618
false
Definition: lua.cpp:6789
uint flags
Definition: object.h:151
void pageIn()
Definition: hudets.cpp:832
mission The_mission
void initBarHeight(int _ets_bar_h)
Definition: hudets.cpp:792
char type
Definition: object.h:146
#define MIN_ENGINE_RECHARGE_INDEX
Definition: hudets.cpp:195
#define HUD_C_DIM
Definition: hud.h:163
int shield_recharge_index
Definition: ship.h:637
#define HUD_OBJECT_ETS_WEAPONS
Definition: hudparse.h:127
#define HAS_ENGINES
Definition: hudets.h:34
void transfer_energy_weapon_common(object *objp, float from_field, float to_field, float *from_delta, float *to_delta, float max, float scale)
Definition: hudets.cpp:588
char ship_name[NAME_LENGTH]
Definition: ship.h:604
Definition: hudets.h:45
int Bottom_offsets[2]
Definition: hudets.h:72
#define HUD_ETS_GAUGE
Definition: hudgauges.h:31
Definition: hudets.h:45
GLint y
Definition: Gl.h:1505
float max_shield_regen_per_second
Definition: ship.h:1277
#define SHIELDS_EMERG_LEVEL_PERCENT
Definition: hudets.cpp:191