Skip to content

Commit 3c939f5

Browse files
authored
Particle Curves with access to host object & ship properties (#7047)
* Add parent / host input curves * reorder some includes to allow particles access to ship.h * Allow modular_curves to deal with functions returning optionals * Add convenience function to return an optional from an objp and an instance type * Add a bunch of particle curve inputs * Fix internal linkage warning * Add hitpoint and shield fraction (albeit limited to ships)
1 parent db4f9e4 commit 3c939f5

File tree

11 files changed

+114
-23
lines changed

11 files changed

+114
-23
lines changed

code/asteroid/asteroid.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "object/objcollide.h"
3333
#include "object/object.h"
3434
#include "parse/parselo.h"
35+
#include "particle/ParticleEffect.h"
3536
#include "scripting/global_hooks.h"
3637
#include "particle/hosts/EffectHostVector.h"
3738
#include "render/3d.h"

code/hud/hudets.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class object;
2121
#define INTIAL_ENGINE_RECHARGE_INDEX 4 // default engine charge rate (index in Energy_levels[])
2222

2323
#define NUM_ENERGY_LEVELS 13
24-
#define MAX_ENERGY_INDEX (NUM_ENERGY_LEVELS - 1)
24+
inline constexpr int MAX_ENERGY_INDEX = (NUM_ENERGY_LEVELS - 1);
2525

2626
#define AI_MODIFY_ETS_INTERVAL 500 // time between ets modifications for ai's (in milliseconds)
2727

code/model/model.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#include "model/model_flags.h"
2424
#include "object/object.h"
2525
#include "ship/ship_flags.h"
26-
#include "particle/ParticleEffect.h"
26+
#include "particle/particle.h"
2727

2828
class object;
2929
class ship_info;

code/object/object_instance.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#pragma once
2+
3+
#include <optional>
4+
5+
#include "asteroid/asteroid.h"
6+
#include "debris/debris.h"
7+
#include "fireball/fireballs.h"
8+
#include "object/object.h"
9+
#include "ship/ship.h"
10+
#include "weapon/weapon.h"
11+
12+
template<int type>
13+
inline auto obj_get_instance_maybe(const object* objp) {
14+
if constexpr(type == OBJ_SHIP)
15+
return objp->type == type ? std::optional(&Ships[objp->instance]) : std::nullopt;
16+
else if constexpr(type == OBJ_WEAPON)
17+
return objp->type == type ? std::optional(&Weapons[objp->instance]) : std::nullopt;
18+
else if constexpr(type == OBJ_FIREBALL)
19+
return objp->type == type ? std::optional(&Fireballs[objp->instance]) : std::nullopt;
20+
else if constexpr(type == OBJ_DEBRIS)
21+
return objp->type == type ? std::optional(&Debris[objp->instance]) : std::nullopt;
22+
else if constexpr(type == OBJ_WING)
23+
return objp->type == type ? std::optional(&Wings[objp->instance]) : std::nullopt;
24+
else if constexpr(type == OBJ_ASTEROID)
25+
return objp->type == type ? std::optional(&Asteroids[objp->instance]) : std::nullopt;
26+
else if constexpr(type == OBJ_BEAM)
27+
return objp->type == type ? std::optional(&Beams[objp->instance]) : std::nullopt;
28+
else
29+
return std::nullopt;
30+
}

code/particle/ParticleEffect.h

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
#include "utils/modular_curves.h"
1212
#include "graphics/2d.h"
1313

14+
#include "object/objectshield.h"
15+
#include "ship/ship.h"
16+
#include "object/object_instance.h"
17+
#include "hud/hudets.h"
18+
1419
#include <optional>
1520

1621
class EffectHost;
@@ -261,7 +266,6 @@ class ParticleEffect {
261266
std::pair {"Trigger Velocity", modular_curves_submember_input<&ParticleSource::m_triggerVelocity>{}},
262267
std::pair {"Host Radius", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getHostRadius>{}},
263268
std::pair {"Host Velocity", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getVelocityMagnitude>{}},
264-
//TODO Long term, this should have access to a lot of interesting host properties, especially also those that change during gameplay like current hitpoints
265269
std::pair {"Effects Running", modular_curves_math_input<
266270
modular_curves_submember_input<&ParticleSource::m_effect_is_running, &decltype(ParticleSource::m_effect_is_running)::count>,
267271
modular_curves_submember_input<&ParticleSource::getEffect, &SCP_vector<ParticleEffect>::size>,
@@ -274,7 +278,25 @@ class ParticleEffect {
274278
std::pair {"Nebula Usage Score", modular_curves_math_input<
275279
modular_curves_global_submember_input<get_particle_count>,
276280
modular_curves_global_submember_input<Detail, &detail_levels::nebula_detail>,
277-
ModularCurvesMathOperators::division>{}})
281+
ModularCurvesMathOperators::division>{}},
282+
std::pair {"Host Object Hitpoints", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &object::hull_strength>{}},
283+
std::pair {"Host Ship Hitpoints Fraction", modular_curves_math_input<
284+
modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &object::hull_strength>,
285+
modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::ship_max_hull_strength>,
286+
ModularCurvesMathOperators::division>{}},
287+
std::pair {"Host Object Shield", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &shield_get_strength>{}},
288+
std::pair {"Host Ship Shield Fraction", modular_curves_math_input<
289+
modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &shield_get_strength>,
290+
modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::ship_max_shield_strength>,
291+
ModularCurvesMathOperators::division>{}},
292+
std::pair {"Host Ship AB Fuel Left", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::afterburner_fuel>{}},
293+
std::pair {"Host Ship Countermeasures Left", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::cmeasure_count>{}},
294+
std::pair {"Host Ship Weapon Energy Left", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::weapon_energy>{}},
295+
std::pair {"Host Ship ETS Engines", modular_curves_math_input<modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::engine_recharge_index>, modular_curves_global_submember_input<MAX_ENERGY_INDEX>, ModularCurvesMathOperators::division>{}},
296+
std::pair {"Host Ship ETS Shields", modular_curves_math_input<modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::shield_recharge_index>, modular_curves_global_submember_input<MAX_ENERGY_INDEX>, ModularCurvesMathOperators::division>{}},
297+
std::pair {"Host Ship ETS Weapons", modular_curves_math_input<modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::weapon_recharge_index>, modular_curves_global_submember_input<MAX_ENERGY_INDEX>, ModularCurvesMathOperators::division>{}},
298+
std::pair {"Host Ship EMP Intensity", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::emp_intensity>{}},
299+
std::pair {"Host Ship Time Until Explosion", modular_curves_submember_input<&ParticleSource::m_host, &EffectHost::getParentObjAndSig, 0, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::final_death_time, static_cast<int (*)(int)>(&timestamp_until)>{}})
278300
.derive_modular_curves_input_only_subset<size_t>( //Effect Number
279301
std::pair {"Spawntime Left", modular_curves_functional_full_input<&ParticleSource::getEffectRemainingTime>{}},
280302
std::pair {"Time Running", modular_curves_functional_full_input<&ParticleSource::getEffectRunningTime>{}})
@@ -293,7 +315,7 @@ class ParticleEffect {
293315
std::pair {"Radius Mult", ParticleLifetimeCurvesOutput::RADIUS_MULT}, // Modern Naming Alias
294316
std::pair {"Velocity Mult", ParticleLifetimeCurvesOutput::VELOCITY_MULT}, // Modern Naming Alias
295317
std::pair {"Length Mult", ParticleLifetimeCurvesOutput::LENGTH_MULT},
296-
std::pair {"Anim State Mult", ParticleLifetimeCurvesOutput::ANIM_STATE},
318+
std::pair {"Anim State", ParticleLifetimeCurvesOutput::ANIM_STATE},
297319
std::pair {"Light Radius Mult", ParticleLifetimeCurvesOutput::LIGHT_RADIUS_MULT},
298320
std::pair {"Light Source Radius Mult", ParticleLifetimeCurvesOutput::LIGHT_SOURCE_RADIUS_MULT},
299321
std::pair {"Light Intensity Mult", ParticleLifetimeCurvesOutput::LIGHT_INTENSITY_MULT},
@@ -311,7 +333,25 @@ class ParticleEffect {
311333
modular_curves_submember_input<&particle::max_life>,
312334
ModularCurvesMathOperators::division>{}},
313335
std::pair {"Radius", modular_curves_submember_input<&particle::radius>{}},
314-
std::pair {"Velocity", modular_curves_submember_input<&particle::velocity, &vm_vec_mag_quick>{}})
336+
std::pair {"Velocity", modular_curves_submember_input<&particle::velocity, &vm_vec_mag_quick>{}},
337+
std::pair {"Parent Object Hitpoints", modular_curves_submember_input<&particle::attached_objnum, &Objects, &object::hull_strength>{}},
338+
std::pair {"Parent Ship Hitpoints Fraction", modular_curves_math_input<
339+
modular_curves_submember_input<&particle::attached_objnum, &Objects, &object::hull_strength>,
340+
modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::ship_max_hull_strength>,
341+
ModularCurvesMathOperators::division>{}},
342+
std::pair {"Parent Object Shield", modular_curves_submember_input<&particle::attached_objnum, &Objects, &shield_get_strength>{}},
343+
std::pair {"Parent Ship Shield Fraction", modular_curves_math_input<
344+
modular_curves_submember_input<&particle::attached_objnum, &Objects, &shield_get_strength>,
345+
modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::ship_max_shield_strength>,
346+
ModularCurvesMathOperators::division>{}},
347+
std::pair {"Parent Ship AB Fuel Left", modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::afterburner_fuel>{}},
348+
std::pair {"Parent Ship Countermeasures Left", modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::cmeasure_count>{}},
349+
std::pair {"Parent Ship Weapon Energy Left", modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::weapon_energy>{}},
350+
std::pair {"Parent Ship ETS Engines", modular_curves_math_input<modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::engine_recharge_index>, modular_curves_global_submember_input<MAX_ENERGY_INDEX>, ModularCurvesMathOperators::division>{}},
351+
std::pair {"Parent Ship ETS Shields", modular_curves_math_input<modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::shield_recharge_index>, modular_curves_global_submember_input<MAX_ENERGY_INDEX>, ModularCurvesMathOperators::division>{}},
352+
std::pair {"Parent Ship ETS Weapons", modular_curves_math_input<modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::weapon_recharge_index>, modular_curves_global_submember_input<MAX_ENERGY_INDEX>, ModularCurvesMathOperators::division>{}},
353+
std::pair {"Parent Ship EMP Intensity", modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::emp_intensity>{}},
354+
std::pair {"Parent Ship Time Until Explosion", modular_curves_submember_input<&particle::attached_objnum, &Objects, &obj_get_instance_maybe<OBJ_SHIP>, &ship::final_death_time, static_cast<int (*)(int)>(&timestamp_until)>{}})
315355
.derive_modular_curves_input_only_subset<float>(
316356
std::pair {"Post-Curves Velocity", modular_curves_self_input{}}
317357
);

code/particle/ParticleManager.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#pragma once
44

55
#include "globalincs/pstypes.h"
6-
#include "particle/ParticleEffect.h"
76
#include "utils/id.h"
87

98
#include "particle/hosts/EffectHostBeam.h"

code/particle/ParticleSource.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include <math/bitarray.h>
22
#include "freespace.h"
33
#include "particle/ParticleSource.h"
4+
#include "particle/ParticleEffect.h"
45
#include "weapon/weapon.h"
5-
#include "ship/ship.h"
66

77
namespace particle {
88

code/particle/particle.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "bmpman/bmpman.h"
1313
#include "particle/particle.h"
1414
#include "particle/ParticleManager.h"
15+
#include "particle/ParticleEffect.h"
1516
#include "debugconsole/console.h"
1617
#include "globalincs/systemvars.h"
1718
#include "graphics/2d.h"

code/source_groups.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,7 @@ add_file_folder("Object"
10341034
object/waypoint.cpp
10351035
object/waypoint.h
10361036
object/object_flags.h
1037+
object/object_instance.h
10371038
)
10381039

10391040
# Observer files

code/utils/modular_curves.h

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,34 @@ struct modular_curves_submember_input {
8383
const auto& current_access = grab_part<input_type, grabber>(input.get());
8484
//If the current grabber isn't guaranteed to succeed, check for completion first
8585
if constexpr (is_optional_v<std::decay_t<decltype(current_access)>>) {
86-
using lower_return_type = decltype(grab_internal<std::decay_t<decltype((*current_access).get())>, other_grabbers...>(*current_access));
87-
using return_type = typename std::conditional_t<is_optional_v<std::decay_t<lower_return_type>>, lower_return_type, std::optional<lower_return_type>>;
88-
//If we're already nullopt (i.e. this array access failed) return early
89-
if (current_access.has_value()) {
90-
//Now, it's possible that lower acceses _also_ produce optionals. In this case, we need to forward the lower result, not re-wrap it.
91-
if constexpr (is_optional_v<std::decay_t<lower_return_type>>) {
92-
return grab_internal<std::decay_t<decltype((*current_access).get())>, other_grabbers...>(*current_access);
93-
}
94-
else{
95-
return return_type(grab_internal<std::decay_t<decltype((*current_access).get())>, other_grabbers...>(*current_access));
96-
}
86+
if constexpr (is_instance_of_v<std::decay_t<decltype(*current_access)>, std::reference_wrapper>) {
87+
using lower_return_type = decltype(grab_internal<std::decay_t<decltype((*current_access).get())>, other_grabbers...>(*current_access));
88+
using return_type = typename std::conditional_t<is_optional_v<std::decay_t<lower_return_type>>, lower_return_type, std::optional<lower_return_type>>;
89+
//If we're already nullopt (i.e. this array access failed) return early
90+
if (current_access.has_value()) {
91+
//Now, it's possible that lower acceses _also_ produce optionals. In this case, we need to forward the lower result, not re-wrap it.
92+
if constexpr (is_optional_v<std::decay_t<lower_return_type>>) {
93+
return grab_internal<std::decay_t<decltype((*current_access).get())>, other_grabbers...>(*current_access);
94+
} else {
95+
return return_type(grab_internal<std::decay_t<decltype((*current_access).get())>, other_grabbers...>(*current_access));
96+
}
97+
} else
98+
return return_type(std::nullopt);
99+
}
100+
else {
101+
using lower_return_type = decltype(grab_internal<std::decay_t<decltype(*current_access)>, other_grabbers...>(*current_access));
102+
using return_type = typename std::conditional_t<is_optional_v<std::decay_t<lower_return_type>>, lower_return_type, std::optional<lower_return_type>>;
103+
//If we're already nullopt (i.e. this array access failed) return early
104+
if (current_access.has_value()) {
105+
//Now, it's possible that lower acceses _also_ produce optionals. In this case, we need to forward the lower result, not re-wrap it.
106+
if constexpr (is_optional_v<std::decay_t<lower_return_type>>) {
107+
return grab_internal<std::decay_t<decltype(*current_access)>, other_grabbers...>(*current_access);
108+
} else {
109+
return return_type(grab_internal<std::decay_t<decltype(*current_access)>, other_grabbers...>(*current_access));
110+
}
111+
} else
112+
return return_type(std::nullopt);
97113
}
98-
else
99-
return return_type(std::nullopt);
100114
}
101115
//Otherwise just send it on to the next grabber
102116
else if constexpr (is_instance_of_v<std::decay_t<decltype(current_access)>, std::reference_wrapper>) {
@@ -136,8 +150,12 @@ struct modular_curves_submember_input {
136150
static inline float grab(const input_type& input) {
137151
const auto& result = grab_internal<std::decay_t<decltype(grab_from_tuple<tuple_idx, input_type>(input).get())>, grabbers...>(grab_from_tuple<tuple_idx, input_type>(input));
138152
if constexpr (is_optional_v<typename std::decay_t<decltype(result)>>) {
139-
if (result.has_value())
140-
return number_to_float(result->get());
153+
if (result.has_value()) {
154+
if constexpr (is_instance_of_v<std::decay_t<decltype(*result)>, std::reference_wrapper>)
155+
return number_to_float(result->get());
156+
else
157+
return number_to_float(*result);
158+
}
141159
else
142160
return 1.0f;
143161
}

0 commit comments

Comments
 (0)