@@ -31,13 +31,15 @@ int Knossos_warp_ani_used;
3131
3232#define MAX_WARP_LOD 0
3333
34- fireball Fireballs[MAX_FIREBALLS];
34+ constexpr int INTITIAL_FIREBALL_CONTAINTER_SIZE = 256 ;
35+
36+ SCP_vector<fireball> Fireballs;
37+ SCP_vector<int > Unused_fireball_indices;
3538
3639fireball_info Fireball_info[MAX_FIREBALL_TYPES];
3740
3841int fireball_used[MAX_FIREBALL_TYPES];
3942
40- int Num_fireballs = 0 ;
4143int Num_fireball_types = 0 ;
4244
4345bool fireballs_inited = false ;
@@ -435,8 +437,6 @@ void fireball_load_data()
435437// This will get called at the start of each level.
436438void fireball_init ()
437439{
438- int i;
439-
440440 if ( !fireballs_inited ) {
441441 // Do all the processing that happens only once
442442 fireball_parse_tbl ();
@@ -446,10 +446,10 @@ void fireball_init()
446446 }
447447
448448 // Reset everything between levels
449- Num_fireballs = 0 ;
450- for (i= 0 ; i<MAX_FIREBALLS; i++ ) {
451- Fireballs[i]. objnum = - 1 ;
452- }
449+ Fireballs. clear () ;
450+ Fireballs. reserve (INTITIAL_FIREBALL_CONTAINTER_SIZE);
451+ Unused_fireball_indices. clear () ;
452+ Unused_fireball_indices. reserve (INTITIAL_FIREBALL_CONTAINTER_SIZE);
453453
454454 // Goober5000 - reset Knossos warp flag
455455 Knossos_warp_ani_used = 0 ;
@@ -467,27 +467,25 @@ void fireball_delete( object * obj )
467467 fireball *fb;
468468
469469 num = obj->instance ;
470+ // Make sure the new system works fine.
471+ Assert (obj->instance > -1 );
472+ Assert (static_cast <int >(Fireballs.size ()) > obj->instance );
470473 fb = &Fireballs[num];
471474
472475 Assert ( fb->objnum == OBJ_INDEX (obj));
473476
474477 Fireballs[num].objnum = -1 ;
475- Num_fireballs--;
476- Assert ( Num_fireballs >= 0 );
478+ Unused_fireball_indices.push_back (num);
477479}
478480
479481/* *
480482 * Delete all active fireballs, by calling obj_delete directly.
481483 */
482484void fireball_delete_all ()
483485{
484- fireball *fb;
485- int i;
486-
487- for ( i = 0 ; i < MAX_FIREBALLS; i++ ) {
488- fb = &Fireballs[i];
489- if ( fb->objnum != -1 ) {
490- obj_delete (fb->objnum );
486+ for (auto & current_fireball : Fireballs) {
487+ if ( current_fireball.objnum != -1 ) {
488+ obj_delete (current_fireball.objnum );
491489 }
492490 }
493491}
@@ -499,6 +497,8 @@ void fireball_set_framenum(int num)
499497 fireball_info *fd;
500498 fireball_lod *fl;
501499
500+ Assert (static_cast <int >(Fireballs.size ()) > num);
501+
502502 fb = &Fireballs[num];
503503 fd = &Fireball_info[Fireballs[num].fireball_info_index ];
504504
@@ -537,6 +537,9 @@ int fireball_is_perishable(object * obj)
537537
538538 num = obj->instance ;
539539 objnum = OBJ_INDEX (obj);
540+ // Make sure the new system works fine.
541+ Assert (obj->instance > -1 );
542+ Assert ((int )Fireballs.size () > obj->instance );
540543 Assert ( Fireballs[num].objnum == objnum );
541544
542545 fb = &Fireballs[num];
@@ -553,50 +556,16 @@ int fireball_is_perishable(object * obj)
553556 return 0 ;
554557}
555558
556-
557- /* *
558- * There are too many fireballs, so delete the oldest small one
559- * to free up a slot.
560- *
561- * @return The fireball slot freed.
562- */
563- int fireball_free_one ()
564- {
565- fireball *fb;
566- int i;
567-
568- int oldest_objnum = -1 , oldest_slotnum = -1 ;
569- float lifeleft, oldest_lifeleft = 0 .0f ;
570-
571- for ( i = 0 ; i < MAX_FIREBALLS; i++ ) {
572- fb = &Fireballs[i];
573-
574- // only remove the ones that aren't warp effects
575- if ( (fb->objnum >= 0 ) && fireball_is_perishable (&Objects[fb->objnum ]) ) {
576-
577- lifeleft = fb->total_time - fb->time_elapsed ;
578- if ( (oldest_objnum < 0 ) || (lifeleft < oldest_lifeleft) ) {
579- oldest_slotnum = i;
580- oldest_lifeleft = lifeleft;
581- oldest_objnum = fb->objnum ;
582- }
583- break ;
584- }
585- }
586-
587- if ( oldest_objnum > -1 ) {
588- obj_delete (oldest_objnum);
589- }
590- return oldest_slotnum;
591- }
592-
593559int fireball_is_warp (object * obj)
594560{
595561 int num, objnum;
596562 fireball *fb;
597563
598564 num = obj->instance ;
599565 objnum = OBJ_INDEX (obj);
566+ // Make sure the new system works fine.
567+ Assert (obj->instance > -1 );
568+ Assert (static_cast <int >(Fireballs.size ()) > obj->instance );
600569 Assert ( Fireballs[num].objnum == objnum );
601570
602571 fb = &Fireballs[num];
@@ -641,6 +610,9 @@ void fireball_process_post(object * obj, float frame_time)
641610
642611 num = obj->instance ;
643612 objnum = OBJ_INDEX (obj);
613+ // Make sure the new system works fine.
614+ Assert (obj->instance > -1 );
615+ Assert (static_cast <int >(Fireballs.size ()) > obj->instance );
644616 Assert ( Fireballs[num].objnum == objnum );
645617
646618 fb = &Fireballs[num];
@@ -665,6 +637,10 @@ float fireball_lifeleft( object *obj )
665637
666638 num = obj->instance ;
667639 objnum = OBJ_INDEX (obj);
640+ // Make sure the new system works fine.
641+ Assert (obj->instance > -1 );
642+ Assert (static_cast <int >(Fireballs.size ()) > obj->instance );
643+
668644 Assert ( Fireballs[num].objnum == objnum );
669645
670646 fb = &Fireballs[num];
@@ -680,6 +656,10 @@ float fireball_lifeleft_percent( object *obj )
680656 int num, objnum;
681657 fireball *fb;
682658
659+ // Make sure the new system works fine.
660+ Assert (obj->instance > -1 );
661+ Assert (static_cast <int >(Fireballs.size ()) > obj->instance );
662+
683663 num = obj->instance ;
684664 objnum = OBJ_INDEX (obj);
685665 Assert ( Fireballs[num].objnum == objnum );
@@ -781,10 +761,8 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
781761{
782762 int n, objnum, fb_lod;
783763 object *obj;
784- fireball *fb;
785764 fireball_info *fd;
786765 fireball_lod *fl;
787-
788766 Assert ( fireball_type > -1 );
789767 Assert ( fireball_type < Num_fireball_types );
790768
@@ -800,23 +778,21 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
800778 }
801779 }
802780
803- if ( (Num_fireballs >= MAX_FIREBALLS) || (Num_objects >= MAX_OBJECTS) ) {
781+ if (Num_objects >= MAX_OBJECTS) {
782+ return -1 ;
783+ }
804784
805- // out of slots, so free one up.
806- n = fireball_free_one ();
807- if ( n < 0 ) {
808- return -1 ;
809- }
810- } else {
811- for ( n = 0 ; n < MAX_FIREBALLS; n++ ) {
812- if ( Fireballs[n].objnum < 0 ) {
813- break ;
814- }
815- }
816- Assert ( n != MAX_FIREBALLS );
785+
786+ if (!Unused_fireball_indices.empty ()) {
787+ n = Unused_fireball_indices.back ();
788+ Unused_fireball_indices.pop_back ();
789+ }
790+ else {
791+ n = static_cast <int >(Fireballs.size ());
792+ Fireballs.emplace_back ();
817793 }
818794
819- fb = &Fireballs[n];
795+ fireball* new_fireball = &Fireballs[n];
820796
821797 // get an lod to use
822798 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
833809 }
834810 fl = &fd->lod [fb_lod];
835811
836- fb ->lod = (char )fb_lod;
812+ new_fireball ->lod = (char )fb_lod;
837813
838- fb ->flags = extra_flags;
839- fb ->warp_open_sound_index = warp_open_sound;
840- fb ->warp_close_sound_index = warp_close_sound;
841- fb ->warp_open_duration = (warp_open_duration < 0 .0f ) ? WARPHOLE_GROW_TIME : warp_open_duration;
842- fb ->warp_close_duration = (warp_close_duration < 0 .0f ) ? WARPHOLE_GROW_TIME : warp_close_duration;
814+ new_fireball ->flags = extra_flags;
815+ new_fireball ->warp_open_sound_index = warp_open_sound;
816+ new_fireball ->warp_close_sound_index = warp_close_sound;
817+ new_fireball ->warp_open_duration = (warp_open_duration < 0 .0f ) ? WARPHOLE_GROW_TIME : warp_open_duration;
818+ new_fireball ->warp_close_duration = (warp_close_duration < 0 .0f ) ? WARPHOLE_GROW_TIME : warp_close_duration;
843819
844820 matrix orient;
845821 if (orient_override != NULL ){
@@ -856,58 +832,53 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
856832 default_flags.set (Object::Object_Flags::Renders);
857833 objnum = obj_create (OBJ_FIREBALL, parent_obj, n, &orient, pos, size, default_flags);
858834
859- if (objnum < 0 ) {
860- Int3 (); // Get John, we ran out of objects for fireballs
861- return objnum;
862- }
863-
864835 obj = &Objects[objnum];
865836
866- fb ->fireball_info_index = fireball_type;
867- fb ->fireball_render_type = render_type;
868- fb ->time_elapsed = 0 .0f ;
869- fb ->objnum = objnum;
870- fb ->current_bitmap = -1 ;
837+ new_fireball ->fireball_info_index = fireball_type;
838+ new_fireball ->fireball_render_type = render_type;
839+ new_fireball ->time_elapsed = 0 .0f ;
840+ new_fireball ->objnum = objnum;
841+ new_fireball ->current_bitmap = -1 ;
871842
872- switch ( fb ->fireball_render_type ) {
843+ switch ( new_fireball ->fireball_render_type ) {
873844
874845 case FIREBALL_MEDIUM_EXPLOSION:
875- fb ->orient = (myrand ()>>8 ) & 7 ; // 0 - 7
846+ new_fireball ->orient = (myrand ()>>8 ) & 7 ; // 0 - 7
876847 break ;
877848
878849 case FIREBALL_LARGE_EXPLOSION:
879- fb ->orient = (myrand ()>>8 ) % 360 ; // 0 - 359
850+ new_fireball ->orient = (myrand ()>>8 ) % 360 ; // 0 - 359
880851 break ;
881852
882853 case FIREBALL_WARP_EFFECT:
883854 // Play sound effect for warp hole opening up
884- fireball_play_warphole_open_sound (ship_class, fb );
855+ fireball_play_warphole_open_sound (ship_class, new_fireball );
885856
886857 // warp in type
887858 if (reverse) {
888- fb ->orient = 1 ;
859+ new_fireball ->orient = 1 ;
889860 // if warp out, then reverse the orientation
890861 vm_vec_scale ( &obj->orient .vec .fvec , -1 .0f ); // Reverse the forward vector
891862 vm_vec_scale ( &obj->orient .vec .rvec , -1 .0f ); // Reverse the right vector
892863 } else {
893- fb ->orient = 0 ;
864+ new_fireball ->orient = 0 ;
894865 }
895866 break ;
896867
897868 default :
898- Int3 ( );
869+ UNREACHABLE ( " Bad type set in fireball_create " );
899870 break ;
900871 }
901872
902- if ( fb ->fireball_render_type == FIREBALL_WARP_EFFECT ) {
873+ if ( new_fireball ->fireball_render_type == FIREBALL_WARP_EFFECT ) {
903874 Assert ( warp_lifetime >= 4 .0f ); // Warp lifetime must be at least 4 seconds!
904875 if ( warp_lifetime < 4 .0f )
905876 warp_lifetime = 4 .0f ;
906- fb ->total_time = warp_lifetime; // in seconds
877+ new_fireball ->total_time = warp_lifetime; // in seconds
907878 } else {
908- fb ->total_time = i2fl (fl->num_frames ) / fl->fps ; // in seconds
879+ new_fireball ->total_time = i2fl (fl->num_frames ) / fl->fps ; // in seconds
909880 }
910-
881+
911882 fireball_set_framenum (n);
912883
913884 if ( velocity ) {
@@ -923,7 +894,6 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
923894 vm_vec_zero (&obj->phys_info .max_rotvel );
924895 }
925896
926- Num_fireballs++;
927897 return objnum;
928898}
929899
@@ -1058,24 +1028,28 @@ void fireball_render(object* obj, model_draw_list *scene)
10581028
10591029 MONITOR_INC ( NumFireballsRend, 1 );
10601030
1031+ // Make sure the new system works fine.
1032+ Assert (obj->instance > -1 );
1033+ Assert (static_cast <int >(Fireballs.size ()) > obj->instance );
1034+
10611035 num = obj->instance ;
10621036 fb = &Fireballs[num];
10631037
1064- if ( Fireballs[num]. current_bitmap < 0 )
1038+ if ( fb-> current_bitmap < 0 )
10651039 return ;
10661040
10671041 g3_transfer_vertex (&p, &obj->pos );
10681042
10691043 switch ( fb->fireball_render_type ) {
10701044
10711045 case FIREBALL_MEDIUM_EXPLOSION: {
1072- batching_add_volume_bitmap (Fireballs[num]. current_bitmap , &p, fb->orient , obj->radius );
1046+ batching_add_volume_bitmap (fb-> current_bitmap , &p, fb->orient , obj->radius );
10731047 }
10741048 break ;
10751049
10761050 case FIREBALL_LARGE_EXPLOSION: {
10771051 // Make the big explosions rotate with the viewer.
1078- batching_add_volume_bitmap_rotated (Fireballs[num]. current_bitmap , &p, (i2fl (fb->orient )*PI) / 180 .0f , obj->radius );
1052+ batching_add_volume_bitmap_rotated (fb-> current_bitmap , &p, (i2fl (fb->orient )*PI) / 180 .0f , obj->radius );
10791053 }
10801054 break ;
10811055
@@ -1093,3 +1067,14 @@ void fireball_render(object* obj, model_draw_list *scene)
10931067 Int3 ();
10941068 }
10951069}
1070+
1071+ // Because fireballs are only added and removed in two places, and Unused_fireball_indices is always updated in those places to contain unused indices,
1072+ // this very simple code will give you the correct count of currently existing fireballs in use.
1073+ int fireball_get_count ()
1074+ {
1075+ int count = static_cast <int >(Fireballs.size ()) - static_cast <int >(Unused_fireball_indices.size ());
1076+
1077+ Assert (count >= 0 );
1078+
1079+ return count;
1080+ }
0 commit comments