mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 13:01:29 -10:00
A subsystem's looping sounds are now switched by ship_update_subsys_sounds, split out of ship_recalc_subsys_strength, which the support-ship and automatic repair paths now also call when a subsystem comes back from zero. Previously those paths left the subsystem playing its dead sound. Both the recalc and do_subobj_destroyed_stuff also cleared the dead-sound flag immediately after assigning the dead sound, so a revived subsystem never stopped it and a destroyed one gained another copy on each recalc. They now set the flag. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2282 lines
93 KiB
C++
2282 lines
93 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.
|
|
*
|
|
*/
|
|
|
|
#ifndef _SHIP_H
|
|
#define _SHIP_H
|
|
|
|
#include "ai/ai.h"
|
|
#include "fireball/fireballs.h"
|
|
#include "globalincs/globals.h" // for defintions of token lengths -- maybe move this elsewhere later (Goober5000 - moved to globals.h)
|
|
#include "globalincs/pstypes.h"
|
|
#include "graphics/2d.h" // for color def
|
|
#include "hud/hud.h"
|
|
#include "hud/hudparse.h"
|
|
#include "model/model.h"
|
|
#include "model/animation/modelanimation.h"
|
|
#include "network/multi_obj.h"
|
|
#include "radar/radarsetup.h"
|
|
#include "render/3d.h"
|
|
#include "species_defs/species_defs.h"
|
|
#include "weapon/shockwave.h"
|
|
#include "weapon/trails.h"
|
|
#include "ship/anchor_t.h"
|
|
#include "ship/ship_flags.h"
|
|
#include "utils/reset_on_move.h"
|
|
#include "weapon/weapon_flags.h"
|
|
#include "weapon/weapon.h"
|
|
#include "ai/ai.h"
|
|
|
|
#include <string>
|
|
#include <set>
|
|
#include <optional>
|
|
#include <particle/ParticleManager.h>
|
|
|
|
class object;
|
|
class WarpEffect;
|
|
|
|
// Part of the player died system.
|
|
extern vec3d Original_vec_to_deader;
|
|
|
|
// States for player death sequence, stuffed in Player_died_state.
|
|
#define PDS_NONE 1
|
|
#define PDS_DIED 2
|
|
#define PDS_EJECTED 3
|
|
|
|
#define SHIP_GUARDIAN_THRESHOLD_DEFAULT 1 // Goober5000
|
|
|
|
#define HULL_DAMAGE_THRESHOLD_PERCENT 0.25f // Apply damage to hull, not shield if shield < this
|
|
|
|
// the #defines below are to avoid round-off errors
|
|
#define WEAPON_RESERVE_THRESHOLD 0.01f // energy threshold where ship is considered to have no weapon energy system
|
|
#define SUBSYS_MAX_HITS_THRESHOLD 0.01f // max_hits threshold where subsys is considered to take damage
|
|
|
|
#define MAX_SHIP_SPARKS 8 // maximum number of spark emitters on a ship
|
|
#define MAX_SHIP_DETAIL_LEVELS 5 // maximum detail levels that a ship can render at
|
|
|
|
|
|
// defines for 'direction' parameter of ship_select_next_primary()
|
|
enum class CycleDirection { NEXT, PREV };
|
|
|
|
#define BANK_1 0
|
|
#define BANK_2 1
|
|
#define BANK_3 2
|
|
#define BANK_4 3
|
|
#define BANK_5 4
|
|
#define BANK_6 5
|
|
#define BANK_7 6
|
|
#define BANK_8 7
|
|
#define BANK_9 8
|
|
|
|
#define TYPE_ATTACK_PROTECT 0
|
|
#define TYPE_REPAIR_REARM 1
|
|
|
|
#define MAX_REINFORCEMENT_MESSAGES 5
|
|
|
|
#define RF_IS_AVAILABLE (1<<0) // reinforcement is now available
|
|
|
|
struct reinforcements {
|
|
char name[NAME_LENGTH]; // ship or wing name (ship and wing names don't collide)
|
|
int type; // what operations this reinforcement unit can perform
|
|
int uses; // number of times reinforcemnt unit can be used
|
|
int num_uses; // number of times this reinforcement was actually used
|
|
int arrival_delay; // how long after called does this reinforcement appear
|
|
int flags;
|
|
char no_messages[MAX_REINFORCEMENT_MESSAGES][NAME_LENGTH]; // list of messages to possibly send when calling for reinforcement not available
|
|
char yes_messages[MAX_REINFORCEMENT_MESSAGES][NAME_LENGTH]; // list of messages to acknowledge reinforcement on the way
|
|
|
|
reinforcements(const char *reinforcement_name = nullptr);
|
|
};
|
|
|
|
// Per-bank state for a weapon's external model - the model rendered at the bank's firing
|
|
// points when the ship enables $Show Primary Models: / $Show Secondary Models:.
|
|
struct external_weapon_state
|
|
{
|
|
int model_instance = -1; // model instance used to spin Gun_rotation submodels, or -1 if the weapon doesn't need one
|
|
int model_instance_weapon = -1; // the weapon the model instance state was created for, or -1 if not yet checked
|
|
int fp_counter = 0; // cycles through the model's firing points, for "chain external model fps" weapons
|
|
float rotate_rate = 0.0f; // current spin rate of the model's Gun_rotation submodels (primaries only)
|
|
float rotate_ang = 0.0f; // current spin angle of the model's Gun_rotation submodels (primaries only)
|
|
bool spin_up_requested = false; // set each frame the bank tries to fire; consumed by update_external_weapon_spin()
|
|
};
|
|
|
|
class ship_weapon {
|
|
public:
|
|
int num_primary_banks; // Number of primary banks (same as model)
|
|
int num_secondary_banks; // Number of secondary banks (same as model)
|
|
int num_tertiary_banks;
|
|
|
|
int primary_bank_weapons[MAX_SHIP_PRIMARY_BANKS]; // Weapon_info[] index for the weapon in the bank
|
|
int secondary_bank_weapons[MAX_SHIP_SECONDARY_BANKS]; // Weapon_info[] index for the weapon in the bank
|
|
|
|
external_weapon_state primary_bank_external_weapon[MAX_SHIP_PRIMARY_BANKS];
|
|
external_weapon_state secondary_bank_external_weapon[MAX_SHIP_SECONDARY_BANKS];
|
|
|
|
int current_primary_bank; // currently selected primary bank
|
|
int current_secondary_bank; // currently selected secondary bank
|
|
int current_tertiary_bank;
|
|
|
|
int previous_primary_bank;
|
|
int previous_secondary_bank; // currently selected secondary bank
|
|
|
|
int next_primary_fire_stamp[MAX_SHIP_PRIMARY_BANKS]; // next time this primary bank can fire
|
|
int last_primary_fire_stamp[MAX_SHIP_PRIMARY_BANKS]; // last time this primary bank fired (mostly used by SEXPs)
|
|
int next_secondary_fire_stamp[MAX_SHIP_SECONDARY_BANKS]; // next time this secondary bank can fire
|
|
int last_secondary_fire_stamp[MAX_SHIP_SECONDARY_BANKS]; // last time this secondary bank fired (mostly used by SEXPs)
|
|
int next_tertiary_fire_stamp;
|
|
int last_primary_fire_sound_stamp[MAX_SHIP_PRIMARY_BANKS]; // trailing end of the last time this primary bank was fired, for purposes of timing the pre-launch sound
|
|
|
|
// ballistic primary support - by Goober5000
|
|
int primary_bank_ammo[MAX_SHIP_PRIMARY_BANKS]; // Number of missiles left in primary bank
|
|
int primary_bank_start_ammo[MAX_SHIP_PRIMARY_BANKS]; // Number of missiles starting in primary bank
|
|
int primary_bank_capacity[MAX_SHIP_PRIMARY_BANKS]; // Max number of projectiles in bank
|
|
int primary_next_slot[MAX_SHIP_PRIMARY_BANKS]; // Next slot to fire in the bank
|
|
int primary_bank_rearm_time[MAX_SHIP_PRIMARY_BANKS]; // timestamp which indicates when bank can get new projectile
|
|
// end ballistic primary support
|
|
|
|
float primary_bank_fof_cooldown[MAX_SHIP_PRIMARY_BANKS]; // SUSHI: Current FOF cooldown level for the primary weapon
|
|
|
|
// dynamic weapon linking - by RSAXVC
|
|
int primary_bank_slot_count[MAX_SHIP_PRIMARY_BANKS]; // Fire this many slots at a time
|
|
int dynamic_firing_pattern[MAX_SHIP_PRIMARY_BANKS]; // Index into ship_info's dyn_firing_patterns_allowed
|
|
// end dynamic weapon linking
|
|
|
|
int secondary_bank_ammo[MAX_SHIP_SECONDARY_BANKS]; // Number of missiles left in secondary bank
|
|
int secondary_bank_start_ammo[MAX_SHIP_SECONDARY_BANKS]; // Number of missiles starting in secondary bank -- Every time the secondary bank changes, this must change too!
|
|
int secondary_bank_capacity[MAX_SHIP_SECONDARY_BANKS]; // Max number of missiles in bank
|
|
int secondary_next_slot[MAX_SHIP_SECONDARY_BANKS]; // Next slot to fire in the bank
|
|
int secondary_bank_rearm_time[MAX_SHIP_SECONDARY_BANKS]; // timestamp which indicates when bank can get new missile
|
|
|
|
int tertiary_bank_ammo; // Number of shots left tertiary bank
|
|
int tertiary_bank_start_ammo; // Number of shots starting in tertiary bank
|
|
int tertiary_bank_capacity; // Max number of shots in bank
|
|
int tertiary_bank_rearm_time; // timestamp which indicates when bank can get new something (used for ammopod or boostpod)
|
|
|
|
int remote_detonaters_active;
|
|
int detonate_weapon_time; // time at which last fired weapon can be detonated
|
|
int ai_class;
|
|
|
|
int firing_loop_sounds[MAX_SHIP_PRIMARY_BANKS]; // objsnd indices,
|
|
// -2 is a special value used to mean 'a loop WOULD be going on right now'
|
|
// but the modder did not actually specify a loop sound
|
|
|
|
flagset<Ship::Weapon_Flags> flags;
|
|
|
|
EModelAnimationPosition primary_animation_position[MAX_SHIP_PRIMARY_BANKS];
|
|
EModelAnimationPosition secondary_animation_position[MAX_SHIP_SECONDARY_BANKS];
|
|
int primary_animation_done_time[MAX_SHIP_PRIMARY_BANKS];
|
|
int secondary_animation_done_time[MAX_SHIP_SECONDARY_BANKS];
|
|
|
|
int burst_counter[MAX_SHIP_PRIMARY_BANKS + MAX_SHIP_SECONDARY_BANKS];
|
|
int burst_seed[MAX_SHIP_PRIMARY_BANKS + MAX_SHIP_SECONDARY_BANKS]; // A random seed, recalculated only when the weapon's burst resets
|
|
|
|
SCP_vector<int> primary_firepoint_indices[MAX_SHIP_PRIMARY_BANKS]; // A list of firepoint indices which is shuffled for random fire ordering
|
|
int primary_firepoint_next_to_fire_index[MAX_SHIP_PRIMARY_BANKS]; // For cycle firing modes, keeps track of which firepoint we're on
|
|
// For randomized ones, keeps track of where we are in primary_firepoint_indices
|
|
|
|
size_t primary_bank_substitution_pattern_index[MAX_SHIP_PRIMARY_BANKS];
|
|
size_t secondary_bank_substitution_pattern_index[MAX_SHIP_SECONDARY_BANKS];
|
|
|
|
// for type5 beams, keeps track of accumulated per burst rotation, added to with each shot (or burst)
|
|
float per_burst_rot;
|
|
|
|
/**
|
|
* @brief Constructor. Calls clear()
|
|
*/
|
|
ship_weapon();
|
|
|
|
/**
|
|
* @brief Inits ship_weapon
|
|
*/
|
|
void clear();
|
|
};
|
|
|
|
//**************************************************************
|
|
//WMC - Damage type handling code
|
|
|
|
int damage_type_add(const char *name);
|
|
|
|
//**************************************************************
|
|
//WMC - Armor stuff
|
|
|
|
// Nuke: some defines for difficulty scaling type
|
|
#define ADT_DIFF_SCALE_BAD_VAL -1 // error mode
|
|
#define ADT_DIFF_SCALE_FIRST 0
|
|
#define ADT_DIFF_SCALE_LAST 1
|
|
#define ADT_DIFF_SCALE_MANUAL 2 // this is the user defined mode where the modder has to handle difficulty scaling in their calculations
|
|
|
|
// Nuke: +value: replacing constants
|
|
// these are stored as altArguments, positive values mean storage idxes and -1 means not used, anything below that is fair game
|
|
#define AT_CONSTANT_NOT_USED -1 // will probibly never get used
|
|
#define AT_CONSTANT_BAD_VAL -2 // this conveys table error to the user
|
|
#define AT_CONSTANT_BASE_DMG -3 // what the damage was at start of calculations
|
|
#define AT_CONSTANT_CURRENT_DMG -4 // what the damage currently is
|
|
#define AT_CONSTANT_DIFF_FACTOR -5 // difficulty factor (by default 0.2 (easy) to 1.0 (insane))
|
|
#define AT_CONSTANT_RANDOM -6 // number between 0 and 1 (redundant but saves a calculation)
|
|
#define AT_CONSTANT_PI -7 // because everyone likes pi
|
|
|
|
struct ArmorDamageType
|
|
{
|
|
friend class ArmorType;
|
|
private:
|
|
//Rather than make an extra struct,
|
|
//I just made two arrays
|
|
int DamageTypeIndex;
|
|
SCP_vector<int> Calculations;
|
|
SCP_vector<float> Arguments;
|
|
SCP_vector<int> altArguments; // Nuke: to facilitate optional importation of data in place of +value: tag -nuke
|
|
float shieldpierce_pct;
|
|
|
|
// piercing effect data
|
|
float piercing_start_pct;
|
|
int piercing_type;
|
|
// Nuke: difficulty scale type
|
|
int difficulty_scale_type;
|
|
|
|
public:
|
|
void clear();
|
|
};
|
|
|
|
class ArmorType
|
|
{
|
|
private:
|
|
char Name[NAME_LENGTH];
|
|
|
|
SCP_vector<ArmorDamageType> DamageTypes;
|
|
public:
|
|
ArmorType(const char* in_name);
|
|
int flags;
|
|
|
|
//Get
|
|
char *GetNamePtr(){return Name;}
|
|
bool IsName(const char* in_name) { return (stricmp(in_name, Name) == 0); }
|
|
float GetDamage(float damage_applied, int in_damage_type_idx, float diff_dmg_scale, bool is_beam);
|
|
float GetShieldPiercePCT(int damage_type_idx);
|
|
int GetPiercingType(int damage_type_idx);
|
|
float GetPiercingLimit(int damage_type_idx);
|
|
|
|
//Set
|
|
void ParseData();
|
|
};
|
|
|
|
extern SCP_vector<ArmorType> Armor_types;
|
|
|
|
// Caps how far the guarder will stray from the guarded ship while guarding it; range <= 0 removes the cap
|
|
void set_guard_range_ship(float range, int guarded_shipnum, ship* guarder_shipp);
|
|
// Returns the guarder's cap for the guarded ship, or -1 if there is none
|
|
float get_guard_range_ship(int guarded_shipnum, const ship* guarder_shipp);
|
|
// Removes the caps that all ships have for the guarded ship
|
|
void clear_guard_ranges_for_ship(int guarded_shipnum);
|
|
|
|
//**************************************************************
|
|
//WMC - Damage type handling code
|
|
|
|
typedef struct DamageTypeStruct
|
|
{
|
|
char name[NAME_LENGTH];
|
|
} DamageTypeStruct;
|
|
|
|
extern SCP_vector<DamageTypeStruct> Damage_types;
|
|
|
|
#define SAF_IGNORE_SS_ARMOR (1 << 0) // hull armor is applied regardless of the subsystem armor for hull damage
|
|
|
|
#define SADTF_PIERCING_NONE 0 // no piercing effects, no beam tooling
|
|
#define SADTF_PIERCING_DEFAULT 1 // piercing effects, beam tooling
|
|
#define SADTF_PIERCING_RETAIL 2 // no piercing effects, beam tooling
|
|
|
|
//SUSHI: Damage lightning types. SLT = Ship Lighting Type.
|
|
#define SLT_NONE 0
|
|
#define SLT_DEFAULT 1
|
|
|
|
#define NUM_TURRET_ORDER_TYPES 3
|
|
extern const char *Turret_target_order_names[NUM_TURRET_ORDER_TYPES]; //aiturret.cpp
|
|
|
|
#define NUM_TURRET_TYPES 4
|
|
extern const char* Turret_valid_types[NUM_TURRET_TYPES];
|
|
|
|
// Swifty: Cockpit displays
|
|
typedef struct cockpit_display {
|
|
int target;
|
|
int source;
|
|
int foreground;
|
|
int background;
|
|
int offset[2];
|
|
int size[2];
|
|
char name[MAX_FILENAME_LEN];
|
|
} cockpit_display;
|
|
|
|
extern bool Disable_cockpits;
|
|
extern bool Disable_cockpit_sway;
|
|
|
|
extern SCP_vector<cockpit_display> Player_displays;
|
|
|
|
typedef struct cockpit_display_info {
|
|
char name[MAX_FILENAME_LEN];
|
|
char filename[MAX_FILENAME_LEN];
|
|
char fg_filename[MAX_FILENAME_LEN];
|
|
char bg_filename[MAX_FILENAME_LEN];
|
|
int offset[2];
|
|
int size[2];
|
|
} cockpit_display_info;
|
|
|
|
// structure to keep track of ship locks
|
|
typedef struct lock_info {
|
|
object *obj;
|
|
ship_subsys *subsys;
|
|
|
|
vec3d world_pos;
|
|
|
|
int current_target_sx;
|
|
int current_target_sy;
|
|
|
|
bool locked;
|
|
int maintain_lock_count;
|
|
int indicator_x;
|
|
int indicator_y;
|
|
int indicator_start_x;
|
|
int indicator_start_y;
|
|
bool indicator_visible;
|
|
float time_to_lock;
|
|
float dist_to_lock;
|
|
int catching_up;
|
|
float catch_up_distance;
|
|
float last_dist_to_target;
|
|
double accumulated_x_pixels;
|
|
double accumulated_y_pixels;
|
|
bool need_new_start_pos;
|
|
bool target_in_lock_cone;
|
|
|
|
float lock_gauge_time_elapsed;
|
|
float lock_anim_time_elapsed;
|
|
} lock_info;
|
|
|
|
struct guard_range_entry {
|
|
float range;
|
|
int shipnum;
|
|
guard_range_entry(float _range, int _shipnum) : range(_range), shipnum(_shipnum) {}
|
|
};
|
|
|
|
// structure definition for a linked list of subsystems for a ship. Each subsystem has a pointer
|
|
// to the static data for the subsystem. The obj_subsystem data is defined and read in the model
|
|
// code. Other dynamic data (such as current_hits) should remain in this structure.
|
|
class ship_subsys
|
|
{
|
|
public:
|
|
class ship_subsys *next, *prev; // Index of next and previous objects in list.
|
|
model_subsystem *system_info; // pointer to static data for this subsystem -- see model.h for definition
|
|
|
|
int parent_objnum; // objnum of the parent ship
|
|
int parent_subsys_index; // index of this subsystem in the parent ship's linked list -- Do not access manually, use parent_subsys_index() as this may not yet be cached.
|
|
|
|
char sub_name[NAME_LENGTH]; //WMC - Name that overrides name of original
|
|
float current_hits; // current number of hits this subsystem has left.
|
|
float max_hits;
|
|
|
|
flagset<Ship::Subsystem_Flags> flags; // Goober5000
|
|
|
|
int subsys_guardian_threshold; // Goober5000
|
|
int armor_type_idx; // FUBAR
|
|
|
|
// turret info
|
|
//Important -WMC
|
|
//With the new turret code, indexes run from 0 to MAX_SHIP_WEAPONS; a value of MAX_SHIP_PRIMARY_WEAPONS
|
|
//or higher, an index into the turret weapons is considered to be an index into the secondary weapons
|
|
//for much of the code. See turret_next_weap_fire_stamp.
|
|
|
|
vec3d turret_last_fire_direction; // direction pointing last time this turret fired
|
|
int turret_next_enemy_check_stamp; // time at which to next look for a new enemy.
|
|
int turret_next_fire_stamp; // next time this turret can fire
|
|
TIMESTAMP turret_last_fired; // time when the turret last fired any weapon
|
|
int turret_enemy_objnum; // object index of ship this turret is firing upon
|
|
int turret_enemy_sig; // signature of object ship this turret is firing upon
|
|
int turret_next_fire_pos; // counter which tells us which gun position to fire from next
|
|
float turret_time_enemy_in_range; // Number of seconds enemy in view cone, accuracy improves over time.
|
|
int turret_targeting_order[NUM_TURRET_ORDER_TYPES]; //Order that turrets target different types of things.
|
|
float optimum_range;
|
|
float favor_current_facing;
|
|
ship_subsys *targeted_subsys; // subsystem this turret is attacking
|
|
bool scripting_target_override;
|
|
int last_fired_weapon_info_index; // which weapon class was last fired
|
|
int shared_fire_direction_beam_objnum; // reference beam for shared fire direction
|
|
|
|
int turret_pick_big_attack_point_timestamp; // Next time to pick an attack point for this turret
|
|
vec3d turret_big_attack_point; // local coordinate of point for this turret to attack on enemy
|
|
|
|
float turret_inaccuracy; // additional SEXP inaccuracy, field of fire degrees
|
|
|
|
EModelAnimationPosition turret_animation_position;
|
|
int turret_animation_done_time;
|
|
|
|
// swarm (rapid fire) info
|
|
int turret_swarm_info_index[MAX_TFP];
|
|
int turret_swarm_num;
|
|
|
|
// awacs info
|
|
float awacs_intensity;
|
|
float awacs_radius;
|
|
|
|
ship_weapon weapons;
|
|
|
|
// Data the renderer needs for ship instance specific data, like
|
|
// angles and if it is blown off or not.
|
|
// There are 2 of these because turrets need one for the turret and one for the barrel.
|
|
// Things like radar dishes would only use one.
|
|
submodel_instance *submodel_instance_1; // Instance data for main turret or main object
|
|
submodel_instance *submodel_instance_2; // Instance data for turret guns, if there is one
|
|
|
|
int disruption_timestamp; // time at which subsystem isn't disrupted
|
|
|
|
int subsys_cargo_name; // cap ship cargo on subsys
|
|
char subsys_cargo_title[NAME_LENGTH]; // cap ship cargo title (IE: Cargo: or Passengers:)
|
|
fix time_subsys_cargo_revealed; // added by Goober5000
|
|
|
|
int triggered_rotation_index; //the actual currently running animation and assosiated states
|
|
|
|
float points_to_target;
|
|
float base_rotation_rate_pct;
|
|
float gun_rotation_rate_pct;
|
|
|
|
// still going through these...
|
|
flagset<Ship::Subsys_Sound_Flags> subsys_snd_flags;
|
|
|
|
int rotation_timestamp;
|
|
|
|
// target priority setting for turrets
|
|
int target_priority[32];
|
|
int num_target_priorities;
|
|
|
|
//SUSHI: Fields for max_turret_aim_update_delay
|
|
//Only used when targeting small ships
|
|
fix next_aim_pos_time;
|
|
vec3d last_aim_enemy_pos;
|
|
vec3d last_aim_enemy_vel;
|
|
|
|
//scaler for setting adjusted turret rof
|
|
float rof_scaler;
|
|
|
|
//Per-turret ownage settings - SUSHI
|
|
int turret_max_bomb_ownage;
|
|
int turret_max_target_ownage;
|
|
|
|
// multiplayer
|
|
TIMESTAMP info_from_server_stamp;
|
|
|
|
ship_subsys()
|
|
: next(NULL), prev(NULL)
|
|
{}
|
|
|
|
void clear();
|
|
};
|
|
|
|
// The head sentinel of a ship's intrusive subsystem list. The sentinel's
|
|
// address is meaningful: the first node's prev and the last node's next point
|
|
// back at it, and an empty list is self-referential (after list_init) or
|
|
// null-linked (after construction or ship::clear). Moving a ship would
|
|
// otherwise leave the bookend nodes pointing at the old sentinel address, so
|
|
// the move operations re-link them. Copying is deleted: a copied sentinel
|
|
// would alias another list's nodes.
|
|
struct ship_subsys_sentinel : public ship_subsys
|
|
{
|
|
ship_subsys_sentinel() = default;
|
|
|
|
ship_subsys_sentinel(const ship_subsys_sentinel &) = delete;
|
|
ship_subsys_sentinel &operator=(const ship_subsys_sentinel &) = delete;
|
|
|
|
ship_subsys_sentinel(ship_subsys_sentinel &&other) noexcept
|
|
{
|
|
take_links_from(other);
|
|
}
|
|
|
|
ship_subsys_sentinel &operator=(ship_subsys_sentinel &&other) noexcept
|
|
{
|
|
if (this != &other)
|
|
{
|
|
Assertion(next == nullptr || next == this, "Move-assigning over a sentinel whose subsystem list is not empty! The destination's subsystems would be orphaned.");
|
|
take_links_from(other);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
void take_links_from(ship_subsys_sentinel &other) noexcept
|
|
{
|
|
if (other.next == nullptr)
|
|
{
|
|
// other was never list_init'd; match that state
|
|
next = nullptr;
|
|
prev = nullptr;
|
|
}
|
|
else if (other.next == &other)
|
|
{
|
|
// other is an initialized empty list
|
|
next = this;
|
|
prev = this;
|
|
}
|
|
else
|
|
{
|
|
// take ownership of the chain and re-point the bookends
|
|
next = other.next;
|
|
prev = other.prev;
|
|
next->prev = this;
|
|
prev->next = this;
|
|
}
|
|
// leave other as an initialized empty list, which is safe to iterate
|
|
other.next = &other;
|
|
other.prev = &other;
|
|
}
|
|
};
|
|
|
|
// structure for subsystems which tells us the total count of a particular type of subsystem (i.e.
|
|
// we might have 3 engines), and the relative strength of the subsystem. The #defines in model.h
|
|
// for SUBSYSTEM_xxx will be used as indices into this array.
|
|
typedef struct ship_subsys_info {
|
|
int type_count; // number of subsystems of type on this ship;
|
|
float aggregate_max_hits; // maximum number of hits for all subsystems of this type.
|
|
float aggregate_current_hits; // current count of hits for all subsystems of this type.
|
|
} ship_subsys_info;
|
|
|
|
// Karajorma - Used by the alter-ship-flag SEXP as an alternative to having lots of ship flag SEXPs
|
|
typedef struct ship_flag_name {
|
|
Ship::Ship_Flags flag; // the actual ship flag constant as given by the define below
|
|
char flag_name[TOKEN_LENGTH]; // the name written to the mission file for its corresponding parse_object flag
|
|
} ship_flag_name;
|
|
|
|
typedef struct ship_flag_description {
|
|
Ship::Ship_Flags flag;
|
|
const char *flag_desc;
|
|
} ship_flag_description;
|
|
|
|
extern ship_flag_name Ship_flag_names[];
|
|
extern ship_flag_description Ship_flag_descriptions[];
|
|
extern const size_t Num_ship_flag_names;
|
|
extern const size_t Num_ship_flag_descriptions;
|
|
|
|
typedef struct wing_flag_name {
|
|
Ship::Wing_Flags flag;
|
|
char flag_name[TOKEN_LENGTH];
|
|
} wing_flag_name;
|
|
|
|
typedef struct wing_flag_description {
|
|
Ship::Wing_Flags flag;
|
|
const char *flag_desc;
|
|
} wing_flag_description;
|
|
|
|
extern wing_flag_name Wing_flag_names[];
|
|
extern wing_flag_description Wing_flag_descriptions[];
|
|
extern const size_t Num_wing_flag_names;
|
|
extern const size_t Num_wing_flag_descriptions;
|
|
|
|
#define DEFAULT_SHIP_PRIMITIVE_SENSOR_RANGE 10000 // Goober5000
|
|
|
|
#define MAX_DAMAGE_SLOTS 32
|
|
#define MAX_SHIP_DAMAGE_ARCS 5 // How many damage or emp "arcs" can be active at once
|
|
#define NUM_SUB_EXPL_HANDLES 2 // How many different big ship sub explosion sounds can be played.
|
|
|
|
#define MAX_SHIP_CONTRAILS 24
|
|
|
|
typedef struct ship_spark {
|
|
vec3d pos; // position of spark in the submodel's RF
|
|
int submodel_num; // which submodel is making the spark
|
|
int end_time;
|
|
} ship_spark;
|
|
|
|
template <class T>
|
|
struct reload_pct
|
|
{
|
|
void init(int num_banks, int points_per_bank, T value)
|
|
{
|
|
_points_per_bank = points_per_bank;
|
|
_buffer.clear();
|
|
_buffer.resize(num_banks * points_per_bank, value);
|
|
_value = value;
|
|
}
|
|
|
|
T& get(int bank, int point)
|
|
{
|
|
int pos = bank * _points_per_bank + point;
|
|
|
|
// this can happen with mismatched ships.tbl and models
|
|
if (pos >= (int)_buffer.size())
|
|
return _value;
|
|
|
|
return _buffer[pos];
|
|
}
|
|
|
|
void set(int bank, int point, T value)
|
|
{
|
|
int pos = bank * _points_per_bank + point;
|
|
|
|
// this can happen with mismatched ships.tbl and models
|
|
if (pos >= (int)_buffer.size())
|
|
return;
|
|
|
|
_buffer[pos] = value;
|
|
}
|
|
|
|
private:
|
|
int _points_per_bank = 0;
|
|
T _value;
|
|
SCP_vector<T> _buffer;
|
|
};
|
|
|
|
struct ship_electrical_arc : electrical_arc
|
|
{
|
|
TIMESTAMP timestamp; // When this times out, the spark goes away. Invalid is not used
|
|
|
|
// if this vector exists, these points will be used instead of the ones generated on each frame by interp_generate_arc_segment()
|
|
std::unique_ptr<SCP_vector<vec3d>> persistent_arc_points;
|
|
};
|
|
|
|
// NOTE: Can't be treated as a struct anymore, since it has STL data structures in its object tree!
|
|
class ship
|
|
{
|
|
public:
|
|
int objnum;
|
|
int ai_index; // Index in Ai_info of ai_info associated with this ship.
|
|
int ship_info_index; // Index in ship_info for this ship
|
|
int hotkey;
|
|
int escort_priority;
|
|
int score;
|
|
float assist_score_pct;
|
|
int respawn_priority;
|
|
|
|
// BEGIN PACK ubytes and chars
|
|
ubyte pre_death_explosion_happened; // If set, it means the 4 or 5 smaller explosions
|
|
ubyte wash_killed;
|
|
char cargo1;
|
|
char cargo_title[NAME_LENGTH];
|
|
|
|
// ship wing status info
|
|
char wing_status_wing_index; // wing index (0-4) in wingman status gauge
|
|
char wing_status_wing_pos; // wing position (0-5) in wingman status gauge
|
|
|
|
// alternate indexes
|
|
int alt_type_index; // only used for display purposes (read : safe)
|
|
int callsign_index; // ditto
|
|
|
|
// targeting laser info
|
|
char targeting_laser_bank; // -1 if not firing, index into polymodel gun points if it _is_ firing
|
|
int targeting_laser_objnum; // -1 if invalid, beam object # otherwise
|
|
|
|
// corkscrew missile stuff
|
|
ubyte num_corkscrew_to_fire; // # of corkscrew missiles lef to fire
|
|
int corkscrew_missile_bank;
|
|
int next_corkscrew_fire; // next time to fire a corkscrew missile
|
|
// END PACK
|
|
|
|
int final_death_time; // Time until big fireball starts
|
|
int really_final_death_time; // Time until ship breaks up and disappears
|
|
vec3d deathroll_rotvel; // Desired death rotational velocity
|
|
|
|
std::unique_ptr<WarpEffect> warpin_effect;
|
|
std::unique_ptr<WarpEffect> warpout_effect;
|
|
|
|
int warpin_params_index;
|
|
int warpout_params_index;
|
|
|
|
int next_fireball;
|
|
|
|
int next_hit_spark;
|
|
int num_sparks; // Note, this is the number of spark emitter positions!
|
|
ship_spark sparks[MAX_SHIP_SPARKS];
|
|
|
|
bool use_special_explosion;
|
|
int special_exp_damage; // new special explosion/hitpoints system
|
|
int special_exp_blast;
|
|
int special_exp_inner;
|
|
int special_exp_outer;
|
|
bool use_shockwave;
|
|
int special_exp_shockwave_speed;
|
|
int special_exp_deathroll_time;
|
|
|
|
int special_hitpoints;
|
|
int special_shield;
|
|
|
|
float ship_max_shield_strength;
|
|
float ship_max_hull_strength;
|
|
|
|
float max_shield_recharge;
|
|
float max_shield_regen_per_second; // wookieejedi - make this a ship object variable
|
|
float max_weapon_regen_per_second; // wookieejedi - make this a ship object variable
|
|
|
|
int ship_guardian_threshold; // Goober5000 - now also determines whether ship is guardian'd
|
|
SCP_vector<guard_range_entry> max_guard_ranges; // per-guarded-ship caps on this ship's guard engagement/resume range
|
|
float max_guard_radius; // cap for every ship guarding this one, used when the guarder has no cap of its own; <= 0 means unused
|
|
|
|
|
|
char ship_name[NAME_LENGTH];
|
|
SCP_string display_name;
|
|
|
|
int team; // Which team it's on, HOSTILE, FRIENDLY, UNKNOWN, NEUTRAL
|
|
|
|
fix time_cargo_revealed; // time at which the cargo was revealed
|
|
|
|
ArrivalLocation arrival_location;
|
|
int arrival_distance; // how far away this ship should arrive
|
|
anchor_t arrival_anchor; // ship registry index of object this ship arrives near (or in front of)
|
|
int arrival_path_mask; // Goober5000 - possible restrictions on which bay paths to use
|
|
int arrival_cue;
|
|
int arrival_delay;
|
|
|
|
DepartureLocation departure_location; // depart to hyperspace or someplace else (like docking bay)
|
|
anchor_t departure_anchor; // when docking bay -- ship registry index of ship to use
|
|
int departure_path_mask; // Goober5000 - possible restrictions on which bay paths to use
|
|
int departure_cue; // sexpression to eval when departing
|
|
int departure_delay; // time in seconds after sexp is true that we delay.
|
|
|
|
int wingnum; // wing number this ship is in. -1 if in no wing, Wing array index otherwise
|
|
SCP_set<size_t> orders_accepted; // set of orders this ship will accept from the player.
|
|
SCP_set<size_t> orders_allowed_against; // set of orders for which this ship cannot be a target.
|
|
|
|
// Subsystem fields. The subsys_list is a list of all subsystems (which might include multiple types
|
|
// of a particular subsystem, like engines). The subsys_info struct is information for particular
|
|
// types of subsystems. (i.e. the list might contain 3 engines. There will be one subsys_info entry
|
|
// describing the state of all engines combined) -- MWA 4/1/97
|
|
ship_subsys_sentinel subsys_list; // linked list of subsystems for this ship.
|
|
std::unique_ptr<ship_subsys*[]> subsys_list_indexer; // provides random-access lookup to the linked list
|
|
ship_subsys *last_targeted_subobject[MAX_PLAYERS]; // Last subobject that has been targeted. NULL if none;(player specific)
|
|
ship_subsys_info subsys_info[SUBSYSTEM_MAX]; // info on particular generic types of subsystems
|
|
|
|
// ETS fields
|
|
int shield_recharge_index; // index into array holding the shield recharge rate
|
|
int weapon_recharge_index; // index into array holding the weapon recharge rate
|
|
int engine_recharge_index; // index into array holding the engine recharge rate
|
|
float weapon_energy; // Number of EUs in energy reserves
|
|
int next_manage_ets; // timestamp for when ai can next modify ets ( -1 means never )
|
|
float prev_engine_strength; // used only in update_ets() to allow for minimizing overrides to max speed --Asteroth and wookieejedi
|
|
|
|
flagset<Ship::Ship_Flags> flags; // flag variable to contain ship state
|
|
int reinforcement_index; // index into reinforcement struct or -1
|
|
|
|
float afterburner_fuel; // amount of afterburner fuel remaining (capacity is stored
|
|
// as afterburner_fuel_capacity in ship_info).
|
|
float afterburner_last_engage_fuel; // the fuel level when the afterburners were last engaged
|
|
int afterburner_last_end_time; // timestamp when the ship last stopped its afterburner
|
|
|
|
int cmeasure_count; // Number of charges of countermeasures this ship can hold.
|
|
int current_cmeasure; // Currently selected countermeasure.
|
|
|
|
int cmeasure_fire_stamp; // Time at which can fire countermeasure.
|
|
|
|
float target_shields_delta; // Target for shield recharge system.
|
|
float target_weapon_energy_delta; // Target for recharge system.
|
|
ship_weapon weapons;
|
|
|
|
int shield_hits; // Number of hits on shield this frame.
|
|
|
|
SCP_vector<vec3d> shield_points;
|
|
|
|
float wash_intensity;
|
|
vec3d wash_rot_axis;
|
|
int wash_timestamp;
|
|
|
|
SCP_vector<lock_info> missile_locks;
|
|
SCP_vector<lock_info> missile_locks_firing;
|
|
|
|
int num_swarm_missiles_to_fire; // number of swarm missiles that need to be launched
|
|
int next_swarm_fire; // timestamp of next swarm missile to fire
|
|
int num_turret_swarm_info; // number of turrets in process of launching swarm
|
|
int swarm_missile_bank; // The missilebank the swarm was originally launched from
|
|
|
|
int group; // group ship is in, or -1 if none. Fred thing
|
|
SCP_string fred_layer = "Default"; // FRED view layer assignment
|
|
sound_handle death_roll_snd; // id of death roll sound, may need to be stopped early
|
|
int ship_list_index; // index of ship in Ship_objs[] array
|
|
|
|
int thruster_bitmap; // What frame the current thruster bitmap is at for this ship
|
|
float thruster_frame; // Used to keep track of which frame the animation should be on.
|
|
|
|
int thruster_glow_bitmap; // What frame the current thruster engine glow bitmap is at for this ship
|
|
float thruster_glow_frame; // Used to keep track of which frame the engine glow animation should be on.
|
|
float thruster_glow_noise; // Noise for current frame
|
|
|
|
int thruster_secondary_glow_bitmap; // Bobboau
|
|
int thruster_tertiary_glow_bitmap; // Bobboau
|
|
int thruster_distortion_bitmap; // Valathil
|
|
|
|
int next_engine_stutter; // timestamp to time the engine stuttering when a ship dies
|
|
|
|
TIMESTAMP base_texture_anim_timestamp; // Goober5000 - zero mark for texture animations
|
|
|
|
float total_damage_received; // total damage received (for scoring purposes)
|
|
float damage_ship[MAX_DAMAGE_SLOTS]; // damage applied from each player
|
|
int damage_ship_id[MAX_DAMAGE_SLOTS]; // signature of the damager (corresponds to each entry in damage_ship)
|
|
int persona_index; // which persona is this guy.
|
|
|
|
int subsys_disrupted_flags; // bitflags used to check if SUBYSTEM_* is disrupted or not
|
|
int subsys_disrupted_check_timestamp; // timer to control how oftern flags are set/cleared in subsys_disrupted_flags
|
|
|
|
uint create_time; // time ship was created, set by gettime()
|
|
|
|
// keep multiplayer specific stuff below this point
|
|
int ts_index; // index into the team select and Wss_slots array (or -1 if not in one of those arrays)
|
|
|
|
int large_ship_blowup_index; // -1 if not a large ship exploding, else this is an index used by the shipfx large ship exploding code.
|
|
std::array<sound_handle, NUM_SUB_EXPL_HANDLES> sub_expl_sound_handle;
|
|
|
|
// Stuff for showing electrical arcs on damaged ships
|
|
SCP_vector<ship_electrical_arc> electrical_arcs;
|
|
TIMESTAMP arc_next_time; // When the next damage/emp arc will be created.
|
|
SCP_vector<TIMESTAMP> passive_arc_next_times; // When the next passive ship arc will be created.
|
|
|
|
// emp missile stuff
|
|
float emp_intensity; // <= 0.0f if no emp effect present
|
|
float emp_decr; // how much to decrement EMP effect per second for this ship
|
|
|
|
// contrail stuff
|
|
trail *trail_ptr[MAX_SHIP_CONTRAILS];
|
|
|
|
// tag stuff
|
|
float tag_total; // total tag time
|
|
float tag_left; // total tag remaining
|
|
fix time_first_tagged;
|
|
float level2_tag_total; // total tag time
|
|
float level2_tag_left; // total tag remaining
|
|
|
|
// lightning timestamp
|
|
int lightning_stamp;
|
|
|
|
// AWACS warning flag
|
|
flagset<Ship::Awacs_Warning_Flags> awacs_warning_flag;
|
|
|
|
// Special warp objnum (warping at knossos)
|
|
int special_warpin_objnum;
|
|
int special_warpout_objnum;
|
|
|
|
ship_subsys fighter_beam_turret_data; //a fake subsystem that pretends to be a turret for fighter beams
|
|
model_subsystem beam_sys_info;
|
|
int was_firing_last_frame[MAX_SHIP_PRIMARY_BANKS];
|
|
|
|
// Goober5000 - range of primitive sensors
|
|
int primitive_sensor_range;
|
|
|
|
// Goober5000 - index into pm->view_positions[]
|
|
// apparently, early in FS1 development, there was a field called current_eye_index
|
|
// that had this same functionality
|
|
int current_viewpoint;
|
|
|
|
trail *ABtrail_ptr[MAX_SHIP_CONTRAILS]; //after burner trails -Bobboau
|
|
trail_info ab_info[MAX_SHIP_CONTRAILS];
|
|
int ab_count;
|
|
|
|
// glow points
|
|
std::deque<bool> glow_point_bank_active;
|
|
|
|
//Animated Shader effects
|
|
int shader_effect_num;
|
|
int shader_effect_duration;
|
|
TIMESTAMP shader_effect_timestamp;
|
|
|
|
float alpha_mult;
|
|
|
|
ship_subsys *last_fired_turret; // which turret has fired last
|
|
|
|
// fighter bay door stuff, parent side
|
|
int bay_doors_anim_done_time; // ammount of time to transition from one animation state to another
|
|
EModelAnimationPosition bay_doors_status; // anim status of the bay doors (closed/not-animating, opening, open/not-animating)
|
|
int bay_doors_wanting_open; // how many ships want/need the bay door open
|
|
|
|
// figther bay door stuff, client side
|
|
ubyte bay_doors_launched_from; // the bay door that I launched from
|
|
bool bay_doors_need_open; // keep track of whether I need the door open or not
|
|
int bay_doors_parent_shipnum; // our parent ship, what we are entering/leaving
|
|
|
|
reload_pct<float> secondary_point_reload_pct; //after fireing a secondary it takes some time for that secondary weapon to reload, this is how far along in that proces it is (from 0 to 1)
|
|
|
|
SCP_vector<std::tuple<TIMESTAMP, int, float>> rcs_activity; //Timestamp of when thrusters started
|
|
//Sound index for thrusters
|
|
//Thruster status
|
|
|
|
SCP_vector<alt_class> s_alt_classes;
|
|
|
|
SCP_map<std::pair<int, int>, int> ship_iff_color;
|
|
|
|
int ammo_low_complaint_count; // number of times this ship has complained about low ammo
|
|
int armor_type_idx;
|
|
int shield_armor_type_idx;
|
|
int collision_damage_type_idx;
|
|
int debris_damage_type_idx;
|
|
ushort debris_net_sig; // net signiture of the first piece of debris this ship has
|
|
|
|
int model_instance_num;
|
|
|
|
fix time_created;
|
|
|
|
fix radar_visible_since; // The first time this ship was visible on the radar. Gets reset when ship is not visible anymore
|
|
fix radar_last_contact; // The last time this ship appeared on the radar. When it is currently visible this has the value if Missiontime
|
|
|
|
RadarVisibility radar_last_status; // Last radar status
|
|
RadarVisibility radar_current_status; // Current radar status
|
|
|
|
SCP_string team_name;
|
|
SCP_string secondary_team_name; //If the change-team-color sexp is used, these fields control the fading behaviour
|
|
fix team_change_timestamp;
|
|
int team_change_time;
|
|
|
|
float autoaim_fov;
|
|
float bank_autoaim_fov[MAX_SHIP_PRIMARY_BANKS];
|
|
|
|
int cockpit_model_instance;
|
|
|
|
TIMESTAMP multi_client_collision_timestamp;
|
|
|
|
enum warpstage {
|
|
STAGE1 = 0,
|
|
STAGE2,
|
|
BOTH,
|
|
};
|
|
|
|
// Ships support moving but not copying. The defaulted moves are correct
|
|
// because the members carry the smarts: the subsys_list sentinel re-links
|
|
// its bookend nodes, and the owning pointers are unique_ptrs. Callers must
|
|
// still fix up external back-references (Objects[].instance,
|
|
// Ai_info[].shipnum, etc.) -- see reassign_ship_slot in
|
|
// missioneditor/common.cpp.
|
|
// All the defaulted special member functions are defaulted in ship.cpp
|
|
// rather than here because they need the complete WarpEffect type.
|
|
// The moves are not declared noexcept because the implicit exception
|
|
// specification differs by standard library: MSVC and clang compute
|
|
// nothrow, but libstdc++ computes potentially-throwing for some members,
|
|
// making an explicit noexcept ill-formed there (a defaulted redeclaration
|
|
// may not strengthen the implicit specification). The NOLINTs suppress
|
|
// clang-tidy's performance-noexcept-move-constructor, which only sees
|
|
// clang's computation.
|
|
ship();
|
|
~ship();
|
|
ship(const ship &) = delete;
|
|
ship &operator=(const ship &) = delete;
|
|
ship(ship &&); // NOLINT(performance-noexcept-move-constructor)
|
|
ship &operator=(ship &&); // NOLINT(performance-noexcept-move-constructor)
|
|
|
|
// reset to a completely blank ship
|
|
void clear();
|
|
|
|
//Helper functions
|
|
bool is_arriving(ship::warpstage stage = ship::warpstage::BOTH, bool dock_leader_or_single = false) const;
|
|
inline bool is_departing() const { return flags.any_of(Ship::Ship_Flags::Depart_warp,Ship::Ship_Flags::Depart_dockbay); }
|
|
inline bool cannot_warp_flags() const { return flags.any_of(Ship::Ship_Flags::Warp_broken,Ship::Ship_Flags::Warp_never,Ship::Ship_Flags::Disabled,Ship::Ship_Flags::No_subspace_drive); }
|
|
inline bool is_dying_or_departing() const { return is_departing() || flags[Ship::Ship_Flags::Dying]; }
|
|
|
|
const char* get_display_name() const;
|
|
bool has_display_name() const;
|
|
|
|
void apply_replacement_textures(const SCP_vector<texture_replace> &replacements);
|
|
};
|
|
|
|
struct ai_target_priority {
|
|
char name[NAME_LENGTH];
|
|
|
|
int obj_type;
|
|
SCP_vector <int> ship_type;
|
|
SCP_vector <int> ship_class;
|
|
SCP_vector <int> weapon_class;
|
|
|
|
flagset<Object::Object_Flags> obj_flags;
|
|
flagset<Ship::Info_Flags> sif_flags;
|
|
flagset<Weapon::Info_Flags> wif_flags;
|
|
};
|
|
|
|
extern SCP_vector <ai_target_priority> Ai_tp_list;
|
|
|
|
void parse_ai_target_priorities();
|
|
void parse_weapon_targeting_priorities();
|
|
ai_target_priority init_ai_target_priorities();
|
|
|
|
// structure and array def for ships that have exited the game. Keeps track of certain useful
|
|
// information.
|
|
|
|
typedef struct exited_ship {
|
|
char ship_name[NAME_LENGTH];
|
|
SCP_string display_name;
|
|
int obj_signature;
|
|
int ship_class;
|
|
int team;
|
|
int wingnum;
|
|
flagset<Ship::Exit_Flags> flags;
|
|
fix time;
|
|
int hull_strength;
|
|
fix time_cargo_revealed;
|
|
char cargo1;
|
|
float damage_ship[MAX_DAMAGE_SLOTS]; // A copy of the arrays from the ship so that we can figure out what damaged it
|
|
int damage_ship_id[MAX_DAMAGE_SLOTS];
|
|
} exited_ship;
|
|
|
|
extern SCP_vector<exited_ship> Ships_exited;
|
|
|
|
// a couple of functions to get at the data
|
|
extern void ship_add_exited_ship( ship *shipp, Ship::Exit_Flags reason );
|
|
extern int ship_find_exited_ship_by_name( const char *name );
|
|
extern int ship_find_exited_ship_by_signature( int signature);
|
|
|
|
// Stuff for overall ship status, useful for reference by sexps and scripts. Status changes occur in the same frame as mission log entries.
|
|
enum class ShipStatus
|
|
{
|
|
// The ship_registry_entry hasn't been initialized yet
|
|
INVALID = 0,
|
|
|
|
// A ship is on the arrival list as a parse object
|
|
NOT_YET_PRESENT,
|
|
|
|
// A ship is currently in-mission, and its objp and shipp pointers are valid
|
|
PRESENT,
|
|
|
|
// A ship has been destroyed but is still doing its death roll (not yet "exited");
|
|
// the objp and shipp pointers are still valid
|
|
DEATH_ROLL,
|
|
|
|
// A ship is destroyed, departed, or vanished; the objp and shipp pointers are nullptr.
|
|
// Note that for destroyed ships, ship_cleanup is not called until the death roll is complete,
|
|
// so the ship will spend a period of time in DEATH_ROLL before moving to EXITED.
|
|
EXITED
|
|
};
|
|
|
|
struct ship_registry_entry
|
|
{
|
|
ShipStatus status = ShipStatus::INVALID;
|
|
char name[NAME_LENGTH] = { 0 };
|
|
|
|
int pobj_num = -1;
|
|
int objnum = -1;
|
|
int shipnum = -1;
|
|
|
|
int cleanup_mode = 0;
|
|
int exited_index = -1;
|
|
|
|
ship_registry_entry(const char* _name);
|
|
|
|
inline bool has_p_objp() const { return pobj_num >= 0; }
|
|
inline bool has_objp() const { return objnum >= 0; }
|
|
inline bool has_shipp() const { return shipnum >= 0; }
|
|
|
|
p_object* p_objp() const;
|
|
object* objp() const;
|
|
ship* shipp() const;
|
|
|
|
p_object* p_objp_or_null() const;
|
|
object* objp_or_null() const;
|
|
ship* shipp_or_null() const;
|
|
|
|
ship_info* sip() const;
|
|
int ship_class_index() const;
|
|
};
|
|
|
|
extern SCP_vector<ship_registry_entry> Ship_registry;
|
|
extern SCP_unordered_map<SCP_string, int, SCP_string_lcase_hash, SCP_string_lcase_equal_to> Ship_registry_map;
|
|
|
|
extern int ship_registry_get_index(const char *name);
|
|
extern int ship_registry_get_index(const SCP_string &name);
|
|
extern bool ship_registry_exists(const char *name);
|
|
extern bool ship_registry_exists(const SCP_string &name);
|
|
extern bool ship_registry_exists(int index);
|
|
extern const ship_registry_entry *ship_registry_get(const char *name);
|
|
extern const ship_registry_entry *ship_registry_get(const SCP_string &name);
|
|
extern const ship_registry_entry *ship_registry_get(int index);
|
|
extern const ship_registry_entry *ship_registry_get(anchor_t anchor);
|
|
extern void ship_registry_rename(int entry_index, const char *new_name, bool erase_old_key);
|
|
|
|
#define REGULAR_WEAPON (1<<0)
|
|
#define DOGFIGHT_WEAPON (1<<1)
|
|
|
|
typedef struct ship_passive_arc_info {
|
|
std::pair<int, int> submodels;
|
|
std::pair<SCP_string, SCP_string> submodel_strings; // the string names from parsing, to be looked up and used to fill the above later when the model is ready
|
|
std::pair<vec3d, vec3d> pos;
|
|
float duration;
|
|
float frequency;
|
|
float width;
|
|
color primary_color_1;
|
|
color primary_color_2;
|
|
color secondary_color;
|
|
} ship_lightning_data;
|
|
|
|
typedef struct thruster_particles {
|
|
generic_anim thruster_bitmap;
|
|
particle::ParticleEffectHandle particle_handle;
|
|
} thruster_particles;
|
|
|
|
typedef struct ship_type_info {
|
|
char name[NAME_LENGTH];
|
|
|
|
flagset<Ship::Type_Info_Flags> flags;
|
|
|
|
float debris_max_speed;
|
|
|
|
// Damage multiplier for friendly fire, but only for purposes of scoring and traitor check, not actually damaging ships in-mission
|
|
float ff_multiplier;
|
|
|
|
// Not currently implemented. Originally used for "electronics" weapons. Deactivated in commit 941faf9ab9ed05a1b0efebf7de32c6e3c724baf7
|
|
// as it broke retail compatibility.
|
|
float emp_multiplier;
|
|
|
|
// Modifies the audible range used for warp fireball 3d sound effects
|
|
float warp_sound_range_multiplier;
|
|
|
|
//Fog
|
|
float fog_start_dist;
|
|
float fog_complete_dist;
|
|
|
|
//AI
|
|
SCP_set<ai_goal_mode> ai_valid_goals;
|
|
SCP_set<size_t> ai_player_orders;
|
|
int ai_active_dock;
|
|
int ai_passive_dock;
|
|
SCP_vector<int> ai_actively_pursues;
|
|
SCP_vector<int> ai_cripple_ignores;
|
|
|
|
//Explosions
|
|
float skip_deathroll_chance;
|
|
|
|
//Resources
|
|
SCP_vector<int> explosion_bitmap_anims;
|
|
|
|
//Regen values - need to be converted after all types have loaded
|
|
SCP_vector<SCP_string> ai_actively_pursues_temp;
|
|
SCP_vector<SCP_string> ai_cripple_ignores_temp;
|
|
|
|
ship_type_info( )
|
|
: debris_max_speed( 0.f ),
|
|
ff_multiplier( 0.f ), emp_multiplier( 0.f ), warp_sound_range_multiplier( 1.f ),
|
|
fog_start_dist( 0.f ), fog_complete_dist( 0.f ),
|
|
ai_active_dock( 0 ), ai_passive_dock( 0 ),
|
|
skip_deathroll_chance( 0.f )
|
|
|
|
{
|
|
flags.reset();
|
|
name[ 0 ] = '\0';
|
|
}
|
|
} ship_type_info;
|
|
|
|
extern SCP_vector<ship_type_info> Ship_types;
|
|
extern bool Fighter_bomber_valid; // Whether "fighter/bomber" can be used as a union of "fighter" and "bomber"
|
|
extern const char *Fighter_bomber_type_name;
|
|
extern int Ship_type_fighter, Ship_type_bomber, Ship_type_fighter_bomber;
|
|
|
|
class rcs_thruster_info {
|
|
public:
|
|
flagset<Ship::Thruster_Flags> use_flags;
|
|
|
|
gamesnd_id start_snd;
|
|
gamesnd_id loop_snd;
|
|
gamesnd_id stop_snd;
|
|
|
|
int tex_id;
|
|
int tex_nframes;
|
|
int tex_fps;
|
|
float length;
|
|
float radius;
|
|
|
|
vec3d pos, norm;
|
|
|
|
rcs_thruster_info() : tex_id(-1), tex_nframes(0), tex_fps(0), length(0), radius (0.0f) {
|
|
norm.xyz.x = norm.xyz.y = norm.xyz.z = 0.0f; // I wanted to do norm = ZERO_VECTOR here, but apparently that breaks the MSVC 2015 compiler....
|
|
pos.xyz.x = pos.xyz.y = pos.xyz.z = 0.0f;
|
|
use_flags.reset();
|
|
|
|
start_snd = gamesnd_id();
|
|
loop_snd = gamesnd_id();
|
|
stop_snd = gamesnd_id();
|
|
}
|
|
};
|
|
|
|
// Holds variables for collision physics (Gets its own struct purely for clarity purposes)
|
|
// Most of this only really applies properly to small ships
|
|
typedef struct ship_collision_physics {
|
|
// Collision physics definitions: how a ship responds to collisions
|
|
float both_small_bounce{}; // Bounce factor when both ships are small
|
|
// This currently only comes into play if one ship is the player...
|
|
// blame retail for that.
|
|
float bounce{}; // Bounce factor for all other cases
|
|
float friction{}; // Controls lateral velocity lost when colliding with a large ship
|
|
float rotation_factor{}; // Affects the rotational energy of collisions... TBH not sure how.
|
|
float rotation_mag_max{}; // Maximum value of the final rotational velocity resulting from a collision --wookieejedi
|
|
|
|
// Speed & angle constraints for a smooth landing
|
|
// Note that all angles are stored as a dotproduct between normalized vectors instead. This saves us from having
|
|
// to do a lot of dot product calculations later.
|
|
float landing_max_z{};
|
|
float landing_min_z{};
|
|
float landing_min_y{};
|
|
float landing_max_x{};
|
|
float landing_max_angle{};
|
|
float landing_min_angle{};
|
|
float landing_max_rot_angle{};
|
|
|
|
// Speed & angle constraints for a "rough" landing (one with normal collision consequences, but where
|
|
// the ship is still reoriented towards its resting orientation)
|
|
float reorient_max_z{};
|
|
float reorient_min_z{};
|
|
float reorient_min_y{};
|
|
float reorient_max_x{};
|
|
float reorient_max_angle{};
|
|
float reorient_min_angle{};
|
|
float reorient_max_rot_angle{};
|
|
|
|
// Landing response parameters
|
|
float reorient_mult{}; // How quickly the ship will reorient towards it's resting position
|
|
float landing_rest_angle{}; // The vertical angle where the ship's orientation comes to rest
|
|
gamesnd_id landing_sound_idx; //Sound to play on successful landing collisions
|
|
|
|
// Collision sounds
|
|
gamesnd_id collision_sound_light_idx;
|
|
gamesnd_id collision_sound_heavy_idx;
|
|
gamesnd_id collision_sound_shielded_idx;
|
|
|
|
} ship_collision_physics;
|
|
|
|
typedef struct path_metadata {
|
|
vec3d departure_rvec;
|
|
vec3d arrival_rvec;
|
|
float arrive_speed_mult;
|
|
float depart_speed_mult;
|
|
} path_metadata;
|
|
|
|
class allowed_weapon_bank
|
|
{
|
|
public:
|
|
SCP_vector<std::pair<int, ubyte>> weapon_and_flags;
|
|
|
|
ubyte find_flags(int weapon_info_index) const;
|
|
void set_flag(int weapon_info_index, ubyte flag);
|
|
void clear_flag(int weapon_info_index, ubyte flag);
|
|
void clear_flag(ubyte flag);
|
|
|
|
void clear();
|
|
|
|
ubyte operator[](int index) const;
|
|
ubyte operator[](size_t index) const;
|
|
};
|
|
|
|
// The real FreeSpace ship_info struct.
|
|
// NOTE: Can't be treated as a struct anymore, since it has STL data structures in its object tree!
|
|
class ship_info
|
|
{
|
|
public:
|
|
char name[NAME_LENGTH]; // name for the ship
|
|
SCP_string display_name; // display another name for the ship
|
|
char short_name[NAME_LENGTH]; // short name, for use in the editor?
|
|
int species; // which species this craft belongs to
|
|
int class_type; //For type table
|
|
|
|
std::unique_ptr<char[]> type_str; // type string used by tooltips
|
|
std::unique_ptr<char[]> maneuverability_str; // string used by tooltips
|
|
std::unique_ptr<char[]> armor_str; // string used by tooltips
|
|
std::unique_ptr<char[]> manufacturer_str; // string used by tooltips
|
|
std::unique_ptr<char[]> desc; // string used by tooltips
|
|
std::unique_ptr<char[]> tech_desc; // string used by tech database
|
|
char tech_title[NAME_LENGTH]; // ship's name (in tech database)
|
|
|
|
std::unique_ptr<char[]> ship_length; // string used by multiplayer ship desc
|
|
std::unique_ptr<char[]> gun_mounts; // string used by multiplayer ship desc
|
|
std::unique_ptr<char[]> missile_banks; // string used by multiplayer ship desc
|
|
|
|
char cockpit_pof_file[MAX_FILENAME_LEN]; // POF file for cockpit view
|
|
vec3d cockpit_offset;
|
|
float cockpit_sway_val; // multiplier for cockpit 'swaying'
|
|
char pof_file[MAX_FILENAME_LEN]; // POF file to load/associate with ship
|
|
char pof_file_hud[MAX_FILENAME_LEN]; // POF file to load for the HUD target box
|
|
char pof_file_tech[MAX_FILENAME_LEN]; // POF file to load for the techroom
|
|
int num_detail_levels; // number of detail levels for this ship
|
|
int detail_distance[MAX_SHIP_DETAIL_LEVELS]; // distance to change detail levels at
|
|
int collision_lod; // check for collisions using a LOD
|
|
int cockpit_model_num; // cockpit model
|
|
int model_num; // ship model
|
|
int model_num_hud; // model to use when rendering to the HUD (eg, mini supercap)
|
|
int hud_target_lod; // LOD to use for rendering to the HUD targetbox (if not already using special HUD model)
|
|
float density; // density of the ship in g/cm^3 (water = 1)
|
|
float damp; // drag
|
|
float rotdamp; // rotational drag
|
|
float delta_bank_const;
|
|
vec3d max_vel; // max velocity of the ship in the linear directions -- read from ships.tbl
|
|
vec3d min_vel; // min velocity of the ship in the linear directions -- read from ships.tbl
|
|
vec3d max_rotvel; // maximum rotational velocity
|
|
vec3d rotation_time; // time to rotate in x/y/z dimension traveling at max rotvel
|
|
float srotation_time; // scalar, computed at runtime as (rotation_time.x + rotation_time.y)/2
|
|
float max_rear_vel; // max speed ship can go backwards.
|
|
float forward_accel;
|
|
float forward_decel;
|
|
float slide_accel;
|
|
float slide_decel;
|
|
float gravity_const; // multiplies the affect of gravity, if any
|
|
float dying_gravity_const; // as above, when death rolling
|
|
|
|
int warpin_params_index;
|
|
int warpout_params_index;
|
|
|
|
flagset<Ship::Info_Flags> flags; // See SIF_xxxx - changed to uint by Goober5000, changed back by Zacam, and changed to something entirely different by The E!
|
|
int ai_class; // Index into Ai_classes[]. Defined in ai.tbl
|
|
float max_speed, min_speed, max_accel;
|
|
|
|
//Collision
|
|
int collision_damage_type_idx;
|
|
ship_collision_physics collision_physics;
|
|
|
|
// ship explosion info
|
|
shockwave_create_info shockwave;
|
|
int explosion_propagates; // If true, then the explosion propagates
|
|
bool explosion_splits_ship; // If true, then the ship 'splits in two' when it blows up
|
|
float big_exp_visual_rad; //SUSHI: The visual size of the main explosion
|
|
float prop_exp_rad_mult; // propagating explosions radius multiplier
|
|
float death_roll_r_mult;
|
|
float death_fx_r_mult;
|
|
float death_roll_time_mult;
|
|
float death_roll_rotation_mult;
|
|
float death_roll_xrotation_cap; // max rotation around x-axis in radians-per-sec (aka pitch)
|
|
float death_roll_yrotation_cap; // max rotation around y-axis in radians-per-sec (aka yaw)
|
|
float death_roll_zrotation_cap; // max rotation around z-axis in radians-per-sec (aka roll)
|
|
int death_roll_base_time;
|
|
int death_fx_count;
|
|
int shockwave_count; // the # of total shockwaves
|
|
SCP_vector<int> explosion_bitmap_anims;
|
|
bool disable_main_fireball;
|
|
float skip_deathroll_chance;
|
|
|
|
particle::ParticleEffectHandle impact_spew;
|
|
particle::ParticleEffectHandle damage_spew;
|
|
particle::ParticleEffectHandle death_roll_exp_particles;
|
|
particle::ParticleEffectHandle pre_death_exp_particles;
|
|
particle::ParticleEffectHandle propagating_exp_particles;
|
|
particle::ParticleEffectHandle split_particles;
|
|
particle::ParticleEffectHandle knossos_end_particles;
|
|
particle::ParticleEffectHandle regular_end_particles;
|
|
particle::ParticleEffectHandle debris_flame_particles;
|
|
particle::ParticleEffectHandle shrapnel_flame_particles;
|
|
particle::ParticleEffectHandle debris_end_particles;
|
|
particle::ParticleEffectHandle shrapnel_end_particles;
|
|
particle::ParticleEffectHandle default_subsys_debris_flame_particles;
|
|
particle::ParticleEffectHandle default_subsys_shrapnel_flame_particles;
|
|
|
|
//Debris stuff
|
|
float debris_min_lifetime;
|
|
float debris_max_lifetime;
|
|
float debris_min_speed;
|
|
float debris_max_speed;
|
|
float debris_min_rotspeed;
|
|
float debris_max_rotspeed;
|
|
int debris_damage_type_idx;
|
|
float debris_min_hitpoints;
|
|
float debris_max_hitpoints;
|
|
float debris_hitpoints_radius_multi;
|
|
float debris_damage_mult;
|
|
float debris_arc_percent;
|
|
float debris_gravity_const; // see gravity_const above
|
|
float debris_density;
|
|
gamesnd_id debris_ambient_sound;
|
|
gamesnd_id debris_collision_sound_light;
|
|
gamesnd_id debris_collision_sound_heavy;
|
|
gamesnd_id debris_explosion_sound;
|
|
char generic_debris_pof_file[MAX_FILENAME_LEN]; // smaller debris bits thrown around willy-nilly on death
|
|
int generic_debris_model_num;
|
|
int generic_debris_num_submodels;
|
|
int generic_debris_spew_num;
|
|
|
|
// subsystem information
|
|
// (n_subsystems describes the subsystems array; the wrapper keeps it
|
|
// consistent with the array by resetting it to 0 in a moved-from ship_info)
|
|
util::reset_on_move<int> n_subsystems; // this number comes from ships.tbl
|
|
std::unique_ptr<model_subsystem[]> subsystems; // see model.h for structure definition
|
|
particle::ParticleEffectHandle default_subsys_death_effect;
|
|
|
|
// Energy Transfer System fields
|
|
float power_output; // power output of ships reactor (EU/s)
|
|
float max_overclocked_speed; // max speed when 100% power output sent to engines
|
|
float max_weapon_reserve; // maximum energy that can be stored for primary weapon usage
|
|
float max_shield_regen_per_second; // Goober5000 - max percent/100 of shield energy regenerated per second
|
|
float shield_regen_hit_delay; // Asteroth - delay after being hit before shield will start recharging again
|
|
float max_weapon_regen_per_second; // Goober5000 - max percent/100 of weapon energy regenerated per second
|
|
|
|
// Fields for tuning the ETS' direct shield<->weapon transfer feature
|
|
float shield_weap_amount; // fraction of shield capacity to transfer
|
|
float shield_weap_efficiency; // efficiency multiplier for output into weapons capacitor
|
|
float shield_weap_speed; // rate that energy will be added to the weap capacitor
|
|
float weap_shield_amount; // ...
|
|
float weap_shield_efficiency; // ditto, but reverse the direction
|
|
float weap_shield_speed; // ...
|
|
|
|
// Afterburner fields
|
|
vec3d afterburner_max_vel; // max velocity of the ship in the linear directions when afterburners are engaged -- read from ships.tbl
|
|
float afterburner_forward_accel; // forward acceleration with afterburner engaged
|
|
float afterburner_fuel_capacity; // maximum afterburner fuel that can be stored
|
|
float afterburner_burn_rate; // rate in fuel/second that afterburner consumes fuel
|
|
float afterburner_recover_rate; // rate in fuel/second that afterburner recovers fuel
|
|
float afterburner_min_start_fuel; // must have at least this much fuel to start
|
|
float afterburner_min_fuel_to_burn; // consumes at least this much fuel before allowing to stop
|
|
float afterburner_cooldown_time; // minimum time between last afterburner finish and next start
|
|
//SparK: reverse afterburner
|
|
float afterburner_max_reverse_vel;
|
|
float afterburner_reverse_accel;
|
|
|
|
int cmeasure_type; // Type of countermeasures this ship carries
|
|
int cmeasure_max; // Number of charges of countermeasures this ship can hold.
|
|
|
|
int num_primary_banks; // Actual number of primary banks (property of model)
|
|
int primary_bank_weapons[MAX_SHIP_PRIMARY_BANKS]; // Weapon_info[] index for the weapon in the bank
|
|
// Goober5000's ballistic conversion
|
|
int primary_bank_ammo_capacity[MAX_SHIP_PRIMARY_BANKS]; // Capacity of primary ballistic bank
|
|
|
|
int num_secondary_banks; // Actual number of secondary banks (property of model)
|
|
int secondary_bank_weapons[MAX_SHIP_SECONDARY_BANKS]; // Weapon_info[] index for the weapon in the bank
|
|
int secondary_bank_ammo_capacity[MAX_SHIP_SECONDARY_BANKS]; // Capacity of bank (not number of missiles)
|
|
|
|
bool draw_primary_models[MAX_SHIP_PRIMARY_BANKS];
|
|
bool draw_secondary_models[MAX_SHIP_SECONDARY_BANKS];
|
|
float weapon_model_draw_distance;
|
|
|
|
// Recoil modifier for the ship
|
|
float ship_recoil_modifier;
|
|
|
|
// Shudder modifier for the ship
|
|
float ship_shudder_modifier;
|
|
|
|
SCP_vector<FiringPattern> dyn_firing_patterns_allowed[MAX_SHIP_PRIMARY_BANKS];
|
|
|
|
float max_hull_strength; // Max hull strength of this class of ship.
|
|
float max_shield_strength;
|
|
float auto_shield_spread; // Thickness of the shield
|
|
bool auto_shield_spread_bypass; // Whether weapons fired up close can bypass shields
|
|
int auto_shield_spread_from_lod; // Which LOD to project the shield from
|
|
float auto_shield_spread_min_span; // Minimum distance weapons must travel until allowed to collide with the shield
|
|
float max_shield_impact_effect_radius;
|
|
|
|
int shield_point_augment_ctrls[4]; // Re-mapping of shield augmentation controls for model point shields
|
|
|
|
float max_shield_recharge;
|
|
|
|
float hull_repair_rate; // How much of the hull is repaired every second
|
|
float subsys_repair_rate; // How much of the subsystem is repaired every second
|
|
float hull_repair_max; // Maximum percent that hull can self repair --wookieejedi
|
|
float subsys_repair_max; // Maximum percent that subsystems can self repair --wookieejedi
|
|
|
|
float sup_hull_repair_rate;
|
|
float sup_shield_repair_rate;
|
|
float sup_subsys_repair_rate;
|
|
|
|
vec3d closeup_pos; // position for camera when using ship in closeup view (eg briefing and techroom)
|
|
float closeup_zoom; // zoom when using ship in closeup view (eg briefing and techroom)
|
|
std::optional<vec3d> icon_closeup_pos; // icon-specific position for camera when using ship in closeup view
|
|
std::optional<float> icon_closeup_zoom; // icon-specific zoom when using ship in closeup view
|
|
|
|
vec3d closeup_pos_targetbox; // position for camera when using ship in closeup view for hud target monitor
|
|
float closeup_zoom_targetbox; // zoom when using ship in closeup view for hud target monitor
|
|
|
|
vec3d chase_view_offset; // special offset for chase view
|
|
float chase_view_rigidity; // how 'floaty' this ship is when viewed in chase view
|
|
|
|
allowed_weapon_bank allowed_weapons; // specifies which weapons can be loaded out by the
|
|
// player during weapons loadout.
|
|
|
|
// Goober5000 - fix for restricted banks mod
|
|
SCP_vector<ubyte> restricted_loadout_flag;
|
|
SCP_vector<allowed_weapon_bank> allowed_bank_restricted_weapons;
|
|
|
|
ubyte shield_icon_index; // index to locate ship-specific animation frames for the shield on HUD
|
|
char icon_filename[MAX_FILENAME_LEN]; // filename for icon that is displayed in ship selection
|
|
angles model_icon_angles; // angle from which the model icon should be rendered (if not 0,0,0)
|
|
char anim_filename[MAX_FILENAME_LEN]; // filename for animation that plays in ship selection
|
|
char overhead_filename[MAX_FILENAME_LEN]; // filename for animation that plays weapons loadout
|
|
int selection_effect;
|
|
color fs2_effect_grid_color; // color of the grid effect in the ship selection screen
|
|
color fs2_effect_scanline_color; // color of the scanline effect in the ship selection screen
|
|
int fs2_effect_grid_density; // density of the grid effect in the ship selection screen
|
|
color fs2_effect_wireframe_color; // color of the wireframe effect in the ship selection screen
|
|
|
|
int wingmen_status_dot_override; // optional wingmen dot status animation to use instead of default --wookieejedi
|
|
|
|
int bii_index_ship; // if this ship has a briefing icon that overrides the normal icon set
|
|
int bii_index_ship_with_cargo;
|
|
int bii_index_wing;
|
|
int bii_index_wing_with_cargo;
|
|
|
|
int score; // default score for this ship
|
|
|
|
int scan_time; // time to scan this ship (in ms)
|
|
float scan_range_normal; // this ship can scan other normal/small ships at this range
|
|
float scan_range_capital; // this ship can scan other capital/large ships at this range
|
|
float scanning_time_multiplier; // when this ship is doing the scanning, the factor to apply to scan time
|
|
float scanning_range_multiplier; // ditto for scan range
|
|
|
|
float ask_help_shield_percent;
|
|
float ask_help_hull_percent;
|
|
|
|
// contrail info
|
|
trail_info ct_info[MAX_SHIP_CONTRAILS];
|
|
int ct_count;
|
|
|
|
// rgb shield color
|
|
ubyte shield_color[3];
|
|
|
|
// HW2-style team coloring
|
|
bool uses_team_colors;
|
|
SCP_string default_team_name;
|
|
|
|
// optional afterburner trail values
|
|
generic_bitmap afterburner_trail;
|
|
float afterburner_trail_tex_stretch;
|
|
float afterburner_trail_width_factor;
|
|
float afterburner_trail_alpha_factor;
|
|
float afterburner_trail_alpha_end_factor;
|
|
float afterburner_trail_alpha_decay_exponent;
|
|
float afterburner_trail_life;
|
|
float afterburner_trail_spread;
|
|
int afterburner_trail_faded_out_sections;
|
|
|
|
// thruster particles
|
|
SCP_vector<thruster_particles> normal_thruster_particles;
|
|
SCP_vector<thruster_particles> afterburner_thruster_particles;
|
|
|
|
// Bobboau's extra thruster stuff
|
|
thrust_pair thruster_flame_info;
|
|
thrust_pair thruster_glow_info;
|
|
thrust_pair_bitmap thruster_secondary_glow_info;
|
|
thrust_pair_bitmap thruster_tertiary_glow_info;
|
|
thrust_pair_bitmap thruster_distortion_info;
|
|
|
|
float thruster01_glow_rad_factor;
|
|
float thruster02_glow_rad_factor;
|
|
float thruster03_glow_rad_factor;
|
|
float thruster02_glow_len_factor;
|
|
float thruster_dist_rad_factor;
|
|
float thruster_dist_len_factor;
|
|
float thruster_glow_noise_mult;
|
|
|
|
bool draw_distortion;
|
|
|
|
// Goober5000
|
|
SCP_vector<texture_replace> replacement_textures;
|
|
|
|
|
|
int armor_type_idx;
|
|
int shield_armor_type_idx;
|
|
|
|
bool can_glide;
|
|
float glide_cap; //Backslash - for 'newtonian'-style gliding, the cap on velocity
|
|
bool glide_dynamic_cap; //SUSHI: Whether or not we are using a dynamic glide cap
|
|
float glide_accel_mult; //SUSHI: acceleration multiplier for glide mode
|
|
bool use_newtonian_damp; //SUSHI: Whether or not to use newtonian dampening for this ship
|
|
bool newtonian_damp_override;
|
|
|
|
float autoaim_fov;
|
|
float bank_autoaim_fov[MAX_SHIP_PRIMARY_BANKS];
|
|
|
|
bool aims_at_flight_cursor;
|
|
bool aims_at_flight_cursor_secondary;
|
|
float flight_cursor_aim_extent;
|
|
|
|
bool topdown_offset_def;
|
|
vec3d topdown_offset;
|
|
|
|
gamesnd_id engine_snd; // handle to engine sound for ship (-1 if no engine sound)
|
|
float min_engine_vol; // minimum volume modifier for engine sound when ship is stationary
|
|
gamesnd_id glide_start_snd; // handle to sound to play at the beginning of a glide maneuver (default is 0 for regular throttle down sound)
|
|
gamesnd_id glide_end_snd; // handle to sound to play at the end of a glide maneuver (default is 0 for regular throttle up sound)
|
|
gamesnd_id flyby_snd; // handle to sound to play with ship flyby
|
|
|
|
SCP_map<GameSounds, gamesnd_id> ship_sounds; // specifies ship-specific sound indexes
|
|
|
|
SCP_map<SCP_string, SCP_string> custom_data;
|
|
|
|
SCP_vector<custom_string> custom_strings;
|
|
|
|
SCP_vector<rcs_thruster_info> rcs_thrusters;
|
|
|
|
int radar_image_2d_idx;
|
|
int radar_color_image_2d_idx;
|
|
int radar_image_size;
|
|
float radar_projection_size_mult;
|
|
|
|
SCP_map<std::pair<int, int>, int> ship_iff_info;
|
|
|
|
flagset<Object::Aiming_Flags> aiming_flags;
|
|
float minimum_convergence_distance;
|
|
float convergence_distance;
|
|
vec3d convergence_offset;
|
|
gamesnd_id autoaim_lock_snd;
|
|
gamesnd_id autoaim_lost_snd;
|
|
|
|
float emp_resistance_mod;
|
|
|
|
float piercing_damage_draw_limit;
|
|
particle::ParticleEffectHandle shield_impact_explosion_anim;
|
|
|
|
int damage_lightning_type;
|
|
|
|
SCP_vector<std::unique_ptr<HudGauge>> hud_gauges;
|
|
bool hud_enabled;
|
|
bool hud_retail;
|
|
|
|
SCP_vector<cockpit_display_info> displays;
|
|
|
|
SCP_map<SCP_string, path_metadata> pathMetadata;
|
|
|
|
SCP_unordered_map<int, int> glowpoint_bank_override_map; // key: glowpoint bank (-1 = all banks); value: index into the growable global glowpoint_bank_overrides vector
|
|
|
|
animation::ModelAnimationSet animations;
|
|
animation::ModelAnimationSet cockpit_animations;
|
|
|
|
SCP_vector<ship_passive_arc_info> ship_passive_arcs;
|
|
|
|
ship_info();
|
|
~ship_info() = default;
|
|
void clone(const ship_info& other);
|
|
|
|
ship_info(ship_info&& other) = default; // NOLINT(performance-noexcept-move-constructor) - not declared noexcept because the implicit exception specification differs by standard library
|
|
ship_info &operator=(ship_info&& other) = default; // NOLINT(performance-noexcept-move-constructor) - ditto
|
|
|
|
// Deleted so nobody copies a ship class by accident; use clone() for a deliberate deep copy.
|
|
ship_info(const ship_info& other) = delete;
|
|
ship_info &operator=(const ship_info& other) = delete;
|
|
|
|
//Helper functions
|
|
|
|
inline bool is_small_ship() const { return flags.any_of(Ship::Info_Flags::Fighter,Ship::Info_Flags::Bomber,Ship::Info_Flags::Support,Ship::Info_Flags::Escapepod); }
|
|
inline bool is_big_ship() const { return flags.any_of(Ship::Info_Flags::Cruiser,Ship::Info_Flags::Freighter,Ship::Info_Flags::Transport,Ship::Info_Flags::Corvette,Ship::Info_Flags::Gas_miner,Ship::Info_Flags::Awacs); }
|
|
inline bool is_huge_ship() const { return flags.any_of(Ship::Info_Flags::Capital,Ship::Info_Flags::Supercap,Ship::Info_Flags::Drydock,Ship::Info_Flags::Knossos_device); }
|
|
inline bool is_flyable() const { return flags.none_of(Ship::Info_Flags::Cargo,Ship::Info_Flags::Navbuoy,Ship::Info_Flags::Sentrygun); } // AL 11-24-97: this useful to know for targeting reasons
|
|
// note: code that previously used is_harmless() / SIF_HARMLESS now uses several flags defined in objecttypes.tbl
|
|
// inline bool is_harmless() const { return flags[Ship::Info_Flags::Cargo, Ship::Info_Flags::Navbuoy, Ship::Info_Flags::Escapepod]; } // AL 12-3-97: ships that are not a threat
|
|
inline bool is_fighter_bomber() const { return flags.any_of(Ship::Info_Flags::Fighter,Ship::Info_Flags::Bomber); }
|
|
inline bool is_big_or_huge() const { return is_big_ship() || is_huge_ship(); }
|
|
inline bool avoids_shockwaves() const { return is_small_ship(); }
|
|
|
|
const char* get_display_name() const;
|
|
bool has_display_name() const;
|
|
|
|
};
|
|
|
|
extern flag_def_list_new<Ship::Info_Flags> Ship_flags[];
|
|
extern const size_t Num_ship_flags;
|
|
|
|
extern flag_def_list_new<Model::Subsystem_Flags> Subsystem_flags[];
|
|
extern const size_t Num_subsystem_flags;
|
|
|
|
extern int Num_wings;
|
|
extern ship Ships[MAX_SHIPS];
|
|
extern ship *Player_ship;
|
|
extern std::shared_ptr<model_texture_replace> Player_cockpit_textures;
|
|
|
|
// Data structure to track the active missiles
|
|
typedef struct ship_obj {
|
|
ship_obj *next, *prev;
|
|
int flags, objnum;
|
|
} ship_obj;
|
|
extern ship_obj Ship_obj_list;
|
|
|
|
typedef struct engine_wash_info
|
|
{
|
|
char name[NAME_LENGTH];
|
|
float angle; // half angle of cone around engine thruster
|
|
float radius_mult; // multiplier for radius
|
|
float length; // length of engine wash, measured from thruster
|
|
float intensity; // intensity of engine wash
|
|
|
|
} engine_wash_info;
|
|
|
|
extern SCP_vector<engine_wash_info> Engine_wash_info;
|
|
|
|
|
|
// Defines a wing of ships.
|
|
typedef struct wing {
|
|
char name[NAME_LENGTH];
|
|
SCP_string display_name;
|
|
|
|
char wing_squad_filename[MAX_FILENAME_LEN]; // Goober5000
|
|
int reinforcement_index; // index in reinforcement struct or -1
|
|
int hotkey;
|
|
|
|
// members for dealing with waves
|
|
int num_waves;
|
|
int current_wave; // NOTE: this is 1-based! As each wave arrives, this will reflect the counting number: Wave 1, Wave 2, etc.
|
|
int threshold; // when number of ships in the wing reaches this number -- new wave
|
|
|
|
fix time_gone; // time into the mission when this wing is officially gone.
|
|
|
|
int wave_count; // max ships per wave (as defined by the number of ships in the ships list)
|
|
int total_arrived_count; // count of number of ships that we have created, regardless of wave
|
|
int red_alert_skipped_ships; // Goober5000 - if we skipped over any indexes while creating red-alert ships
|
|
int current_count; // count of number of ships actually in this wing -- used for limit in next array
|
|
int ship_index[MAX_SHIPS_PER_WING]; // index into ships array of all ships currently in the wing
|
|
|
|
int total_destroyed; // total number of ships destroyed in the wing (including all waves)
|
|
int total_departed; // total number of ships departed in this wing (including all waves)
|
|
int total_vanished; // total number of ships vanished in this wing (including all waves)
|
|
|
|
int special_ship; // the leader of the wing. An index into ship_index[].
|
|
int special_ship_ship_info_index; // the ship info index of the special ship
|
|
|
|
ArrivalLocation arrival_location; // arrival and departure information for wings -- similar to info for ships
|
|
int arrival_distance; // distance from some ship where this ship arrives
|
|
anchor_t arrival_anchor; // ship registry index of object this wing arrives near (or in front of)
|
|
int arrival_path_mask; // Goober5000 - possible restrictions on which bay paths to use
|
|
int arrival_cue;
|
|
int arrival_delay;
|
|
|
|
DepartureLocation departure_location;
|
|
anchor_t departure_anchor; // ship registry index of object that we depart to (in case of dock bays)
|
|
int departure_path_mask; // Goober5000 - possible restrictions on which bay paths to use
|
|
int departure_cue;
|
|
int departure_delay;
|
|
|
|
int wave_delay_min; // minimum number of seconds before new wave can arrive
|
|
int wave_delay_max; // maximum number of seconds before new wave can arrive
|
|
TIMESTAMP wave_delay_timestamp; // timestamp used for delaying arrival of next wave
|
|
|
|
flagset<Ship::Wing_Flags> flags;
|
|
|
|
ai_goal ai_goals[MAX_AI_GOALS]; // goals for the wing -- converted to ai_goal struct
|
|
|
|
ushort net_signature; // starting net signature for ships in this wing. assiged at mission load time
|
|
|
|
// Goober5000 - if this wing has a unique squad logo
|
|
// it's specified for the wing rather than each individual ship to cut down on the amount
|
|
// of stuff that needs to be sitting in memory at once - each ship uses the wing texture;
|
|
// and it also makes practical sense: no wing has two different squadrons in it :)
|
|
int wing_insignia_texture;
|
|
|
|
// if -1, retail formation, else a custom one defined in ships.tbl
|
|
int formation;
|
|
float formation_scale;
|
|
|
|
// reset to a completely blank wing
|
|
void clear();
|
|
|
|
const char *get_display_name() const;
|
|
bool has_display_name() const;
|
|
} wing;
|
|
|
|
extern wing Wings[MAX_WINGS];
|
|
|
|
extern int Starting_wings[MAX_STARTING_WINGS];
|
|
extern int Squadron_wings[MAX_SQUADRON_WINGS];
|
|
extern int TVT_wings[MAX_TVT_WINGS];
|
|
|
|
extern char Starting_wing_names[MAX_STARTING_WINGS][NAME_LENGTH];
|
|
extern char Squadron_wing_names[MAX_SQUADRON_WINGS][NAME_LENGTH];
|
|
extern char TVT_wing_names[MAX_TVT_WINGS][NAME_LENGTH];
|
|
|
|
extern int ai_paused;
|
|
|
|
extern SCP_vector<ship_info> Ship_info;
|
|
extern SCP_vector<const char *> Ship_class_names;
|
|
|
|
extern SCP_vector<reinforcements> Reinforcements;
|
|
|
|
// structure definition for ship type counts. Used to give a count of the number of ships
|
|
// of a particular type, and the number of times that a ship of that particular type has been
|
|
// killed. When changing any info here, be sure to update the ship_type_names array in Ship.cpp
|
|
// the order of the types here MUST match the order of the types in the array
|
|
typedef struct ship_counts {
|
|
int total;
|
|
int killed;
|
|
ship_counts(){total=0;killed=0;}
|
|
} ship_counts;
|
|
|
|
extern SCP_vector<ship_counts> Ship_type_counts;
|
|
|
|
|
|
// Formations
|
|
typedef struct wing_formation {
|
|
char name[NAME_LENGTH];
|
|
std::array<vec3d, MAX_SHIPS_PER_WING - 1> positions; // does NOT include wing leader, so index 0 for each formation is the second in the wing, 1 is third, etc
|
|
} wing_formation;
|
|
|
|
extern SCP_vector<wing_formation> Wing_formations;
|
|
|
|
|
|
// Use the below macros when you want to find the index of an array element in the
|
|
// Wings[] or Ships[] arrays.
|
|
#define WING_INDEX(wingp) (static_cast<int>((wingp)-Wings))
|
|
#define SHIP_INDEX(shipp) (static_cast<int>((shipp)-Ships))
|
|
#define SHIP_REGISTRY_INDEX(ship_entry) (static_cast<int>((ship_entry)-Ship_registry.data()))
|
|
|
|
|
|
extern void ship_init(); // called once at game start
|
|
extern void ship_level_init(); // called before the start of each level
|
|
extern void ship_level_close(); // called after the end of each level
|
|
|
|
//returns -1 if failed
|
|
extern int ship_create(matrix* orient, vec3d* pos, int ship_type, const char* ship_name = nullptr, bool standalone_ship = false);
|
|
extern void change_ship_type(int n, int ship_type, int by_sexp = 0);
|
|
extern void ship_process_pre( object * objp, float frametime );
|
|
extern void ship_process_post( object * objp, float frametime );
|
|
extern void ship_render( object * obj, model_draw_list * scene );
|
|
// whether this ship class shows a cockpit at all: it has a cockpit model and the player hasn't turned cockpits off
|
|
extern bool ship_cockpit_enabled(const ship_info* sip);
|
|
// whether the cockpit model is rendered for this ship class when it is the viewer
|
|
extern bool ship_render_player_cockpit(const ship_info* sip);
|
|
// whether the viewer's cockpit is being rendered this frame
|
|
extern bool ship_render_player_cockpit_active();
|
|
extern bool ship_render_player_ship_casts_shadow_on_cockpit();
|
|
extern bool ship_render_player_has_closeup_visuals();
|
|
// The cockpit model's render offset: sip->cockpit_offset rotated into world orientation,
|
|
// plus acceleration-driven sway (unless Disable_cockpit_sway). This is the camera-relative
|
|
// offset used to draw the cockpit model, NOT combined with objp->pos -- callers that need
|
|
// a world-space position must add objp->pos themselves. Shared by every path that draws or
|
|
// otherwise anchors the cockpit model: ship_render_player_ship(), render_viewer_shadow()
|
|
// (shadows.cpp), and gatherCockpitShadowCasterInstance() (VulkanRaytracingTlas.cpp).
|
|
extern vec3d ship_cockpit_render_offset(const ship_info* sip, const object* objp);
|
|
extern void ship_render_player_ship( object * objp, const vec3d* offset = nullptr, const matrix* rot_offset = nullptr, const fov_t* fov_override = nullptr);
|
|
extern void ship_delete( object * objp );
|
|
extern int ship_check_collision_fast( object * obj, object * other_obj, vec3d * hitpos );
|
|
extern int ship_get_num_ships();
|
|
|
|
#define SHIP_VANISHED (1<<0)
|
|
#define SHIP_DESTROYED (1<<1)
|
|
#define SHIP_DEPARTED_WARP (1<<2)
|
|
#define SHIP_DEPARTED_BAY (1<<3)
|
|
#define SHIP_DEPARTED ( SHIP_DEPARTED_BAY | SHIP_DEPARTED_WARP )
|
|
#define SHIP_DESTROYED_REDALERT (1<<4)
|
|
#define SHIP_DEPARTED_REDALERT (1<<5)
|
|
#define SHIP_PRESENT_AT_MISSION_END (1<<6)
|
|
|
|
/**
|
|
* @brief Deletes and de-inits a ship.
|
|
*
|
|
* @param[in] shipnum Index of this ship in Ships[]
|
|
* @param[in] cleanup_mode Flags describing how this ship is to be removed. See SHIP_VANISHED, SHIP_DESTROYED, etc.
|
|
*
|
|
* @details This is the deconstructor of a ship, it does all the necassary processes to remove the ship from the Ships
|
|
* array, and frees the slot for use by others. De-init of its Objects[] slot is handled by obj_delete_all_that_should_be_dead().
|
|
*
|
|
* @author Goober5000
|
|
* @sa obj_delete_all_that_should_be_dead()
|
|
*/
|
|
extern void ship_cleanup(int shipnum, int cleanup_mode);
|
|
|
|
// Goober5000
|
|
extern void ship_destroy_instantly(object *ship_obj, bool with_debris = false);
|
|
extern void ship_actually_depart(int shipnum, int method = SHIP_DEPARTED_WARP);
|
|
|
|
extern bool in_autoaim_fov(ship *shipp, int bank_to_fire, object *obj);
|
|
extern int ship_stop_fire_primary(object * obj);
|
|
extern int ship_fire_primary(object * objp, int force = 0, bool rollback_shot = false);
|
|
extern vec3d ship_get_external_model_fp_offset(external_weapon_state *ext, const weapon_info *wip, const polymodel *weapon_model, const w_bank *ship_bank, int slot, bool advance_counter, int sub_shot = 0);
|
|
extern void ship_get_weapon_model_slot_transform(const w_bank *bank, int slot, float reload_slide_back, vec3d *outpnt, matrix *outorient);
|
|
extern int ship_get_external_weapon_model_instance(ship_weapon *swp, int bank, int display_model_num);
|
|
extern int ship_fire_secondary(object * objp, int allow_swarm = 0, bool rollback_shot = false );
|
|
extern bool ship_secondary_bank_can_dual_fire(const ship *shipp, int bank);
|
|
bool ship_start_secondary_fire(object* objp);
|
|
bool ship_stop_secondary_fire(object* objp);
|
|
extern int ship_launch_countermeasure(object *objp, int rand_val = -1);
|
|
|
|
// for special targeting lasers
|
|
extern void ship_process_targeting_lasers();
|
|
|
|
extern bool ship_select_next_primary(object *objp, CycleDirection direction);
|
|
extern int ship_select_next_secondary(object *objp);
|
|
|
|
// Goober5000
|
|
extern int get_available_primary_weapons(object *objp, int *outlist, int *outbanklist);
|
|
|
|
extern int get_available_secondary_weapons(object *objp, int *outlist, int *outbanklist);
|
|
extern void ship_recalc_subsys_strength( ship *shipp );
|
|
|
|
// switch a subsystem's looping sounds between its alive and dead sets, according to its hitpoints
|
|
extern void ship_update_subsys_sounds(const ship *shipp, ship_subsys *ss);
|
|
extern void physics_ship_init(object *objp);
|
|
|
|
// Note: This is not a general purpose routine.
|
|
// It is specifically used for targeting.
|
|
// Return true/false for subsystem found/not found.
|
|
// Stuff vector *pos with absolute position.
|
|
extern int get_subsystem_pos(vec3d *pos, const object *objp, const ship_subsys *subsysp);
|
|
|
|
extern int ship_info_lookup(const char *name);
|
|
extern int ship_name_lookup(const char *name, int inc_players = 0); // returns the index into Ship array of name
|
|
extern int ship_type_name_lookup(const char *name);
|
|
|
|
inline int ship_info_size()
|
|
{
|
|
return static_cast<int>(Ship_info.size());
|
|
}
|
|
|
|
extern int wing_lookup(const char *name);
|
|
extern int wing_formation_lookup(const char *formation_name);
|
|
|
|
// returns 0 if no conflict, 1 if conflict, -1 on some kind of error with wing struct
|
|
extern int wing_has_conflicting_teams(int wing_index);
|
|
|
|
// next function takes optional second parameter which says to ignore the current count of ships
|
|
// in the wing -- used to tell is the wing exists or not, not whether it exists and has ships currently
|
|
// present.
|
|
extern int wing_name_lookup(const char *name, int ignore_count = 0);
|
|
|
|
extern bool wing_has_yet_to_arrive(const wing *wingp);
|
|
|
|
// for generating a ship name for arbitrary waves/indexes of that wing
|
|
extern void wing_bash_ship_name(SCP_string &ship_name, const char *wing_name, int ordinal);
|
|
extern void wing_bash_ship_name(char *ship_name, const char *wing_name, int ordinal);
|
|
extern void wing_bash_ship_name(p_object *p_objp, const wing *wingp, int ordinal, bool reset_display_name_if_normal = false);
|
|
extern void wing_bash_ship_name(ship *shipp, const wing *wingp, int ordinal, bool reset_display_name_if_normal = false);
|
|
extern bool wing_bash_legacy_hashed_ship_name(SCP_string &dest, const char *src);
|
|
|
|
extern int Player_ship_class;
|
|
|
|
// Do the special effect for energy dissipating into the shield for a hit.
|
|
// model_num = index in Polygon_models[]
|
|
// centerp = pos of object, sort of the center of the shield
|
|
// tcp = hit point, probably the global hit_point set in polygon_check_face
|
|
// tr0 = index of polygon in shield pointer in polymodel.
|
|
extern void create_shield_explosion(int objnum, int model_num, matrix *orient, vec3d *centerp, vec3d *tcp, int tr0);
|
|
|
|
// Initialize shield hit system.
|
|
extern void shield_hit_init();
|
|
extern void create_shield_explosion_all(object *objp);
|
|
extern void shield_frame_init();
|
|
extern void add_shield_point(int objnum, int tri_num, const vec3d *hit_pos, float radius_override);
|
|
extern void add_shield_point_multi(int objnum, int tri_num, vec3d *hit_pos);
|
|
extern void shield_point_multi_setup();
|
|
extern void shield_hit_close();
|
|
|
|
float ship_shield_hitpoint_threshold(const object* obj, bool all_quadrants = false);
|
|
bool ship_is_shield_up(const object *obj, int quadrant);
|
|
|
|
//=================================================
|
|
void ship_model_replicate_submodels(object *objp);
|
|
|
|
//============================================
|
|
extern int ship_find_num_crewpoints(object *objp);
|
|
extern int ship_find_num_turrets(object *objp);
|
|
|
|
extern void compute_slew_matrix(matrix *orient, angles *a);
|
|
extern void object_get_eye(vec3d *eye_pos, matrix *eye_orient, const object *obj, bool do_slew = true, bool local_pos = false, bool local_orient = false);
|
|
|
|
extern ship_subsys *ship_find_first_subsys(ship *sp, int subsys_type, const vec3d *attacker_pos = nullptr);
|
|
extern ship_subsys *ship_get_indexed_subsys(ship *sp, int index); // returns index'th subsystem of this ship
|
|
extern int ship_find_subsys(const ship *sp, const char *ss_name); // returns numerical index in linked list of subsystems
|
|
extern int ship_get_subsys_index(const ship_subsys *subsys);
|
|
|
|
extern bool ship_subsystems_blown(const ship *shipp, int type, bool skip_dying_check = false);
|
|
extern float ship_get_subsystem_strength(const ship *shipp, int type, bool skip_dying_check = false, bool no_minimum_engine_str = false);
|
|
extern ship_subsys *ship_get_subsys(const ship *shipp, const char *subsys_name);
|
|
extern int ship_get_num_subsys(const ship *shipp);
|
|
extern ship_subsys *ship_get_closest_subsys_in_sight(const ship *sp, int subsys_type, const vec3d *attacker_pos);
|
|
|
|
//WMC
|
|
const char *ship_subsys_get_name(const ship_subsys *ss);
|
|
bool ship_subsys_has_instance_name(const ship_subsys *ss);
|
|
void ship_subsys_set_name(ship_subsys* ss, const char* n_name);
|
|
|
|
const char *ship_subsys_get_name_on_hud(const ship_subsys *ss);
|
|
const char *ship_subsys_get_canonical_name(const ship_subsys *ss);
|
|
|
|
// subsys disruption
|
|
extern int ship_subsys_disrupted(const ship_subsys *ss);
|
|
extern int ship_subsys_disrupted(const ship *sp, int type);
|
|
extern void ship_subsys_set_disrupted(ship_subsys *ss, int time);
|
|
|
|
extern int ship_do_rearm_frame( object *objp, float frametime );
|
|
extern float ship_calculate_rearm_duration( object *objp );
|
|
extern void ship_wing_cleanup( int shipnum, wing *wingp );
|
|
extern void wing_maybe_cleanup( wing *wingp, int team = -1 );
|
|
|
|
extern int ship_find_repair_ship( object *requester_obj, object **ship_we_found = NULL );
|
|
extern void ship_close(); // called in game_shutdown() to free malloced memory
|
|
|
|
|
|
extern void ship_assign_sound_all();
|
|
extern void ship_assign_sound(ship *sp);
|
|
|
|
extern void ship_clear_ship_type_counts();
|
|
extern void ship_add_ship_type_count( int ship_info_index, int num );
|
|
|
|
extern const char *ship_get_type(const ship_info *sip);
|
|
extern const SCP_set<size_t>& ship_get_default_orders_accepted( ship_info *sip );
|
|
extern SCP_set<size_t> ship_get_default_orders_against();
|
|
extern int ship_query_general_type(int ship);
|
|
extern int ship_class_query_general_type(int ship_class);
|
|
extern int ship_query_general_type(ship *shipp);
|
|
extern int ship_docking_valid(int docker, int dockee);
|
|
extern int get_quadrant(const vec3d *hit_pnt, const object *shipobjp = nullptr); // Return quadrant num of given hit point.
|
|
|
|
int ship_secondary_bank_has_ammo(int shipnum); // check if current secondary bank has ammo
|
|
|
|
int ship_engine_ok_to_warp(ship *sp); // check if ship has engine power to warp
|
|
int ship_navigation_ok_to_warp(ship *sp); // check if ship has navigation power to warp
|
|
bool ship_can_warp_full_check(ship *sp); // checks both the warp flags and ship_engine_ok_to_warp() and ship_navigation_ok_to_warp() --wookieejedi
|
|
bool ship_can_bay_depart(ship *sp); // checks to see if a ship has a departure location as a bay and if the mothership is present
|
|
|
|
int ship_return_subsys_path_normal(const ship *sp, const ship_subsys *ss, const vec3d *gsubpos, vec3d *norm);
|
|
bool ship_subsystem_in_sight(const object *objp, const ship_subsys *subsys, const vec3d *eye_pos, const vec3d *subsys_pos, bool do_facing_check = true, float *dot_out = nullptr, vec3d *vec_out = nullptr);
|
|
ship_subsys *ship_return_next_subsys(ship *shipp, int type, vec3d *attacker_pos);
|
|
|
|
// defines and definition for function to get a random ship of a particular team (any ship,
|
|
// any ship but player ships, or only players)
|
|
#define SHIP_GET_ANY_SHIP 0
|
|
#define SHIP_GET_NO_PLAYERS 1
|
|
#define SHIP_GET_ONLY_PLAYERS 2
|
|
#define SHIP_GET_UNSILENCED 3 // Karajorma - Returns no_players that can send builtin messages.
|
|
|
|
|
|
extern int ship_get_random_team_ship(int team_mask, int flags = SHIP_GET_ANY_SHIP, float max_dist = 0.0f);
|
|
extern int ship_get_random_player_wing_ship(int flags = SHIP_GET_ANY_SHIP, float max_dist = 0.0f, int persona_index = -1, int get_first = 0, int multi_team = -1);
|
|
extern int ship_get_random_ship_in_wing(int wingnum, int flags = SHIP_GET_ANY_SHIP, float max_dist = 0.0f, int get_first = 0, int order_id = -1);
|
|
|
|
// return ship index
|
|
int ship_get_random_targetable_ship();
|
|
|
|
extern int ship_get_by_signature(int signature);
|
|
|
|
#ifndef NDEBUG
|
|
extern int Ai_render_debug_flag;
|
|
extern int Show_shield_mesh;
|
|
extern int Ship_auto_repair; // flag to indicate auto-repair of subsystem should occur
|
|
#endif
|
|
|
|
int ship_dumbfire_threat(ship *sp);
|
|
int ship_lock_threat(ship *sp);
|
|
|
|
int bitmask_2_bitnum(int num);
|
|
SCP_string ship_return_orders(ship *sp);
|
|
char *ship_return_time_to_goal(char *outbuf, ship *sp);
|
|
int ship_return_seconds_to_goal(ship *sp);
|
|
|
|
void ship_maybe_warn_player(ship *enemy_sp, float dist);
|
|
void ship_maybe_praise_player(ship *deader_sp);
|
|
void ship_maybe_praise_self(ship *deader_sp, ship *killer_sp);
|
|
void ship_maybe_ask_for_help(ship *sp, ship *attacker);
|
|
void ship_scream(ship *sp);
|
|
void ship_maybe_scream(ship *sp);
|
|
void ship_maybe_tell_about_rearm(ship *sp);
|
|
void ship_maybe_tell_about_low_ammo(ship *sp);
|
|
void ship_maybe_lament();
|
|
|
|
void ship_primary_changed(ship *sp);
|
|
void ship_secondary_changed(ship *sp);
|
|
|
|
// get the Ship_info flags for a given ship
|
|
flagset<Ship::Info_Flags> ship_get_SIF(ship *shipp);
|
|
flagset<Ship::Info_Flags> ship_get_SIF(int sh);
|
|
|
|
// get the ship type info (objecttypes.tbl)
|
|
ship_type_info *ship_get_type_info(object *objp);
|
|
|
|
extern void ship_do_cargo_revealed( ship *shipp, int from_network = 0 );
|
|
extern void ship_do_cargo_hidden( ship *shipp, int from_network = 0 );
|
|
extern void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network = 0);
|
|
extern void ship_do_cap_subsys_cargo_hidden( ship *shipp, ship_subsys *subsys, int from_network = 0);
|
|
|
|
float ship_get_secondary_weapon_range(ship *shipp);
|
|
|
|
// Goober5000
|
|
int get_max_ammo_count_for_primary_bank(int ship_class, int bank, int ammo_type);
|
|
int get_max_ammo_count_for_primary_turret_bank(ship_weapon* swp, int bank, int ammo_type);
|
|
|
|
|
|
int get_max_ammo_count_for_bank(int ship_class, int bank, int ammo_type);
|
|
int get_max_ammo_count_for_turret_bank(ship_weapon *swp, int bank, int ammo_type);
|
|
|
|
int is_support_allowed(object *objp, bool do_simple_check = false);
|
|
|
|
// Given an object and a turret on that object, return the actual firing point of the gun
|
|
// and its normal. This uses the current turret angles. We are keeping track of which
|
|
// gun to fire next in the ship specific info for this turret subobject. Use this info
|
|
// to determine which position to fire from next.
|
|
// Stuffs:
|
|
// *gpos: absolute position of gun firing point
|
|
// *gvec: vector fro *gpos to *targetp
|
|
void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp, vec3d *gpos, bool avg_origin, vec3d *gvec, bool use_angles, const vec3d *targetp);
|
|
|
|
// Given an object and a turret on that object, return the global position and forward vector
|
|
// of the turret. The gun normal is the unrotated gun normal, (the center of the FOV cone), not
|
|
// the actual gun normal given using the current turret heading. But it _is_ rotated into the model's orientation
|
|
// in global space.
|
|
void ship_get_global_turret_info(const object *objp, const model_subsystem *tp, vec3d *gpos, vec3d *gvec);
|
|
|
|
// return 1 if objp is in fov of the specified turret, tp. Otherwise return 0.
|
|
// dist = distance from turret to center point of object
|
|
bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d *tvec, const vec3d *tpos, float dist);
|
|
|
|
// functions for testing fov.. returns true if fov test is passed.
|
|
bool turret_std_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod = 0);
|
|
bool turret_adv_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod = 0);
|
|
bool turret_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod = 0);
|
|
|
|
// function for checking adjusted turret rof
|
|
float get_adjusted_turret_rof(ship_subsys *ss);
|
|
|
|
// forcible jettison cargo from a ship
|
|
void object_jettison_cargo(object *objp, object *cargo_objp, float jettison_speed, bool jettison_new);
|
|
|
|
// get damage done by exploding ship, takes into account mods for individual ship
|
|
float ship_get_exp_damage(object* objp);
|
|
|
|
// get outer radius of damage, takes into account mods for individual ship
|
|
float ship_get_exp_outer_rad(object *ship_objp);
|
|
|
|
// externed by Goober5000
|
|
extern int ship_explode_area_calc_damage( vec3d *pos1, vec3d *pos2, float inner_rad, float outer_rad, float max_damage, float max_blast, float *damage, float *blast );
|
|
|
|
// determine turret status of a given subsystem, returns 0 for no turret, 1 for "fixed turret", 2 for "rotating" turret
|
|
int ship_get_turret_type(ship_subsys *subsys);
|
|
|
|
// get ship by object signature, returns OBJECT INDEX
|
|
int ship_get_by_signature(int sig);
|
|
|
|
// get the team of a reinforcement item
|
|
int ship_get_reinforcement_team(const reinforcements &reinforcement);
|
|
|
|
// page in bitmaps for all ships on a given level
|
|
void ship_page_in();
|
|
|
|
// Goober5000 - helper for above
|
|
void ship_page_in_textures(int ship_index = -1);
|
|
|
|
// fixer for above - taylor
|
|
void ship_page_out_textures(int ship_index, bool release = false);
|
|
|
|
// replaces a texture on a ship with a different texture
|
|
void ship_replace_active_texture(int ship_index, const char* old_name, const char* new_name);
|
|
|
|
// update artillery lock info
|
|
void ship_update_artillery_lock();
|
|
|
|
// checks if a world point is inside the extended bounding box of a ship
|
|
int check_world_pt_in_expanded_ship_bbox(const vec3d *world_pt, const object *objp, float delta_box);
|
|
|
|
// returns true if objp is ship and is tagged
|
|
int ship_is_tagged(object *objp);
|
|
|
|
// returns max normal speed of ship (overclocked / afterburned)
|
|
float ship_get_max_speed(ship *shipp);
|
|
|
|
// returns warpout speed of ship
|
|
float ship_get_warpout_speed(object *objp, ship_info *sip = nullptr, float half_length = 0.0f, float warping_dist = 0.0f);
|
|
|
|
// returns true if ship is beginning to speed up in warpout
|
|
int ship_is_beginning_warpout_speedup(object *objp);
|
|
|
|
// return the length of the ship class
|
|
float ship_class_get_length(const ship_info *sip);
|
|
|
|
// return the actual center of the ship class
|
|
void ship_class_get_actual_center(const ship_info *sip, vec3d *center_pos);
|
|
|
|
// Goober5000 - used by change-ai-class
|
|
extern void ship_set_new_ai_class(ship *shipp, int new_ai_class);
|
|
extern void ship_subsystem_set_new_ai_class(ship_subsys *ss, int new_ai_class);
|
|
|
|
// wing squad logos - Goober5000
|
|
extern void wing_load_squad_bitmap(wing *w);
|
|
|
|
// Goober5000 - needed by new hangar depart code
|
|
extern bool ship_has_hangar_bay(int shipnum);
|
|
extern bool ship_useful_for_departure(int shipnum, int path_mask = 0);
|
|
extern int ship_get_ship_for_departure(int team);
|
|
|
|
// Goober5000
|
|
extern bool ship_fighterbays_all_destroyed(ship *shipp);
|
|
|
|
// Goober5000
|
|
extern bool ship_subsys_takes_damage(ship_subsys *ss);
|
|
|
|
// Goober5000 - handles submodel rotation for subsystems, excluding turrets
|
|
extern void ship_move_subsystems(object *objp);
|
|
|
|
// Goober5000 - shortcut hud stuff
|
|
extern int ship_has_energy_weapons(ship *shipp);
|
|
extern int ship_has_engine_power(ship *shipp);
|
|
|
|
// Swifty - Cockpit displays
|
|
void ship_init_cockpit_displays(ship *shipp);
|
|
void ship_close_cockpit_displays(ship* shipp);
|
|
int ship_start_render_cockpit_display(size_t cockpit_display_num);
|
|
void ship_end_render_cockpit_display(size_t cockpit_display_num);
|
|
|
|
// Goober5000
|
|
int ship_starting_wing_lookup(const char *wing_name);
|
|
int ship_squadron_wing_lookup(const char *wing_name);
|
|
int ship_tvt_wing_lookup(const char *wing_name);
|
|
|
|
// Goober5000
|
|
int ship_class_compare(int ship_class_1, int ship_class_2);
|
|
|
|
int armor_type_get_idx(const char* name);
|
|
|
|
void armor_init();
|
|
|
|
// Sushi - Path metadata
|
|
void init_path_metadata(path_metadata& metadata);
|
|
|
|
|
|
typedef struct ship_effect {
|
|
char name[NAME_LENGTH];
|
|
bool disables_rendering;
|
|
bool invert_timer;
|
|
int shader_effect;
|
|
} ship_effect;
|
|
|
|
extern SCP_vector<ship_effect> Ship_effects;
|
|
|
|
/**
|
|
* @brief Returns a ship-specific sound index
|
|
*
|
|
* @param objp An object pointer. Has to be of type OBJ_SHIP
|
|
* @param id A sound id as defined in gamsesnd.h. If the given id is unknown then the game_snd with the id as index is returned.
|
|
*
|
|
* @return An index into the Snds vector, if the specified index could not be found then the id itself will be returned
|
|
*/
|
|
gamesnd_id ship_get_sound(object *objp, GameSounds id);
|
|
|
|
/**
|
|
* @brief Specifies if a ship has a custom sound for the specified id
|
|
*
|
|
* @param objp An object pointer. Has to be of type OBJ_SHIP
|
|
* @param id A sound id as defined in gamsesnd.h
|
|
*
|
|
* @return True if this object has the specified sound, false otherwise
|
|
*/
|
|
bool ship_has_sound(object *objp, GameSounds id);
|
|
|
|
/**
|
|
* @brief Returns the index of the default player ship
|
|
*
|
|
* @return An index into Ship_info[], location of the default player ship.
|
|
*/
|
|
int get_default_player_ship_index();
|
|
|
|
/**
|
|
* Given a ship with bounding box and a point, find the closest point on the bbox
|
|
*
|
|
* @param ship_obj Object that has the bounding box (should be a ship)
|
|
* @param start World position of the point being compared
|
|
* @param box_pt OUTPUT PARAMETER: closest point on the bbox to start
|
|
*
|
|
* @return point is inside bbox, TRUE/1
|
|
* @return point is outside bbox, FALSE/0
|
|
*/
|
|
int get_nearest_bbox_point(const object *ship_obj, const vec3d *start, vec3d *box_pt);
|
|
|
|
extern flagset<Ship::Ship_Flags> Ignore_List;
|
|
inline bool should_be_ignored(ship* shipp) {
|
|
return (shipp->flags & Ignore_List).any_set();
|
|
}
|
|
|
|
extern void set_default_ignore_list();
|
|
|
|
extern void toggle_ignore_list_flag(Ship::Ship_Flags flag);
|
|
|
|
ship_subsys* ship_get_subsys_for_submodel(ship* shipp, int submodel);
|
|
|
|
// Clears a lock_info struct with defaults
|
|
void ship_clear_lock(lock_info *slot);
|
|
|
|
// queues up locks
|
|
void ship_queue_missile_locks(ship *shipp);
|
|
|
|
// snoops missile locks to see if any are ready to fire.
|
|
bool ship_lock_present(ship *shipp);
|
|
|
|
bool ship_secondary_has_ammo(ship_weapon* swp, int bank_index);
|
|
|
|
// Used to check if one ship can see the other on radar
|
|
int ship_check_visibility(const ship* viewed, ship* viewer);
|
|
|
|
// Find the first available arc slot. If none is available, and no_create is false, add one.
|
|
ship_electrical_arc *ship_find_or_create_electrical_arc_slot(ship *shipp, bool no_create);
|
|
|
|
#endif
|