Skip to content

Commit

Permalink
make fireball types dynamic
Browse files Browse the repository at this point in the history
As requested by Event Horizon, this removes the limit on fireball types.  The fixed array has been replaced with a vector and the relevant code updated accordingly.  There is also a new version of `stuff_int_list()` to parse ints into a vector.

This also adds bounds checking for explosion animations that are parsed for ship classes, ship types, and asteroids, since previously there was no guarantee that the indexes would be in range.
  • Loading branch information
Goober5000 committed Apr 26, 2024
1 parent 289d0b6 commit 3851832
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 94 deletions.
10 changes: 3 additions & 7 deletions code/asteroid/asteroid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1593,9 +1593,8 @@ static float asteroid_create_explosion(object *objp)
fireball_type = FIREBALL_ASTEROID;
}

if (fireball_type >= Num_fireball_types) {
Warning(LOCATION, "Invalid fireball type %i specified for an asteroid, only %i fireball types are defined.", fireball_type, Num_fireball_types);

if (fireball_type >= static_cast<int>(Fireball_info.size())) {
Warning(LOCATION, "Invalid fireball type %i specified for an asteroid; only " SIZE_T_ARG " fireball types are defined.", fireball_type, Fireball_info.size());
return 0;
}

Expand Down Expand Up @@ -2251,10 +2250,7 @@ static void asteroid_parse_section()
}

if(optional_string("$Explosion Animations:")){
int temp[MAX_FIREBALL_TYPES];
auto parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
asteroid_p->explosion_bitmap_anims.clear();
asteroid_p->explosion_bitmap_anims.insert(asteroid_p->explosion_bitmap_anims.begin(), temp, temp + parsed_ints);
stuff_fireball_index_list(asteroid_p->explosion_bitmap_anims, asteroid_p->name);
}

if (optional_string("$Explosion Radius Mult:")) {
Expand Down
72 changes: 38 additions & 34 deletions code/fireball/fireballs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ constexpr int INTITIAL_FIREBALL_CONTAINTER_SIZE = 256;
SCP_vector<fireball> Fireballs;
SCP_vector<int> Unused_fireball_indices;

fireball_info Fireball_info[MAX_FIREBALL_TYPES];

int fireball_used[MAX_FIREBALL_TYPES];

int Num_fireball_types = 0;
SCP_vector<fireball_info> Fireball_info;

bool fireballs_inited = false;
bool fireballs_parsed = false;
Expand Down Expand Up @@ -120,7 +116,7 @@ void fireball_play_warphole_close_sound(fireball *fb)

static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
{
Assert((fireball_index >= 0) && (fireball_index < MAX_FIREBALL_TYPES));
Assertion(SCP_vector_inbounds(Fireball_info, fireball_index), "fireball_index is out of bounds!");

switch (fireball_index)
{
Expand Down Expand Up @@ -164,7 +160,7 @@ static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fir
*/
static void fireball_set_default_color(int idx)
{
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
Assertion(SCP_vector_inbounds(Fireball_info, idx), "idx is out of bounds!");

switch (idx)
{
Expand Down Expand Up @@ -200,7 +196,7 @@ static void fireball_set_default_color(int idx)

static void fireball_set_default_warp_attributes(int idx)
{
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
Assertion(SCP_vector_inbounds(Fireball_info, idx), "idx is out of bounds!");

switch (idx)
{
Expand Down Expand Up @@ -232,9 +228,9 @@ void fireball_info_clear(fireball_info *fb)

int fireball_info_lookup(const char *unique_id)
{
for (int i = 0; i < Num_fireball_types; ++i)
for (size_t i = 0; i < Fireball_info.size(); ++i)
if (!stricmp(Fireball_info[i].unique_id, unique_id))
return i;
return static_cast<int>(i);

return -1;
}
Expand Down Expand Up @@ -308,25 +304,19 @@ static void parse_fireball_tbl(const char *table_filename)
// we are creating a new entry, so set some defaults
else
{
// make sure we don't exceed the max
if (Num_fireball_types >= MAX_FIREBALL_TYPES)
{
error_display(0, "Too many fireball entries! Max is %d", MAX_FIREBALL_TYPES);
return;
}

fi = &Fireball_info[Num_fireball_types];
int new_fireball_index = static_cast<int>(Fireball_info.size());
Fireball_info.emplace_back();
fi = &Fireball_info.back();
fireball_info_clear(fi);

// If the table didn't specify a unique ID, generate one. This will be assigned a few lines later.
if (strlen(unique_id) == 0)
fireball_generate_unique_id(unique_id, NAME_LENGTH, Num_fireball_types);
fireball_generate_unique_id(unique_id, NAME_LENGTH, new_fireball_index);

// Set remaining fireball defaults
fireball_set_default_color(Num_fireball_types);
fireball_set_default_warp_attributes(Num_fireball_types);
fireball_set_default_color(new_fireball_index);
fireball_set_default_warp_attributes(new_fireball_index);

Num_fireball_types++;
first_time = true;
}

Expand Down Expand Up @@ -399,9 +389,9 @@ void fireball_parse_tbl()
if (fireballs_parsed)
return;

// every newly parsed fireball_info will get cleared before being added
// must do this outside of parse_fireball_tbl because it's called twice
Num_fireball_types = 0;
// every newly parsed fireball_info will get cleared before being added;
// must clear the vector outside of parse_fireball_tbl because it's called more than once
Fireball_info.clear();

parse_fireball_tbl("fireball.tbl");

Expand Down Expand Up @@ -436,10 +426,11 @@ void fireball_parse_tbl()

void fireball_load_data()
{
int i, idx;
int i, n, idx;
fireball_info *fd;

for ( i = 0; i < Num_fireball_types; i++ ) {
n = static_cast<int>(Fireball_info.size());
for ( i = 0; i < n; i++ ) {
fd = &Fireball_info[i];

for(idx=0; idx<fd->lod_count; idx++){
Expand Down Expand Up @@ -798,8 +789,7 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
object *obj;
fireball_info *fd;
fireball_lod *fl;
Assert( fireball_type > -1 );
Assert( fireball_type < Num_fireball_types );
Assertion(SCP_vector_inbounds(Fireball_info, fireball_type), "fireball_type is out of bounds!");

fd = &Fireball_info[fireball_type];

Expand Down Expand Up @@ -946,13 +936,14 @@ void fireball_close()

void fireballs_page_in()
{
int i, idx;
int i, n, idx;
fireball_info *fd;

for ( i = 0; i < Num_fireball_types; i++ ) {
n = static_cast<int>(Fireball_info.size());
for ( i = 0; i < n; i++ ) {
fd = &Fireball_info[i];

if((i < NUM_DEFAULT_FIREBALLS) || fireball_used[i]) {
if ((i < NUM_DEFAULT_FIREBALLS) || fd->fireball_used) {
// if this is a Knossos ani, only load if Knossos_warp_ani_used is true
if ( (i == FIREBALL_KNOSSOS) && !Knossos_warp_ani_used)
continue;
Expand Down Expand Up @@ -984,8 +975,8 @@ void fireball_get_color(int idx, float *red, float *green, float *blue)
{
Assert( red && blue && green );

if ( (idx < 0) || (idx >= Num_fireball_types) ) {
Int3();
if (!SCP_vector_inbounds(Fireball_info, idx)) {
UNREACHABLE("idx is out of bounds!");

*red = 1.0f;
*green = 1.0f;
Expand Down Expand Up @@ -1120,3 +1111,16 @@ int fireball_get_count()

return count;
}

void stuff_fireball_index_list(SCP_vector<int> &list, const char *name)
{
stuff_int_list(list, RAW_INTEGER_TYPE);

list.erase(std::remove_if(list.begin(), list.end(), [&](int index) {
if (!SCP_vector_inbounds(Fireball_info, index)) {
Warning(LOCATION, "Fireball index %d for %s was out of bounds. Removing this index.", index, name);
return true;
}
return false;
}), list.end());
}
10 changes: 5 additions & 5 deletions code/fireball/fireballs.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,12 @@ class asteroid_info;
#define FIREBALL_EXPLOSION_LARGE1 4 // Used for the big explosion when a ship breaks into pieces
#define FIREBALL_EXPLOSION_LARGE2 5 // Used for the big explosion when a ship breaks into pieces

#define MAX_FIREBALL_TYPES 32 // The maximum number of fireballs that can be defined
#define NUM_DEFAULT_FIREBALLS 6

#define MAX_FIREBALL_LOD 4

#define FIREBALL_NUM_LARGE_EXPLOSIONS 2

extern int fireball_used[MAX_FIREBALL_TYPES];

// all this moved here by Goober5000 because it makes more sense in the H file
typedef struct fireball_lod {
char filename[MAX_FILENAME_LEN];
Expand All @@ -57,6 +54,7 @@ typedef struct fireball_info {
float exp_color[3]; // red, green, blue

bool use_3d_warp;
bool fireball_used;

char warp_glow[NAME_LENGTH];
int warp_glow_bitmap;
Expand All @@ -66,8 +64,7 @@ typedef struct fireball_info {
int warp_model_id;
} fireball_info;

extern fireball_info Fireball_info[MAX_FIREBALL_TYPES];
extern int Num_fireball_types;
extern SCP_vector<fireball_info> Fireball_info;

// flag values for fireball struct flags member
#define FBF_WARP_CLOSE_SOUND_PLAYED (1<<0)
Expand Down Expand Up @@ -153,4 +150,7 @@ extern bool Fireball_warp_flash;
// Cyborg - get a count of how many valid fireballs are in the mission.
int fireball_get_count();

// Goober5000 - stuffs fireballs and checks that indexes are in bounds
void stuff_fireball_index_list(SCP_vector<int> &list, const char *name);

#endif /* _FIREBALLS_H */
4 changes: 2 additions & 2 deletions code/hud/hudartillery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ void parse_ssm(const char *filename)
{
int temp = atoi(unique_id);

if ((temp < 0) || (temp >= Num_fireball_types))
error_display(0, "Fireball index [%d] out of range (should be 0-%d) for SSM strike [%s]", temp, Num_fireball_types - 1, s->name);
if (!SCP_vector_inbounds(Fireball_info, temp))
error_display(0, "Fireball index [%d] out of range (should be 0-%d) for SSM strike [%s]", temp, static_cast<int>(Fireball_info.size()) - 1, s->name);
else
s->fireball_type = temp;
}
Expand Down
35 changes: 28 additions & 7 deletions code/parse/parselo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3064,13 +3064,16 @@ const char* get_lookup_type_name(int lookup_type)
return "Unknown lookup type, tell a coder!";
}

// Stuffs an integer list.
// This is of the form ( i* )
// where i is an integer.
// For example, (1) () (1 2 3) ( 1 ) are legal integer lists.
size_t stuff_int_list(int *ilp, size_t max_ints, int lookup_type)
// use a functor here so that we don't need to re-roll the parsing function for both variants of stuff_int_lists
struct StuffIntListParser
{
return stuff_token_list(ilp, max_ints, [&](int *buf)->bool {
int lookup_type;

StuffIntListParser(int _lookup_type)
: lookup_type(_lookup_type)
{}

bool operator()(int* buf) {
if (*Mp == '"') {
int num = 0;
bool valid_negative = false;
Expand Down Expand Up @@ -3123,7 +3126,25 @@ size_t stuff_int_list(int *ilp, size_t max_ints, int lookup_type)
}

return true;
}, get_lookup_type_name(lookup_type));
}
};

// Stuffs an integer list.
// This is of the form ( i* )
// where i is an integer.
// For example, (1) () (1 2 3) ( 1 ) are legal integer lists.
size_t stuff_int_list(int *ilp, size_t max_ints, int lookup_type)
{
return stuff_token_list(ilp, max_ints, StuffIntListParser(lookup_type), get_lookup_type_name(lookup_type));
}

// Stuffs an integer list.
// This is of the form ( i* )
// where i is an integer.
// For example, (1) () (1 2 3) ( 1 ) are legal integer lists.
void stuff_int_list(SCP_vector<int> &ilp, int lookup_type)
{
stuff_token_list(ilp, StuffIntListParser(lookup_type), get_lookup_type_name(lookup_type));
}

// Karajorma/Goober5000 - Stuffs a loadout list by parsing a list of ship or weapon choices.
Expand Down
1 change: 1 addition & 0 deletions code/parse/parselo.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ void stuff_flagset(T *dest) {
}

extern size_t stuff_int_list(int *ilp, size_t max_ints, int lookup_type = RAW_INTEGER_TYPE);
extern void stuff_int_list(SCP_vector<int> &ilp, int lookup_type = RAW_INTEGER_TYPE);
extern size_t stuff_float_list(float* flp, size_t max_floats);
extern void stuff_float_list(SCP_vector<float>& flp);
extern size_t stuff_vec3d_list(vec3d *vlp, size_t max_vecs);
Expand Down
6 changes: 3 additions & 3 deletions code/parse/sexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3995,7 +3995,7 @@ int check_sexp_syntax(int node, int return_type, int recursive, int *bad_node, s
if (type2 == SEXP_ATOM_NUMBER || can_construe_as_integer(CTEXT(node)))
{
int num = atoi(CTEXT(node));
if (num < 0 || num >= Num_fireball_types)
if (!SCP_vector_inbounds(Fireball_info, num))
{
return SEXP_CHECK_NUM_RANGE_INVALID;
}
Expand Down Expand Up @@ -14234,7 +14234,7 @@ void sexp_explosion_effect(int n)
{
fireball_type = FIREBALL_EXPLOSION_LARGE2;
}
else if (num >= Num_fireball_types)
else if (!SCP_vector_inbounds(Fireball_info, num))
{
Warning(LOCATION, "explosion-effect fireball type is out of range; quitting the explosion...\n");
return;
Expand Down Expand Up @@ -14431,7 +14431,7 @@ void sexp_warp_effect(int n)
{
fireball_type = FIREBALL_KNOSSOS;
}
else if (num >= Num_fireball_types)
else if (!SCP_vector_inbounds(Fireball_info, num))
{
Warning(LOCATION, "warp-effect fireball type is out of range; quitting the warp...\n");
return;
Expand Down
2 changes: 1 addition & 1 deletion code/scripting/api/libs/tables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ ADE_FUNC(__len, l_Tables_FireballClasses, NULL, "Number of fireball classes", "n
if (!fireballs_inited)
return ade_set_args(L, "i", 0);

return ade_set_args(L, "i", Num_fireball_types);
return ade_set_args(L, "i", static_cast<int>(Fireball_info.size()));
}

//*****SUBLIBRARY: Tables/SimulatedSpeechOverrides
Expand Down
Loading

0 comments on commit 3851832

Please sign in to comment.