2525#include " weapon/weapon.h"
2626#include " globalincs/alphacolors.h"
2727
28- 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+ float Energy_levels[NUM_ENERGY_LEVELS ] = {0 .0f , 1 . 0f / 12 , 2 . 0f / 12 , 3 . 0f / 12 , 4 . 0f / 12 , 5 . 0f / 12 , 6 . 0f / 12 , 7 . 0f / 12 , 8 . 0f / 12 , 9 . 0f / 12 , 10 . 0f / 12 , 11 . 0f / 12 , 1 .0f };
2929bool Weapon_energy_cheat = false ;
3030
3131// -------------------------------------------------------------------------------------------------
@@ -54,6 +54,53 @@ void ets_init_ship(object* obj)
5454 set_default_recharge_rates (obj);
5555}
5656
57+ int ets_properties (object* objp)
58+ {
59+ int properties = 0 ;
60+ ship* ship_p = &Ships[objp->instance ];
61+ ship_info* ship_info_p = &Ship_info[ship_p->ship_info_index ];
62+
63+ if (ship_has_energy_weapons (ship_p))
64+ properties |= HAS_WEAPONS ;
65+
66+ if (!(objp->flags [Object::Object_Flags::No_shields]) && !ship_info_p->flags [Ship::Info_Flags::Intrinsic_no_shields])
67+ properties |= HAS_SHIELDS ;
68+
69+ if (ship_has_engine_power (ship_p))
70+ properties |= HAS_ENGINES ;
71+
72+ return properties;
73+ }
74+
75+ // returns the energy that should be dedicated towards a single ETS system
76+ // in retail, this is always 1.0
77+ float ets_power_factor (object *objp, bool include_power_output)
78+ {
79+ auto shipp = &Ships[objp->instance ];
80+ int properties = ets_properties (objp);
81+
82+ if (The_mission.ai_profile ->flags [AI ::Profile_Flags::ETS_energy_same_regardless_of_system_presence] && (properties != (HAS_WEAPONS | HAS_SHIELDS | HAS_ENGINES )))
83+ {
84+ // in retail, the effect of having a missing system (e.g. an unshielded ship) is as if all that energy were redirected to other systems, so take the inverse of that
85+ constexpr float missing_single_factor = 2 .0f /3 ;
86+ constexpr float missing_double_factor = 1 .0f /3 ;
87+
88+ float missing_factor = (properties == HAS_WEAPONS || properties == HAS_SHIELDS || properties == HAS_ENGINES ) ? missing_double_factor : missing_single_factor;
89+
90+ if (The_mission.ai_profile ->flags [AI ::Profile_Flags::ETS_uses_power_output] && include_power_output)
91+ return Ship_info[shipp->ship_info_index ].power_output * missing_factor;
92+ else
93+ return missing_factor;
94+ }
95+ else
96+ {
97+ if (The_mission.ai_profile ->flags [AI ::Profile_Flags::ETS_uses_power_output] && include_power_output)
98+ return Ship_info[shipp->ship_info_index ].power_output ;
99+ else
100+ return 1 .0f ;
101+ }
102+ }
103+
57104// -------------------------------------------------------------------------------------------------
58105// update_ets() is called once per frame for every OBJ_SHIP in the game.
59106// The amount of energy to send to the weapons and shields is calculated.
@@ -83,14 +130,15 @@ void update_ets(object* objp, float fl_frametime)
83130 return ;
84131 }
85132
133+ // See? Volition did, at one point, intend for power output to affect ETS!
86134 // new_energy = fl_frametime * sinfo_p->power_output;
87135
88136 // update weapon energy
89137 max_new_weapon_energy = fl_frametime * ship_p->max_weapon_regen_per_second * max_g;
90138 if ( objp->flags [Object::Object_Flags::Player_ship] ) {
91- ship_p->weapon_energy += Energy_levels[ship_p->weapon_recharge_index ] * max_new_weapon_energy * The_mission.ai_profile ->weapon_energy_scale [Game_skill_level];
139+ ship_p->weapon_energy += ets_power_factor (objp) * Energy_levels[ship_p->weapon_recharge_index ] * max_new_weapon_energy * The_mission.ai_profile ->weapon_energy_scale [Game_skill_level];
92140 } else {
93- ship_p->weapon_energy += Energy_levels[ship_p->weapon_recharge_index ] * max_new_weapon_energy;
141+ ship_p->weapon_energy += ets_power_factor (objp) * Energy_levels[ship_p->weapon_recharge_index ] * max_new_weapon_energy;
94142 }
95143
96144 if ( ship_p->weapon_energy > sinfo_p->max_weapon_reserve ){
@@ -100,9 +148,9 @@ void update_ets(object* objp, float fl_frametime)
100148 float shield_delta;
101149 max_new_shield_energy = fl_frametime * ship_p->max_shield_regen_per_second * shield_get_max_strength (ship_p, true ); // recharge rate is unaffected by $Max Shield Recharge
102150 if ( objp->flags [Object::Object_Flags::Player_ship] ) {
103- shield_delta = Energy_levels[ship_p->shield_recharge_index ] * max_new_shield_energy * The_mission.ai_profile ->shield_energy_scale [Game_skill_level];
151+ shield_delta = ets_power_factor (objp) * Energy_levels[ship_p->shield_recharge_index ] * max_new_shield_energy * The_mission.ai_profile ->shield_energy_scale [Game_skill_level];
104152 } else {
105- shield_delta = Energy_levels[ship_p->shield_recharge_index ] * max_new_shield_energy;
153+ shield_delta = ets_power_factor (objp) * Energy_levels[ship_p->shield_recharge_index ] * max_new_shield_energy;
106154 }
107155
108156 if (Missiontime - Ai_info[ship_p->ai_index ].last_hit_time < fl2f (sinfo_p->shield_regen_hit_delay ))
@@ -170,16 +218,32 @@ void update_ets(object* objp, float fl_frametime)
170218
171219float ets_get_max_speed (object* objp, float engine_energy)
172220{
221+ // NOTE: ets_power_factor() doesn't need to be called in this function, because all the factors cancel out. But
222+ // the system presence does need to be checked since it affects the recharge indexes.
223+
173224 Assertion (objp != NULL , " Invalid object pointer passed!" );
174225 Assertion (objp->type == OBJ_SHIP , " Object needs to be a ship object!" );
175226 Assertion (engine_energy >= 0 .0f && engine_energy <= 1 .0f , " Invalid float passed, needs to be in [0, 1], was %f!" , engine_energy);
176227
177228 ship* shipp = &Ships[objp->instance ];
178-
179229 ship_info* sip = &Ship_info[shipp->ship_info_index ];
180230
231+ float initial_engine_recharge_energy_level;
232+ if (The_mission.ai_profile ->flags [AI ::Profile_Flags::ETS_energy_same_regardless_of_system_presence])
233+ {
234+ int properties = ets_properties (objp);
235+ if (properties == (HAS_WEAPONS | HAS_SHIELDS | HAS_ENGINES ))
236+ initial_engine_recharge_energy_level = Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX ];
237+ else if (properties == HAS_WEAPONS || properties == HAS_SHIELDS || properties == HAS_ENGINES )
238+ initial_engine_recharge_energy_level = Energy_levels[ALL_INDEX ];
239+ else
240+ initial_engine_recharge_energy_level = Energy_levels[ONE_HALF_INDEX ];
241+ }
242+ else
243+ initial_engine_recharge_energy_level = Energy_levels[INTIAL_ENGINE_RECHARGE_INDEX ];
244+
181245 // check for a shortcuts first before doing linear interpolation
182- if ( engine_energy == Energy_levels[ INTIAL_ENGINE_RECHARGE_INDEX ] ){
246+ if ( engine_energy == initial_engine_recharge_energy_level ){
183247 return sip->max_speed ;
184248 } else if ( engine_energy == 0 .0f ){
185249 return 0 .5f * sip->max_speed ;
@@ -188,11 +252,11 @@ float ets_get_max_speed(object* objp, float engine_energy)
188252 } else {
189253 // do a linear interpolation to find the current max speed, using points (0,1/2 default_max_speed) (.333,default_max_speed)
190254 // x = x1 + (y-y1) * (x2-x1) / (y2-y1);
191- if ( engine_energy < Energy_levels[ INTIAL_ENGINE_RECHARGE_INDEX ] ){
192- return 0 .5f *sip->max_speed + (engine_energy * (0 .5f *sip->max_speed ) ) / Energy_levels[ INTIAL_ENGINE_RECHARGE_INDEX ] ;
255+ if ( engine_energy < initial_engine_recharge_energy_level ){
256+ return 0 .5f *sip->max_speed + (engine_energy * (0 .5f *sip->max_speed ) ) / initial_engine_recharge_energy_level ;
193257 } else {
194258 // do a linear interpolation to find the current max speed, using points (.333,default_max_speed) (1,max_overclock_speed)
195- return sip->max_speed + (engine_energy - Energy_levels[ INTIAL_ENGINE_RECHARGE_INDEX ] ) * (sip->max_overclocked_speed - sip->max_speed ) / (1 .0f - Energy_levels[ INTIAL_ENGINE_RECHARGE_INDEX ] );
259+ return sip->max_speed + (engine_energy - initial_engine_recharge_energy_level ) * (sip->max_overclocked_speed - sip->max_speed ) / (1 .0f - initial_engine_recharge_energy_level );
196260 }
197261 }
198262}
@@ -203,6 +267,7 @@ void ets_update_max_speed(object* ship_objp)
203267 Assertion (ship_objp->type == OBJ_SHIP , " Object needs to be a ship object!" );
204268
205269 // calculate the top speed of the ship based on the energy flow to engines
270+ // (note: this doesn't need the power factor; see comments in ets_get_max_speed())
206271 float x = Energy_levels[Ships[ship_objp->instance ].engine_recharge_index ];
207272 ship_objp->phys_info .max_vel .xyz .z = ets_get_max_speed (ship_objp, x);
208273}
@@ -335,23 +400,13 @@ void set_recharge_rates(object* obj, int shields, int weapons, int engines) {
335400// engines to their default levels
336401void set_default_recharge_rates (object* obj)
337402{
338- int ship_properties;
339-
340403 ship* ship_p = &Ships[obj->instance ];
341404 ship_info* ship_info_p = &Ship_info[ship_p->ship_info_index ];
342405
343406 if ( ship_info_p->power_output == 0 )
344407 return ;
345408
346- ship_properties = 0 ;
347- if (ship_has_energy_weapons (ship_p))
348- ship_properties |= HAS_WEAPONS ;
349-
350- if (!(obj->flags [Object::Object_Flags::No_shields]) && !ship_info_p->flags [Ship::Info_Flags::Intrinsic_no_shields])
351- ship_properties |= HAS_SHIELDS ;
352-
353- if (ship_has_engine_power (ship_p))
354- ship_properties |= HAS_ENGINES ;
409+ int ship_properties = ets_properties (obj);
355410
356411 // the default charge rate depends on what systems are on each ship
357412 switch ( ship_properties ) {
0 commit comments