Skip to content

Commit

Permalink
Merge pull request #1 from BMagnu/modular_weapon_curves
Browse files Browse the repository at this point in the history
Modular Curve Framework
  • Loading branch information
Kestrellius authored Oct 29, 2024
2 parents 307df1c + 79ed374 commit 4a4f482
Show file tree
Hide file tree
Showing 13 changed files with 648 additions and 100 deletions.
19 changes: 19 additions & 0 deletions code/globalincs/type_traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <optional>
#include <tl/optional.hpp>

template <typename T> struct is_optional : std::false_type {};
template<typename T> struct is_optional<std::optional<T>> : std::true_type {};
template<> struct is_optional<std::nullopt_t> : std::true_type {};
template<typename T> struct is_optional<tl::optional<T>> : std::true_type {};
template<> struct is_optional<tl::nullopt_t> : std::true_type {};

template<typename T>
inline constexpr bool is_optional_v = is_optional<T>::value;

template <typename T> struct is_tuple : std::false_type {};
template <typename... U> struct is_tuple<std::tuple <U...>> : std::true_type {};

template<typename T>
inline constexpr bool is_tuple_v = is_tuple<T>::value;
7 changes: 3 additions & 4 deletions code/object/collideshipweapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,16 @@ static void ship_weapon_do_hit_stuff(object *pship_obj, object *weapon_obj, vec3
damage = wip->damage;
}

if (wip->damage_incidence_max != 1.0f || wip->damage_incidence_min != 1.0f) {
float dot = -vm_vec_dot(&weapon_obj->orient.vec.fvec, &worldNormal);
float dot = -vm_vec_dot(&weapon_obj->orient.vec.fvec, &worldNormal);

if (wip->damage_incidence_max != 1.0f || wip->damage_incidence_min != 1.0f) {
if (dot < 0.0f)
dot = 0.0f;

damage *= wip->damage_incidence_min + ((wip->damage_incidence_max - wip->damage_incidence_min) * dot);
}

if (wip->damage_curve_idx >= 0)
damage *= Curves[wip->damage_curve_idx].GetValue(f2fl(Missiontime - wp->creation_time) / wip->lifetime);
damage *= wip->hit_modular_curves.get_output(weapon_info::HitModularCurveOutputs::DAMAGE_MULT, std::forward_as_tuple(*wp, *pship_obj, dot), &wp->modular_curves_instance);

// if this is friendly fire, we check for the friendly fire cap values
if (wp->team == shipp->team) {
Expand Down
11 changes: 6 additions & 5 deletions code/object/collideweaponweapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ int collide_weapon_weapon( obj_pair * pair )
if (A->parent_sig == B->parent_sig)
return 1;

float dot = vm_vec_dot(&A->orient.vec.fvec, &B->orient.vec.fvec);

// Only shoot down teammate's missile if not traveling in nearly same direction.
if (Weapons[A->instance].team == Weapons[B->instance].team)
if (vm_vec_dot(&A->orient.vec.fvec, &B->orient.vec.fvec) > 0.7f)
if (dot > 0.7f)
return 1;

// Ignore collisions involving a bomb if the bomb is not yet armed.
Expand Down Expand Up @@ -120,15 +122,14 @@ int collide_weapon_weapon( obj_pair * pair )
// damage calculation should not be done on clients, the server will tell the client version of the bomb when to die
if(!a_override && !b_override && !MULTIPLAYER_CLIENT)
{
float dot_curve = -dot;
float aDamage = wipA->damage;
if (wipA->damage_curve_idx >= 0)
aDamage *= Curves[wipA->damage_curve_idx].GetValue(A_time_alive / wipA->lifetime);
aDamage *= wipA->hit_modular_curves.get_output(weapon_info::HitModularCurveOutputs::DAMAGE_MULT, std::forward_as_tuple(*wpA, *B, dot_curve), &wpA->modular_curves_instance);
if (wipB->armor_type_idx >= 0)
aDamage = Armor_types[wipB->armor_type_idx].GetDamage(aDamage, wipA->damage_type_idx, 1.0f, false);

float bDamage = wipB->damage;
if (wipB->damage_curve_idx >= 0)
bDamage *= Curves[wipB->damage_curve_idx].GetValue(B_time_alive / wipB->lifetime);
bDamage *= wipB->hit_modular_curves.get_output(weapon_info::HitModularCurveOutputs::DAMAGE_MULT, std::forward_as_tuple(*wpB, *A, dot_curve), &wpB->modular_curves_instance);
if (wipA->armor_type_idx >= 0)
bDamage = Armor_types[wipA->armor_type_idx].GetDamage(bDamage, wipB->damage_type_idx, 1.0f, false);

Expand Down
77 changes: 5 additions & 72 deletions code/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1258,78 +1258,11 @@ void obj_move_all_post(object *objp, float frametime)
auto lp = lighting_profiles::current();
hdr_color light_color;

float intensity_mult = 1.f;
float radius_mult = 1.f;
float r_mult = 1.f;
float g_mult = 1.f;
float b_mult = 1.f;

for (uint c = 0; c < wi->lifetime_curves.size(); c++) {
WeaponLifetimeCurve* mod_curve = &wi->lifetime_curves[c];
if (mod_curve->curve_idx < 0) {
Warning(LOCATION, "Curve does not exist!");
continue;
}

Curve curve = Curves[mod_curve->curve_idx];
float input = 1.0f;
float output = 1.0f;
switch (mod_curve->input) {
case WeaponLifetimeCurveInput::LIFETIME:
input = f2fl(Missiontime - wp->creation_time) / wi->lifetime;
break;
case WeaponLifetimeCurveInput::AGE:
input = f2fl(Missiontime - wp->creation_time);
break;
case WeaponLifetimeCurveInput::BASE_VELOCITY:
input = wp->weapon_max_vel;
break;
case WeaponLifetimeCurveInput::HITPOINTS:
if (wi->weapon_hitpoints > 0.f) {
input = objp->hull_strength/i2fl(wi->weapon_hitpoints);
} else {
input = 1.f;
}
break;
case WeaponLifetimeCurveInput::PARENT_RADIUS:
if (objp->parent >= 0) {
input = Objects[objp->parent].radius;
}
break;
default:
continue;
}
float scaling_factor = wp->weapon_curve_data[c].first;
float translation = wp->weapon_curve_data[c].second;
input = (input / scaling_factor) + translation;
if (mod_curve->wraparound) {
float final_x = curve.keyframes.back().pos.x;
input = std::fmod(input, final_x);
}
output = curve.GetValue(input);
if (output < 0.f) {
output = 0.f;
}
switch (mod_curve->output) {
case WeaponLifetimeCurveOutput::LIGHT_INTENSITY_MULT:
intensity_mult *= output;
break;
case WeaponLifetimeCurveOutput::LIGHT_RADIUS_MULT:
radius_mult *= output;
break;
case WeaponLifetimeCurveOutput::LIGHT_R_MULT:
r_mult *= output;
break;
case WeaponLifetimeCurveOutput::LIGHT_G_MULT:
g_mult *= output;
break;
case WeaponLifetimeCurveOutput::LIGHT_B_MULT:
b_mult *= output;
break;
default:
continue;
}
}
float intensity_mult = wi->modular_curves.get_output(weapon_info::ModularCurveOutputs::LIGHT_INTENSITY_MULT, *wp, &wp->modular_curves_instance);
float radius_mult = wi->modular_curves.get_output(weapon_info::ModularCurveOutputs::LIGHT_RADIUS_MULT, *wp, &wp->modular_curves_instance);
float r_mult = wi->modular_curves.get_output(weapon_info::ModularCurveOutputs::LIGHT_R_MULT, *wp, &wp->modular_curves_instance);
float g_mult = wi->modular_curves.get_output(weapon_info::ModularCurveOutputs::LIGHT_G_MULT, *wp, &wp->modular_curves_instance);
float b_mult = wi->modular_curves.get_output(weapon_info::ModularCurveOutputs::LIGHT_B_MULT, *wp, &wp->modular_curves_instance);

// If there is no specific color set in the table, laser render weapons have a dynamic color.
if (!wi->light_color_set && wi->render_type == WRT_LASER) {
Expand Down
11 changes: 1 addition & 10 deletions code/parse/encrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,14 +472,5 @@ uint32_t hash_fnv1a(const SCP_string& string) {
}

uint32_t hash_fnv1a(const void* data, size_t length) {
const uint32_t fnv1a_magic_prime = 16777619;
uint32_t hash = 2166136261;

auto bytes = reinterpret_cast<const uint8_t*>(data);

for (size_t cnt = 0; cnt < length; cnt++) {
hash = (hash ^ bytes[cnt]) * fnv1a_magic_prime;
}

return hash;
return hash_fnv1a(reinterpret_cast<const uint8_t*>(data), length);
}
18 changes: 18 additions & 0 deletions code/parse/encrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,26 @@ void encrypt(char *text, int text_len, char *scrambled_text, int *scrambled_len,
void unencrypt(char *scrambled_text, int scrambled_len, char *text, int *text_len);

//A fast platform/std-implementation stable hashing algorithm. Implements the FNV-1a hash algorithm
constexpr uint32_t hash_fnv1a(const uint8_t* bytes, size_t length) {
const uint32_t fnv1a_magic_prime = 16777619;
uint32_t hash = 2166136261;

for (size_t cnt = 0; cnt < length; cnt++) {
hash = (hash ^ bytes[cnt]) * fnv1a_magic_prime;
}

return hash;
}

uint32_t hash_fnv1a(const SCP_string& string);
uint32_t hash_fnv1a(const void* data, size_t length);
constexpr uint32_t hash_fnv1a(uint32_t value) {
uint8_t bytes[4] = {static_cast<uint8_t>((value) & 0xff),
static_cast<uint8_t>((value >> 8) & 0xff),
static_cast<uint8_t>((value >> 16) & 0xff),
static_cast<uint8_t>((value >> 24) & 0xff)};
return hash_fnv1a(bytes, sizeof(uint32_t));
}

#endif

2 changes: 2 additions & 0 deletions code/source_groups.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ add_file_folder("GlobalIncs"
globalincs/systemvars.cpp
globalincs/systemvars.h
globalincs/toolchain.h
globalincs/type_traits.h
globalincs/undosys.cpp
globalincs/undosys.h
globalincs/utility.h
Expand Down Expand Up @@ -1668,6 +1669,7 @@ add_file_folder("Utils"
utils/HeapAllocator.h
utils/id.h
utils/join_string.h
utils/modular_curves.h
utils/Random.cpp
utils/Random.h
utils/RandomRange.h
Expand Down
20 changes: 19 additions & 1 deletion code/utils/RandomRange.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ class RandomRange {
{
return m_maxValue;
}

void seed(typename GeneratorType::result_type new_seed) const {
if (m_constant)
return;

m_generator.seed(new_seed);
}
};

/**
Expand Down Expand Up @@ -528,7 +535,15 @@ class ParsedRandomRange {
return range.max();
}
};


struct seed_helper {
unsigned int new_seed;

template <typename T>
inline void operator()(T& range) {
range.seed(new_seed);
}
};

public:
template<typename T>
Expand All @@ -548,6 +563,9 @@ class ParsedRandomRange {
inline result_type max() const {
return static_cast<result_type>(mpark::visit(max_helper{}, m_random_range));
}
inline void seed(unsigned int new_seed) const {
mpark::visit(seed_helper{new_seed}, m_random_range);
}
static ParsedRandomRange parseRandomRange(float min = std::numeric_limits<float>::lowest()/2.1f, float max = std::numeric_limits<float>::max()/2.1f) {
switch (optional_string_either("NORMAL", "CURVE")) {
case 0: {
Expand Down
Loading

0 comments on commit 4a4f482

Please sign in to comment.