Remove the fireball limit (#3224)

* Remove the fireball limit

* Handle Feedback

(Without the main PC, so really hoping I don't do any typos)
This commit is contained in:
JohnAFernandez authored and GitHub committed 2021-03-17 14:21:06 -04:00
1 parent d716433848
commit 609ed4ed94
5 files changed
+116 -111

No files matched your search

+87 -102
View File
@@ -31,13 +31,15 @@ int Knossos_warp_ani_used;
#define MAX_WARP_LOD 0
fireball Fireballs[MAX_FIREBALLS];
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_fireballs = 0;
int Num_fireball_types = 0;
bool fireballs_inited = false;
@@ -435,8 +437,6 @@ void fireball_load_data()
// This will get called at the start of each level.
void fireball_init()
{
int i;
if ( !fireballs_inited ) {
// Do all the processing that happens only once
fireball_parse_tbl();
@@ -446,10 +446,10 @@ void fireball_init()
}
// Reset everything between levels
Num_fireballs = 0;
for (i=0; i<MAX_FIREBALLS; i++ ) {
Fireballs[i].objnum = -1;
}
Fireballs.clear();
Fireballs.reserve(INTITIAL_FIREBALL_CONTAINTER_SIZE);
Unused_fireball_indices.clear();
Unused_fireball_indices.reserve(INTITIAL_FIREBALL_CONTAINTER_SIZE);
// Goober5000 - reset Knossos warp flag
Knossos_warp_ani_used = 0;
@@ -467,13 +467,15 @@ void fireball_delete( object * obj )
fireball *fb;
num = obj->instance;
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
fb = &Fireballs[num];
Assert( fb->objnum == OBJ_INDEX(obj));
Fireballs[num].objnum = -1;
Num_fireballs--;
Assert( Num_fireballs >= 0 );
Unused_fireball_indices.push_back(num);
}
/**
@@ -481,13 +483,9 @@ void fireball_delete( object * obj )
*/
void fireball_delete_all()
{
fireball *fb;
int i;
for ( i = 0; i < MAX_FIREBALLS; i++ ) {
fb = &Fireballs[i];
if ( fb->objnum != -1 ) {
obj_delete(fb->objnum);
for (auto& current_fireball : Fireballs) {
if ( current_fireball.objnum != -1 ) {
obj_delete(current_fireball.objnum);
}
}
}
@@ -499,6 +497,8 @@ void fireball_set_framenum(int num)
fireball_info *fd;
fireball_lod *fl;
Assert(static_cast<int>(Fireballs.size()) > num);
fb = &Fireballs[num];
fd = &Fireball_info[Fireballs[num].fireball_info_index];
@@ -537,6 +537,9 @@ int fireball_is_perishable(object * obj)
num = obj->instance;
objnum = OBJ_INDEX(obj);
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert((int)Fireballs.size() > obj->instance);
Assert( Fireballs[num].objnum == objnum );
fb = &Fireballs[num];
@@ -553,43 +556,6 @@ int fireball_is_perishable(object * obj)
return 0;
}
/**
* There are too many fireballs, so delete the oldest small one
* to free up a slot.
*
* @return The fireball slot freed.
*/
int fireball_free_one()
{
fireball *fb;
int i;
int oldest_objnum = -1, oldest_slotnum = -1;
float lifeleft, oldest_lifeleft = 0.0f;
for ( i = 0; i < MAX_FIREBALLS; i++ ) {
fb = &Fireballs[i];
// only remove the ones that aren't warp effects
if ( (fb->objnum >= 0) && fireball_is_perishable(&Objects[fb->objnum]) ) {
lifeleft = fb->total_time - fb->time_elapsed;
if ( (oldest_objnum < 0) || (lifeleft < oldest_lifeleft) ) {
oldest_slotnum = i;
oldest_lifeleft = lifeleft;
oldest_objnum = fb->objnum;
}
break;
}
}
if ( oldest_objnum > -1 ) {
obj_delete(oldest_objnum);
}
return oldest_slotnum;
}
int fireball_is_warp(object * obj)
{
int num, objnum;
@@ -597,6 +563,9 @@ int fireball_is_warp(object * obj)
num = obj->instance;
objnum = OBJ_INDEX(obj);
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
Assert( Fireballs[num].objnum == objnum );
fb = &Fireballs[num];
@@ -641,6 +610,9 @@ void fireball_process_post(object * obj, float frame_time)
num = obj->instance;
objnum = OBJ_INDEX(obj);
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
Assert( Fireballs[num].objnum == objnum );
fb = &Fireballs[num];
@@ -665,6 +637,10 @@ float fireball_lifeleft( object *obj )
num = obj->instance;
objnum = OBJ_INDEX(obj);
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
Assert( Fireballs[num].objnum == objnum );
fb = &Fireballs[num];
@@ -680,6 +656,10 @@ float fireball_lifeleft_percent( object *obj )
int num, objnum;
fireball *fb;
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
num = obj->instance;
objnum = OBJ_INDEX(obj);
Assert( Fireballs[num].objnum == objnum );
@@ -781,10 +761,8 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
{
int n, objnum, fb_lod;
object *obj;
fireball *fb;
fireball_info *fd;
fireball_lod *fl;
Assert( fireball_type > -1 );
Assert( fireball_type < Num_fireball_types );
@@ -800,23 +778,21 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
}
}
if ( (Num_fireballs >= MAX_FIREBALLS) || (Num_objects >= MAX_OBJECTS) ) {
// out of slots, so free one up.
n = fireball_free_one();
if ( n < 0 ) {
return -1;
}
} else {
for ( n = 0; n < MAX_FIREBALLS; n++ ) {
if ( Fireballs[n].objnum < 0 ) {
break;
}
}
Assert( n != MAX_FIREBALLS );
if (Num_objects >= MAX_OBJECTS) {
return -1;
}
fb = &Fireballs[n];
if (!Unused_fireball_indices.empty()) {
n = Unused_fireball_indices.back();
Unused_fireball_indices.pop_back();
}
else {
n = static_cast<int>(Fireballs.size());
Fireballs.emplace_back();
}
fireball* new_fireball = &Fireballs[n];
// get an lod to use
fb_lod = fireball_get_lod(pos, fd, size);
@@ -833,13 +809,13 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
}
fl = &fd->lod[fb_lod];
fb->lod = (char)fb_lod;
new_fireball->lod = (char)fb_lod;
fb->flags = extra_flags;
fb->warp_open_sound_index = warp_open_sound;
fb->warp_close_sound_index = warp_close_sound;
fb->warp_open_duration = (warp_open_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_open_duration;
fb->warp_close_duration = (warp_close_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_close_duration;
new_fireball->flags = extra_flags;
new_fireball->warp_open_sound_index = warp_open_sound;
new_fireball->warp_close_sound_index = warp_close_sound;
new_fireball->warp_open_duration = (warp_open_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_open_duration;
new_fireball->warp_close_duration = (warp_close_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_close_duration;
matrix orient;
if(orient_override != NULL){
@@ -856,58 +832,53 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
default_flags.set(Object::Object_Flags::Renders);
objnum = obj_create(OBJ_FIREBALL, parent_obj, n, &orient, pos, size, default_flags);
if (objnum < 0) {
Int3(); // Get John, we ran out of objects for fireballs
return objnum;
}
obj = &Objects[objnum];
fb->fireball_info_index = fireball_type;
fb->fireball_render_type = render_type;
fb->time_elapsed = 0.0f;
fb->objnum = objnum;
fb->current_bitmap = -1;
new_fireball->fireball_info_index = fireball_type;
new_fireball->fireball_render_type = render_type;
new_fireball->time_elapsed = 0.0f;
new_fireball->objnum = objnum;
new_fireball->current_bitmap = -1;
switch( fb->fireball_render_type ) {
switch( new_fireball->fireball_render_type ) {
case FIREBALL_MEDIUM_EXPLOSION:
fb->orient = (myrand()>>8) & 7; // 0 - 7
new_fireball->orient = (myrand()>>8) & 7; // 0 - 7
break;
case FIREBALL_LARGE_EXPLOSION:
fb->orient = (myrand()>>8) % 360; // 0 - 359
new_fireball->orient = (myrand()>>8) % 360; // 0 - 359
break;
case FIREBALL_WARP_EFFECT:
// Play sound effect for warp hole opening up
fireball_play_warphole_open_sound(ship_class, fb);
fireball_play_warphole_open_sound(ship_class, new_fireball);
// warp in type
if (reverse) {
fb->orient = 1;
new_fireball->orient = 1;
// if warp out, then reverse the orientation
vm_vec_scale( &obj->orient.vec.fvec, -1.0f ); // Reverse the forward vector
vm_vec_scale( &obj->orient.vec.rvec, -1.0f ); // Reverse the right vector
} else {
fb->orient = 0;
new_fireball->orient = 0;
}
break;
default:
Int3();
UNREACHABLE("Bad type set in fireball_create");
break;
}
if ( fb->fireball_render_type == FIREBALL_WARP_EFFECT ) {
if ( new_fireball->fireball_render_type == FIREBALL_WARP_EFFECT ) {
Assert( warp_lifetime >= 4.0f ); // Warp lifetime must be at least 4 seconds!
if ( warp_lifetime < 4.0f )
warp_lifetime = 4.0f;
fb->total_time = warp_lifetime; // in seconds
new_fireball->total_time = warp_lifetime; // in seconds
} else {
fb->total_time = i2fl(fl->num_frames) / fl->fps; // in seconds
new_fireball->total_time = i2fl(fl->num_frames) / fl->fps; // in seconds
}
fireball_set_framenum(n);
if ( velocity ) {
@@ -923,7 +894,6 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
vm_vec_zero(&obj->phys_info.max_rotvel);
}
Num_fireballs++;
return objnum;
}
@@ -1058,10 +1028,14 @@ void fireball_render(object* obj, model_draw_list *scene)
MONITOR_INC( NumFireballsRend, 1 );
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
num = obj->instance;
fb = &Fireballs[num];
if ( Fireballs[num].current_bitmap < 0 )
if ( fb->current_bitmap < 0 )
return;
g3_transfer_vertex(&p, &obj->pos);
@@ -1069,13 +1043,13 @@ void fireball_render(object* obj, model_draw_list *scene)
switch ( fb->fireball_render_type ) {
case FIREBALL_MEDIUM_EXPLOSION: {
batching_add_volume_bitmap(Fireballs[num].current_bitmap, &p, fb->orient, obj->radius);
batching_add_volume_bitmap(fb->current_bitmap, &p, fb->orient, obj->radius);
}
break;
case FIREBALL_LARGE_EXPLOSION: {
// Make the big explosions rotate with the viewer.
batching_add_volume_bitmap_rotated(Fireballs[num].current_bitmap, &p, (i2fl(fb->orient)*PI) / 180.0f, obj->radius);
batching_add_volume_bitmap_rotated(fb->current_bitmap, &p, (i2fl(fb->orient)*PI) / 180.0f, obj->radius);
}
break;
@@ -1093,3 +1067,14 @@ void fireball_render(object* obj, model_draw_list *scene)
Int3();
}
}
// Because fireballs are only added and removed in two places, and Unused_fireball_indices is always updated in those places to contain unused indices,
// this very simple code will give you the correct count of currently existing fireballs in use.
int fireball_get_count()
{
int count = static_cast<int>(Fireballs.size()) - static_cast<int>(Unused_fireball_indices.size());
Assert (count >= 0);
return count;
}
+4 -2
View File
@@ -95,8 +95,7 @@ typedef struct fireball {
} fireball;
// end move
extern fireball Fireballs[MAX_FIREBALLS];
extern int Num_fireballs;
extern SCP_vector<fireball> Fireballs;
extern bool fireballs_inited;
@@ -146,4 +145,7 @@ extern int Knossos_warp_ani_used;
extern bool Fireball_use_3d_warp;
// Cyborg - get a count of how many valid fireballs are in the mission.
int fireball_get_count();
#endif /* _FIREBALLS_H */
+6 -1
View File
@@ -1201,7 +1201,6 @@ void obj_clear_weapon_group_id_list()
int Arc_light = 1; // If set, electrical arcs on debris cast light
DCF_BOOL(arc_light, Arc_light)
extern fireball Fireballs[];
void obj_move_all_post(object *objp, float frametime)
{
@@ -1313,6 +1312,9 @@ void obj_move_all_post(object *objp, float frametime)
if (Detail.lighting > 2) {
float r = 0.0f, g = 0.0f, b = 0.0f;
// Make sure the new system works fine.
Assert(objp->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > objp->instance);
fireball_get_color(Fireballs[objp->instance].fireball_info_index, &r, &g, &b);
@@ -1332,6 +1334,9 @@ void obj_move_all_post(object *objp, float frametime)
float intensity = 1.0f;
if (fireball_is_warp(objp))
{
// Make sure the new system works fine.
Assert(static_cast<int>(Fireballs.size()) > objp->instance);
Assert(objp->instance > -1);
intensity = fireball_wormhole_intensity(&Fireballs[objp->instance]); // Valathil: Get wormhole radius for lighting
rad = objp->radius;
}
+7 -6
View File
@@ -705,26 +705,27 @@ ADE_INDEXER(l_Mission_Fireballs, "number Index", "Gets handle to a fireball obje
if (!ade_get_args(L, "*i", &idx))
return ade_set_error(L, "o", l_Fireball.Set(object_h()));
//Remember, Lua indices start at 0.
//Remember, Lua indices start at 1.
int count = 1;
for (int i = 0; i < MAX_FIREBALLS; i++)
{
if (Fireballs[i].fireball_info_index < 0 || Fireballs[i].objnum < 0 || Objects[Fireballs[i].objnum].type != OBJ_FIREBALL)
for (auto& current_fireball : Fireballs) {
if (current_fireball.fireball_info_index < 0 || current_fireball.objnum < 0 || Objects[current_fireball.objnum].type != OBJ_FIREBALL)
continue;
if (count == idx) {
return ade_set_args(L, "o", l_Fireball.Set(object_h(&Objects[Fireballs[i].objnum])));
return ade_set_args(L, "o", l_Fireball.Set(object_h(&Objects[current_fireball.objnum])));
}
count++;
}
return ade_set_error(L, "o", l_Fireball.Set(object_h()));
}
ADE_FUNC(__len, l_Mission_Fireballs, NULL, "Number of fireball objects in mission. Note that this is only accurate for one frame.", "number", "Number of fireball objects in mission")
{
return ade_set_args(L, "i", Num_fireballs);
int count = fireball_get_count();
return ade_set_args(L, "i", count);
}
ADE_FUNC(addMessage, l_Mission, "string name, string text, [persona persona]", "Adds a message", "message", "The new message or invalid handle on error")
+12
View File
@@ -23,6 +23,9 @@ ADE_VIRTVAR(Class, l_Fireball, "fireballclass", "Fireball's class", "fireballcla
if(!oh->IsValid())
return ade_set_error(L, "o", l_Fireballclass.Set(-1));
if (oh->objp->instance < 0 || oh->objp->instance >= static_cast<int>(Fireballs.size()))
return ade_set_error(L, "o", l_Fireballclass.Set(-1));
fireball *fb = &Fireballs[oh->objp->instance];
if(ADE_SETTING_VAR && nc > -1) {
@@ -42,6 +45,9 @@ ADE_VIRTVAR(RenderType, l_Fireball, "enumeration", "Fireball's render type", "en
if (!oh->IsValid())
return ade_set_error(L, "o", l_Enum.Set(enum_h()));
if (oh->objp->instance < 0 || oh->objp->instance >= static_cast<int>(Fireballs.size()))
return ade_set_error(L, "o", l_Enum.Set(enum_h()));
fireball* fb = &Fireballs[oh->objp->instance];
if (ADE_SETTING_VAR && type.IsValid()) {
@@ -87,6 +93,9 @@ ADE_VIRTVAR(TimeElapsed, l_Fireball, NULL, "Time this fireball exists in seconds
if(!oh->IsValid())
return ade_set_error(L, "f", 0.0f);
if (oh->objp->instance < 0 || oh->objp->instance <= static_cast<int>(Fireballs.size()))
return ade_set_error(L, "f", 0.0f);
fireball *fb = &Fireballs[oh->objp->instance];
return ade_set_args(L, "f", fb->time_elapsed);
@@ -102,6 +111,9 @@ ADE_VIRTVAR(TotalTime, l_Fireball, NULL, "Total lifetime of the fireball's anima
if (!oh->IsValid())
return ade_set_error(L, "f", 0.0f);
if (oh->objp->instance < 0 || oh->objp->instance >= static_cast<int>(Fireballs.size()))
return ade_set_error(L, "f", 0.0f);
fireball* fb = &Fireballs[oh->objp->instance];
return ade_set_args(L, "f", fb->total_time);