Files
fs2open.github.com/code/ship/shiphit.h
T
Goober5000andClaude Fable 5.1 112ca2fc4b handle submodel repair/destruction consistently
When a destroyed subsystem was repaired, its submodels were only restored if the repair was done through a SEXP.  A subsystem repaired by a support ship, by automatic repair, by a script, or through the debug console regained its hitpoints but not its submodels, so a ship could have a working turret with no model.  Any -destroyed form also remained visible.

All of these now call restore_subsystem_submodels, which brings back the subsystem's submodels and hides the -destroyed submodel linked to a special-point subsystem.  The -destroyed form of an ordinary submodel is hidden when the submodels are next replicated.  The SEXP code uses the same function, with no change in its behavior.

Destruction outside do_subobj_destroyed_stuff now goes through a new blow_off_subsystem_submodels function, which do_subobj_destroyed_stuff also uses.  It blows off both of the subsystem's submodels and shows any linked -destroyed submodel, unless the subsystem has "no disappear".  This handles the cases where a subsystem appears destroyed without going through do_subobj_destroyed_stuff:
- the subsystem is destroyed at the start of the mission
- the subsystem was destroyed in the previous mission of a red-alert sequence
- the ship changes class while the subsystem's submodels are blown off
Previously the first two blew off only the first submodel, ignored "no disappear" for it, and never showed a linked -destroyed submodel; the third did nothing.  For red alert, subsystems with no hitpoints at all are not treated as destroyed.  For a class change, the visible state is carried over rather than inferred from hitpoints, so a subsystem set to zero without being blown up, or repaired without its submodels, keeps its appearance.

Red alert also restores the submodels of a subsystem that the mission file starts destroyed if the previous mission's data gives it hitpoints.  Ship-copy-damage now shows or hides the -destroyed submodel linked to a special-point subsystem to match the copied state.

As before, the link between special-point subsystems and -destroyed submodels requires "$Link special-point subsystems to -destroyed submodels:" in game_settings.tbl.

The multiplayer hitpoint-update path is not changed.  A client receives subsystem hitpoints separately from the notification that a subsystem was destroyed, so a hitpoint update sent just before the destruction could arrive after it and wrongly restore the submodels.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-29 02:58:02 -04:00

99 lines
4.8 KiB
C++

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#include "weapon/weapon.h"
#ifndef _SHIPHIT_H
#define _SHIPHIT_H
struct vec3d;
class ship;
class ship_subsys;
class object;
#define NO_SPARKS 0
#define CREATE_SPARKS 1
#define MISS_SHIELDS -1
constexpr float DEATHROLL_ROTVEL_CAP = 6.3f; // maximum added deathroll rotvel in rad/sec (6.3 rad/sec is about 1 rev/sec)
// ===================== NOTE!! =========================
// To apply damage to a ship, call either ship_apply_local_damage or ship_apply_global_damage.
// These replace the old calls to ship_hit and ship_do_damage...
// These functions do nothing to the ship's physics; that is the responsibility
// of whoever is calling these functions. These functions are strictly
// for damaging ship's hulls, shields, and subsystems. Nothing more.
// handle a -destroyed submodel in the special case where it is related to a special-point subsystem
// (the usual submodel-submodel case is handled through the normal code paths)
void check_subsystem_submodel_link(const ship *shipp, const ship_subsys *subsys, bool was_destroyed);
// when a destroyed subsystem has been repaired, bring back its submodels in place of any -destroyed form
void restore_subsystem_submodels(const ship *shipp, const ship_subsys *subsys);
// hide a destroyed subsystem's submodels in favor of any -destroyed form, unless the subsystem is flagged not to disappear
void blow_off_subsystem_submodels(const ship *shipp, const ship_subsys *subsys);
// whether a subsystem's submodels are currently blown off, or its linked -destroyed submodel is shown
bool subsystem_submodels_blown_off(const ship *shipp, const ship_subsys *subsys);
// function to destroy a subsystem. Called internally and from multiplayer messaging code
extern void do_subobj_destroyed_stuff( ship *ship_p, ship_subsys *subsys, const vec3d *hitpos, bool no_explosion = false );
std::pair<std::optional<ConditionData>, float> do_subobj_hit_stuff(object *ship_obj, const object *other_obj, const vec3d *hitpos, int submodel_num, float damage, bool *hull_should_apply_armor, float hit_dot = 1.f, bool shield_hit = false);
// Goober5000
// (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);
// 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);
// 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
// shield got hit and if so, apply damage to it.
// 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);
// like above, but does not apply damage to shields
void ship_apply_wash_damage(object *ship_obj, object *other_obj, float damage);
// next routine needed for multiplayer
void ship_hit_kill(object *ship_obj, object *other_obj, const vec3d *hitpos, float percent_killed, bool self_destruct = false, bool always_log_other_obj = false);
void ship_self_destruct( object *objp );
// Call this instead of physics_apply_whack directly to
// deal with two docked ships properly.
void ship_apply_whack(const vec3d *force, const vec3d *hit_pos, object *objp);
// externed for code in missionparse to create sparks on a ship with < 100% hull integrity.
void ship_hit_sparks_no_rotate(object *ship_obj, vec3d *hitpos);
// externed so that ships which self destruct have the proper things done to them in multiplayer
void ship_generic_kill_stuff( object *objp, float percent_killed );
// find the max number of sparks allowed for ship
// limited for fighter by hull % others by radius.
int get_max_sparks(const object* ship_obj);
// player pain
void ship_hit_pain(float damage, int quadrant);
#endif //_SHIPHIT_H