Add an "On Ship Damage" script hook (#7894)

* Add an "On Ship Damage" script hook

Runs after resolved damage has been applied to a ship (lethal hits run before
the destruction callback). Hook variables: Target, Source, Attacker,
WeaponClass, WeaponSubtype, SourceKind (PROJECTILE, BEAM, SHOCKWAVE, COLLISION,
OTHER), DamageType, ShieldDamage, HullDamage, Quadrant, Ballistic, BeamWeapon
and LethalHit. Conditions can filter on the target ship. Nothing is computed
unless a script has registered the hook.

* Move the On Ship Damage hook call out of a lambda

ship_do_damage() now calls a file-level static function, ship_run_damage_hook(), that takes the values it needs as arguments instead of capturing the function state. Hook behaviour is unchanged.

* Report subsystem damage in the On Ship Damage hook

Adds SubsystemDamage, the total subsystem strength a damage application removed, so a hit absorbed by subsystems no longer looks like a small hull hit. The hook description now says it only runs where damage is applied, which excludes multiplayer clients.

* Address On Ship Damage review comments

- Remove WeaponClass, WeaponSubtype, Ballistic and BeamWeapon from the
  hook. Scripts read these from Source when it is a weapon.
- Add a "Weapon class" condition for the On Ship Damage hook. It matches
  only when the damage source is a weapon of that class; a weapon name
  that does not exist never matches.
- SubsystemDamage is now a table keyed by subsystem handle that lists only
  the subsystems that lost strength. The total is removed.
- Rename PROJECTILE to NON_BEAM_WEAPON.
- Classify SourceKind by damage source: COLLISION for ship, debris and
  asteroid collisions; EXPLOSION for ship-death and docked-ship blasts and
  asteroid blasts; WASH for engine wash; SELF for kills where the ship
  damages itself; OTHER for other ship-sourced damage.
- Reword the hook description.

* Key On Ship Damage SubsystemDamage by canonical name

Lua tables cannot use subsystem handles as keys in a usable way, so key
the SubsystemDamage table by each subsystem's CanonicalName instead.

* Tag ship-vs-prop damage as a collision and use in_bounds

The ship-vs-prop collision call didn't pass DamageSource::Collision, so
the On Ship Damage hook reported those hits as OTHER. Every other
collision path was already tagged.

Also use SCP_vector::in_bounds() for the Weapon_info and Damage_types
index checks in ship_run_damage_hook().
This commit is contained in:
Boutros Tawaifi authored and GitHub committed 2026-11-06 18:41:29 -05:00
1 parent 4dc0ca7878
commit 49464c56f6
10 files changed
+188 -18

No files matched your search

+1 -1
View File
@@ -1693,7 +1693,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
if ( weapon_area_calc_damage(ship_objp, &asteroid_objp->pos, asip->inner_rad, asip->outer_rad, asip->blast, asip->damage, &blast, &damage, asip->outer_rad) == -1 )
continue;
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx);
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx, DamageSource::Explosion);
weapon_area_apply_blast(nullptr, ship_objp, &asteroid_objp->pos, blast, false);
} // end for
}
+4 -4
View File
@@ -158,12 +158,12 @@ int collide_debris_ship( obj_pair * pair )
quadrant_num = -1;
}
if (apply_ship_damage) {
ship_apply_local_damage(debris_hit_info.heavy, debris_hit_info.light, &hitpos, ship_damage, Debris[debris_objp->instance].damage_type_idx, quadrant_num, CREATE_SPARKS, debris_hit_info.heavy_submodel_num);
ship_apply_local_damage(debris_hit_info.heavy, debris_hit_info.light, &hitpos, ship_damage, Debris[debris_objp->instance].damage_type_idx, quadrant_num, CREATE_SPARKS, debris_hit_info.heavy_submodel_num, nullptr, 1.f, nullptr, DamageSource::Collision);
}
} else {
// don't draw sparks using sphere hit position
if (apply_ship_damage) {
ship_apply_local_damage(debris_hit_info.light, debris_hit_info.heavy, &hitpos, ship_damage, Debris[debris_objp->instance].damage_type_idx, MISS_SHIELDS, NO_SPARKS);
ship_apply_local_damage(debris_hit_info.light, debris_hit_info.heavy, &hitpos, ship_damage, Debris[debris_objp->instance].damage_type_idx, MISS_SHIELDS, NO_SPARKS, -1, nullptr, 1.f, nullptr, DamageSource::Collision);
}
}
@@ -348,10 +348,10 @@ int collide_asteroid_ship( obj_pair * pair )
(ship_objp->flags[Object::Object_Flags::No_shields]) || !ship_is_shield_up(ship_objp, quadrant_num) ) {
quadrant_num = -1;
}
ship_apply_local_damage(asteroid_hit_info.heavy, asteroid_hit_info.light, &hitpos, ship_damage, ast_damage_type, quadrant_num, CREATE_SPARKS, asteroid_hit_info.heavy_submodel_num);
ship_apply_local_damage(asteroid_hit_info.heavy, asteroid_hit_info.light, &hitpos, ship_damage, ast_damage_type, quadrant_num, CREATE_SPARKS, asteroid_hit_info.heavy_submodel_num, nullptr, 1.f, nullptr, DamageSource::Collision);
} else {
// don't draw sparks (using sphere hitpos)
ship_apply_local_damage(asteroid_hit_info.light, asteroid_hit_info.heavy, &hitpos, ship_damage, ast_damage_type, MISS_SHIELDS, NO_SPARKS);
ship_apply_local_damage(asteroid_hit_info.light, asteroid_hit_info.heavy, &hitpos, ship_damage, ast_damage_type, MISS_SHIELDS, NO_SPARKS, -1, nullptr, 1.f, nullptr, DamageSource::Collision);
}
// maybe print Collision on HUD
+3 -3
View File
@@ -1392,14 +1392,14 @@ void collide_ship_ship_process(obj_pair * pair, const std::any& collision_data)
float damage_heavy = (100.0f * damage / heavy_obj->phys_info.mass);
ship_apply_local_damage(ship_ship_hit_info.heavy, ship_ship_hit_info.light, &world_hit_pos, damage_heavy, light_shipp->collision_damage_type_idx,
quadrant_num, CREATE_SPARKS, ship_ship_hit_info.heavy_submodel_num, &ship_ship_hit_info.collision_normal);
quadrant_num, CREATE_SPARKS, ship_ship_hit_info.heavy_submodel_num, &ship_ship_hit_info.collision_normal, 1.f, nullptr, DamageSource::Collision);
hud_shield_quadrant_hit(ship_ship_hit_info.heavy, quadrant_num);
// don't draw sparks (using sphere hitpos)
float damage_light = (100.0f * damage / light_obj->phys_info.mass);
ship_apply_local_damage(ship_ship_hit_info.light, ship_ship_hit_info.heavy, &world_hit_pos, damage_light, heavy_shipp->collision_damage_type_idx,
MISS_SHIELDS, NO_SPARKS, -1, &ship_ship_hit_info.collision_normal);
MISS_SHIELDS, NO_SPARKS, -1, &ship_ship_hit_info.collision_normal, 1.f, nullptr, DamageSource::Collision);
hud_shield_quadrant_hit(ship_ship_hit_info.light, -1);
@@ -1811,7 +1811,7 @@ int collide_prop_ship(obj_pair* pair)
// don't draw sparks (using sphere hitpos)
damage = (100.0f * damage / ship_objp->phys_info.mass);
ship_apply_local_damage(ship_objp, prop_objp, &world_hit_pos, damage, -1, MISS_SHIELDS, CREATE_SPARKS, -1, &prop_ship_hit_info.collision_normal);
ship_apply_local_damage(ship_objp, prop_objp, &world_hit_pos, damage, -1, MISS_SHIELDS, CREATE_SPARKS, -1, &prop_ship_hit_info.collision_normal, 1.f, nullptr, DamageSource::Collision);
hud_shield_quadrant_hit(ship_objp, -1);
}
+16
View File
@@ -559,6 +559,22 @@ const std::shared_ptr<Hook<>> OnCameraSetUpHook = Hook<>::Factory("On Camera Set
{"Camera", "camera", "The camera about to be used for rendering."},
});
const std::shared_ptr<Hook<ShipDamageConditions>> OnShipDamage = Hook<ShipDamageConditions>::Factory(
"On Ship Damage", "Called after damage is applied to a ship; lethal hits run before the On Ship Death Started hook. "
"Only called where damage is applied: in single player and on a multiplayer server, not on multiplayer clients.",
{
{"Target", "ship", "The ship that took the damage."},
{"Source", "object", "The weapon, beam, shockwave, or other object that caused the damage. Could be nil."},
{"Attacker", "object", "The source ship or parent object, if available."},
{"SourceKind", "string", "NON_BEAM_WEAPON, BEAM, SHOCKWAVE, COLLISION, EXPLOSION, WASH, SELF (the ship damaged itself, such as a self-destruct), or OTHER."},
{"DamageType", "string", "The damage type, or UNKNOWN if none is defined."},
{"ShieldDamage", "number", "Actual total shield strength removed by this damage application."},
{"HullDamage", "number", "Actual hull strength removed, clamped to the target's remaining hull."},
{"SubsystemDamage", "table", "Maps each subsystem's CanonicalName to the strength it lost in this damage application. Only subsystems that lost strength are listed, in no particular order."},
{"Quadrant", "number", "Shield quadrant hit, or -1 when no single quadrant applies."},
{"LethalHit", "boolean", "Whether this hit reduced positive hull strength to zero or below."},
});
// ========== FRED HOOKS ==========
const std::shared_ptr<Hook<>> FredOnMissionLoad = Hook<>::Factory("FRED On Mission Load",
+2
View File
@@ -100,6 +100,8 @@ extern const std::shared_ptr<Hook<>> OnStateAboutToEndHook;
extern const std::shared_ptr<OverridableHook<>> OnStateEndHook;
extern const std::shared_ptr<Hook<>> OnCameraSetUpHook;
extern const std::shared_ptr<Hook<ShipDamageConditions>> OnShipDamage;
// FRED Hooks
extern const std::shared_ptr<Hook<>> FredOnMissionLoad;
extern const std::shared_ptr<Hook<>> FredOnMissionSpecsSave;
+12
View File
@@ -232,6 +232,18 @@ HOOK_CONDITIONS_START(ShipDeathConditions)
HOOK_CONDITION_SHIPP(ShipDeathConditions, "", "that died.", dying_shipp);
HOOK_CONDITIONS_END
// Damage with no weapon has weapon_info_index -1, and so does a weapon name that does not exist, so a named weapon
// class must also be a real weapon to match.
static bool conditionDamageWeaponClassMatches(int damage_weapon_index, const int& weapon_index)
{
return damage_weapon_index >= 0 && damage_weapon_index == weapon_index;
}
HOOK_CONDITIONS_START(ShipDamageConditions)
HOOK_CONDITION_SHIPP(ShipDamageConditions, "Target ", "that took damage.", target_shipp);
HOOK_CONDITION(ShipDamageConditions, "Weapon class", "Specifies the class of the weapon that caused the damage. For a shockwave, this is the weapon that created it.", weapon_info_index, conditionParseWeaponClass, conditionDamageWeaponClassMatches);
HOOK_CONDITIONS_END
HOOK_CONDITIONS_START(SubsystemDeathConditions)
HOOK_CONDITION_SHIPP(SubsystemDeathConditions, "", "whose subsystem got destroyed.", affected_shipp);
HOOK_CONDITIONS_END
+6
View File
@@ -63,6 +63,12 @@ struct ShipDeathConditions {
const ship* dying_shipp;
};
struct ShipDamageConditions {
HOOK_DEFINE_CONDITIONS;
const ship* target_shipp;
int weapon_info_index; // the weapon that caused the damage, or -1 if none
};
struct SubsystemDeathConditions {
HOOK_DEFINE_CONDITIONS;
const ship* affected_shipp;
+2 -2
View File
@@ -9330,7 +9330,7 @@ static void ship_blow_up_area_apply_blast( object *exp_objp)
switch ( objp->type ) {
case OBJ_SHIP:
ship_apply_global_damage( objp, exp_objp, &exp_objp->pos, damage, sip->shockwave.damage_type_idx);
ship_apply_global_damage( objp, exp_objp, &exp_objp->pos, damage, sip->shockwave.damage_type_idx, DamageSource::Explosion);
ship_apply_whack( &force, &exp_objp->pos, objp );
break;
case OBJ_ASTEROID:
@@ -9387,7 +9387,7 @@ static void do_dying_undock_physics(object *dying_objp, ship *dying_shipp)
float docked_mass = dying_objp->phys_info.mass + docked_objp->phys_info.mass;
// damage this docked object
ship_apply_global_damage(docked_objp, dying_objp, &dying_objp->pos, damage, -1);
ship_apply_global_damage(docked_objp, dying_objp, &dying_objp->pos, damage, -1, DamageSource::Explosion);
// do physics
vm_vec_sub(&impulse_norm, &docked_objp->pos, &dying_objp->pos);
+132 -6
View File
@@ -2393,6 +2393,112 @@ static int maybe_shockwave_damage_adjust(const object *ship_objp, const object *
return 1;
}
// The shield, hull and per-subsystem strength of a ship, recorded before a ship_do_damage() call. Only filled in while
// the On Ship Damage hook is active.
struct ship_damage_snapshot {
float hull_strength = 0.0f;
float shield_strength = 0.0f;
SCP_vector<std::pair<ship_subsys *, float>> subsystem_hits;
};
static void ship_take_damage_snapshot(object *ship_objp, ship_damage_snapshot &snapshot)
{
ship *shipp = &Ships[ship_objp->instance];
snapshot.hull_strength = ship_objp->hull_strength;
snapshot.shield_strength = shield_get_strength(ship_objp);
snapshot.subsystem_hits.clear();
for (ship_subsys *subsys = GET_FIRST(&shipp->subsys_list); subsys != END_OF_LIST(&shipp->subsys_list); subsys = GET_NEXT(subsys)) {
snapshot.subsystem_hits.emplace_back(subsys, subsys->current_hits);
}
}
// Runs the On Ship Damage hook for one ship_do_damage() call, reporting what the ship lost since the snapshot.
// Does nothing if the ship lost none of its shield, hull or subsystem strength.
static void ship_run_damage_hook(object *ship_objp, object *other_obj, int weapon_info_index, int damage_type_idx, int quadrant, DamageSource source, bool wash_damage, const ship_damage_snapshot &before)
{
const float shield_damage = MAX(0.0f, before.shield_strength - shield_get_strength(ship_objp));
const float hull_damage = MAX(0.0f, MAX(0.0f, before.hull_strength) - MAX(0.0f, ship_objp->hull_strength));
bool subsystem_hit = false;
for (const auto &entry : before.subsystem_hits) {
if (entry.first->current_hits < entry.second) {
subsystem_hit = true;
break;
}
}
if (shield_damage <= 0.0f && hull_damage <= 0.0f && !subsystem_hit) {
return;
}
const bool lethal_hit = before.hull_strength > 0.0f && ship_objp->hull_strength <= 0.0f;
// the subsystems that lost strength, keyed by canonical subsystem name
luacpp::LuaTable subsystem_losses = luacpp::LuaTable::create(Script_system.GetLuaSession());
for (const auto &entry : before.subsystem_hits) {
const float lost = entry.second - entry.first->current_hits;
if (lost > 0.0f) {
subsystem_losses.addValue(ship_subsys_get_canonical_name(entry.first), lost);
}
}
const weapon_info *wip = Weapon_info.in_bounds(weapon_info_index) ? &Weapon_info[weapon_info_index] : nullptr;
if (!Damage_types.in_bounds(damage_type_idx) && wip != nullptr) {
damage_type_idx = wip->damage_type_idx;
}
const char *damage_type = Damage_types.in_bounds(damage_type_idx) ? Damage_types[damage_type_idx].name : "UNKNOWN";
const char *source_kind = "OTHER";
if (source == DamageSource::Collision) {
source_kind = "COLLISION";
} else if (source == DamageSource::Explosion) {
source_kind = "EXPLOSION";
} else if (wash_damage) {
source_kind = "WASH";
} else if (other_obj == ship_objp) {
source_kind = "SELF";
} else if (other_obj != nullptr) {
switch (other_obj->type) {
case OBJ_WEAPON:
source_kind = "NON_BEAM_WEAPON";
break;
case OBJ_BEAM:
source_kind = "BEAM";
break;
case OBJ_SHOCKWAVE:
source_kind = "SHOCKWAVE";
break;
default:
break;
}
}
object *attacker_objp = nullptr;
if (other_obj != nullptr) {
if (other_obj->type == OBJ_BEAM) {
int parent_objnum = beam_get_parent(other_obj);
if (parent_objnum >= 0) {
attacker_objp = &Objects[parent_objnum];
}
} else if (other_obj->type == OBJ_SHIP) {
attacker_objp = other_obj;
} else if (other_obj->parent >= 0 && other_obj->parent < MAX_OBJECTS && Objects[other_obj->parent].signature == other_obj->parent_sig) {
attacker_objp = &Objects[other_obj->parent];
}
}
scripting::hooks::OnShipDamage->run(scripting::hooks::ShipDamageConditions{ &Ships[ship_objp->instance], weapon_info_index },
scripting::hook_param_list(
scripting::hook_param("Target", 'o', ship_objp),
scripting::hook_param("Source", 'o', other_obj, other_obj != nullptr),
scripting::hook_param("Attacker", 'o', attacker_objp, attacker_objp != nullptr),
scripting::hook_param("SourceKind", 's', source_kind),
scripting::hook_param("DamageType", 's', damage_type),
scripting::hook_param("ShieldDamage", 'f', shield_damage),
scripting::hook_param("HullDamage", 'f', hull_damage),
scripting::hook_param("SubsystemDamage", 't', subsystem_losses),
scripting::hook_param("Quadrant", 'i', quadrant),
scripting::hook_param("LethalHit", 'b', lethal_hit)));
}
// ------------------------------------------------------------------------
// ship_do_damage()
//
@@ -2411,7 +2517,7 @@ static int maybe_shockwave_damage_adjust(const object *ship_objp, const object *
// Goober5000 - sanity checked this whole function in the case that other_obj is NULL, which
// will happen with the explosion-effect sexp
void ai_update_lethality(const object *ship_objp, const object *weapon_obj, float damage);
static void ship_do_damage(object *ship_objp, object *other_obj, const vec3d *hitpos, float damage, int quadrant, int submodel_num, int damage_type_idx = -1, bool wash_damage = false, float hit_dot = 1.f, const vec3d* hit_normal = nullptr, const vec3d* local_hitpos = nullptr)
static void ship_do_damage(object *ship_objp, object *other_obj, const vec3d *hitpos, float damage, int quadrant, int submodel_num, int damage_type_idx = -1, bool wash_damage = false, float hit_dot = 1.f, const vec3d* hit_normal = nullptr, const vec3d* local_hitpos = nullptr, DamageSource source = DamageSource::Inferred)
{
// mprintf(("doing damage\n"));
@@ -2426,6 +2532,13 @@ static void ship_do_damage(object *ship_objp, object *other_obj, const vec3d *hi
Assertion(ship_objp->instance >= 0 && ship_objp->type == OBJ_SHIP, "invalid ship target in ship_do_damage");
shipp = &Ships[ship_objp->instance];
// snapshot for the On Ship Damage hook, which reports what the ship actually lost
const bool damage_hook_active = scripting::hooks::OnShipDamage->isActive();
bool damage_hook_ran = false;
ship_damage_snapshot damage_before;
if (damage_hook_active) {
ship_take_damage_snapshot(ship_objp, damage_before);
}
// maybe adjust damage done by shockwave for BIG|HUGE
maybe_shockwave_damage_adjust(ship_objp, other_obj, &damage);
@@ -2697,10 +2810,19 @@ static void ship_do_damage(object *ship_objp, object *other_obj, const vec3d *hi
// diag_printf2("Simulated Hull for Ship %s hit, dropping from %.32f to %d.\n", shipp->ship_name, (int) ( ship_objp->sim_hull_strength * 100 ), (int) ( ( ship_objp->sim_hull_strength - damage ) * 100 ) );
ship_objp->sim_hull_strength -= damage;
ship_objp->sim_hull_strength = MAX(0.0f, ship_objp->sim_hull_strength);
if (damage_hook_active) {
ship_run_damage_hook(ship_objp, other_obj, weapon_info_index, damage_type_idx, quadrant, source, wash_damage, damage_before);
}
return;
}
}
ship_objp->hull_strength -= damage;
// a lethal hit runs the hook now, before the ship's death processing below
if (damage_hook_active && ship_objp->hull_strength <= 0.0f) {
ship_run_damage_hook(ship_objp, other_obj, weapon_info_index, damage_type_idx, quadrant, source, wash_damage, damage_before);
damage_hook_ran = true;
}
}
// let damage gauge know that player ship just took damage
@@ -2800,6 +2922,10 @@ static void ship_do_damage(object *ship_objp, object *other_obj, const vec3d *hi
}
}
if (damage_hook_active && !damage_hook_ran) {
ship_run_damage_hook(ship_objp, other_obj, weapon_info_index, damage_type_idx, quadrant, source, wash_damage, damage_before);
}
if (!global_damage) {
maybe_play_conditional_impacts(impact_data, other_obj, ship_objp, true, submodel_num, hitpos, local_hitpos, hit_normal);
}
@@ -3006,7 +3132,7 @@ void ship_apply_tag(ship *shipp, int tag_level, float tag_time, object *target,
// hitpos is in world coordinates.
// if quadrant is not -1, then that part of the shield takes damage properly.
// (it might be possible to make `other_obj` const, but that would set off another const-cascade)
void ship_apply_local_damage(object *ship_objp, object *other_obj, const vec3d *hitpos, float damage, int damage_type_idx, int quadrant, bool create_spark, int submodel_num, const vec3d *hit_normal, float hit_dot, const vec3d* local_hitpos)
void ship_apply_local_damage(object *ship_objp, object *other_obj, const vec3d *hitpos, float damage, int damage_type_idx, int quadrant, bool create_spark, int submodel_num, const vec3d *hit_normal, float hit_dot, const vec3d* local_hitpos, DamageSource source)
{
Assert(ship_objp); // Goober5000
Assert(other_obj); // Goober5000
@@ -3103,7 +3229,7 @@ void ship_apply_local_damage(object *ship_objp, object *other_obj, const vec3d *
ship_do_healing(ship_objp, other_obj, hitpos, damage, quadrant, submodel_num, -1, hit_normal, local_hitpos);
create_sparks = false;
} else {
ship_do_damage(ship_objp, other_obj, hitpos, damage, quadrant, submodel_num, damage_type_idx, false, hit_dot, hit_normal, local_hitpos);
ship_do_damage(ship_objp, other_obj, hitpos, damage, quadrant, submodel_num, damage_type_idx, false, hit_dot, hit_normal, local_hitpos, source);
}
// DA 5/5/98: move ship_hit_create_sparks() after do_damage() since number of sparks depends on hull strength
@@ -3150,7 +3276,7 @@ void ship_apply_local_damage(object *ship_objp, object *other_obj, const vec3d *
// You can pass force_center==NULL if you the damage doesn't come from anywhere,
// like for debug keys to damage an object or something. It will
// assume damage is non-directional and will apply it correctly.
void ship_apply_global_damage(object *ship_objp, object *other_obj, const vec3d *force_center, float damage, int damage_type_idx)
void ship_apply_global_damage(object *ship_objp, object *other_obj, const vec3d *force_center, float damage, int damage_type_idx, DamageSource source)
{
Assert(ship_objp); // Goober5000 (but not other_obj in case of sexp)
@@ -3187,7 +3313,7 @@ void ship_apply_global_damage(object *ship_objp, object *other_obj, const vec3d
ship_do_healing(ship_objp, other_obj, &world_hitpos, damage, -1, damage_type_idx);
else
// Do damage on local point
ship_do_damage(ship_objp, other_obj, &world_hitpos, damage, shield_quad, -1 , damage_type_idx);
ship_do_damage(ship_objp, other_obj, &world_hitpos, damage, shield_quad, -1 , damage_type_idx, false, 1.f, nullptr, nullptr, source);
} else {
// Since an force_center wasn't specified, this is probably just a debug key
// to kill an object. So pick a shield quadrant and a point on the
@@ -3196,7 +3322,7 @@ void ship_apply_global_damage(object *ship_objp, object *other_obj, const vec3d
int n_quadrants = static_cast<int>(ship_objp->shield_quadrant.size());
for (int i=0; i<n_quadrants; i++){
ship_do_damage(ship_objp, other_obj, &world_hitpos, damage/n_quadrants, i, -1, damage_type_idx);
ship_do_damage(ship_objp, other_obj, &world_hitpos, damage/n_quadrants, i, -1, damage_type_idx, false, 1.f, nullptr, nullptr, source);
}
}
+10 -2
View File
@@ -54,12 +54,20 @@ std::pair<std::optional<ConditionData>, float> do_subobj_hit_stuff(object *ship_
// (it might be possible to make `target` const, but that would set off another const-cascade)
extern void ship_apply_tag(ship *ship_p, int tag_level, float tag_time, object *target, const vec3d *start, int ssm_index, int ssm_team);
// Where a ship damage application came from, for the On Ship Damage hook. Inferred uses the damaging object type and
// the engine wash flag. Collision and Explosion are for callers whose damaging object cannot tell them apart.
enum class DamageSource {
Inferred,
Collision,
Explosion,
};
// This gets called to apply damage when something hits a particular point on a ship.
// This assumes that whoever called this knows if the shield got hit or not.
// hitpos is in world coordinates.
// if quadrant is not -1, then that part of the shield takes damage properly.
// (it might be possible to make `other_obj` const, but that would set off another const-cascade)
void ship_apply_local_damage(object *ship_obj, object *other_obj, const vec3d *hitpos, float damage, int damage_type_idx, int quadrant, bool create_spark=true, int submodel_num=-1, const vec3d *hit_normal=nullptr, float hit_dot = 1.f, const vec3d* local_hitpos = nullptr);
void ship_apply_local_damage(object *ship_obj, object *other_obj, const vec3d *hitpos, float damage, int damage_type_idx, int quadrant, bool create_spark=true, int submodel_num=-1, const vec3d *hit_normal=nullptr, float hit_dot = 1.f, const vec3d* local_hitpos = nullptr, DamageSource source = DamageSource::Inferred);
// This gets called to apply damage when a damaging force hits a ship, but at no
// point in particular. Like from a shockwave. This routine will see if the
@@ -67,7 +75,7 @@ void ship_apply_local_damage(object *ship_obj, object *other_obj, const vec3d *h
// You can pass force_center==NULL if you the damage doesn't come from anywhere,
// like for debug keys to damage an object or something. It will
// assume damage is non-directional and will apply it correctly.
void ship_apply_global_damage(object *ship_obj, object *other_obj, const vec3d *force_center, float damage, int damage_type_idx);
void ship_apply_global_damage(object *ship_obj, object *other_obj, const vec3d *force_center, float damage, int damage_type_idx, DamageSource source = DamageSource::Inferred);
// like above, but does not apply damage to shields
void ship_apply_wash_damage(object *ship_obj, object *other_obj, float damage);