@@ -59,6 +59,8 @@ particle::ParticleEffectHandle Debris_hit_particle;
5959
6060#define DEBRIS_INDEX (dp ) (int )(dp-Debris.data())
6161
62+ // Find the first available arc slot. If none is available, and no_create is false, add one.
63+ debris_electrical_arc *debris_find_or_create_electrical_arc_slot (debris *db, bool no_create);
6264
6365/* *
6466 * Start the sequence of a piece of debris writhing in unholy agony!!!
@@ -266,56 +268,48 @@ void debris_process_post(object * obj, float frame_time)
266268 return ; // If arc_frequency <= 0, this piece has no arcs on it
267269 }
268270
269- if ( !timestamp_elapsed (db->fire_timeout ) && timestamp_elapsed (db->next_fireball )) {
271+ if ( !timestamp_elapsed (db->arc_timeout ) && timestamp_elapsed (db->arc_next_time )) {
270272
271- db->next_fireball = _timestamp_rand (db->arc_frequency ,db->arc_frequency *2 );
273+ db->arc_next_time = _timestamp_rand (db->arc_frequency ,db->arc_frequency *2 );
272274 db->arc_frequency += 100 ;
273275
274276 if (db->is_hull ) {
275277
276- int n, n_arcs = Random::next (1 , 3 ); // Create 1-3 sparks
278+ int n_arcs = Random::next (1 , 3 ); // Create 1-3 sparks
277279
278280 vec3d v1 = submodel_get_random_point (db->model_num , db->submodel_num );
279281 vec3d v2 = submodel_get_random_point (db->model_num , db->submodel_num );
280282 vec3d v3 = submodel_get_random_point (db->model_num , db->submodel_num );
281283 vec3d v4 = submodel_get_random_point (db->model_num , db->submodel_num );
282284
283- n = 0 ;
284-
285285 int lifetime = Random::next (100 , 1000 );
286286
287287 // Create the spark effects
288- for (int i= 0 ; i<MAX_DEBRIS_ARCS; ++i) {
289- if ( ! db->arc_timestamp [i]. isValid () ) {
290-
291- db-> arc_timestamp [i] = _timestamp (lifetime); // live up to a second
288+ for (int n = 0 ; n < n_arcs; n++) {
289+ auto arc = debris_find_or_create_electrical_arc_slot (db, db->electrical_arcs . size () >= MAX_DEBRIS_ARCS);
290+ if (arc) {
291+ arc-> timestamp = _timestamp (lifetime); // live up to a second
292292
293293 switch ( n ) {
294294 case 0 :
295- db-> arc_pts [i][ 0 ] = v1;
296- db-> arc_pts [i][ 1 ] = v2;
295+ arc-> endpoint_1 = v1;
296+ arc-> endpoint_2 = v2;
297297 break ;
298298 case 1 :
299- db-> arc_pts [i][ 0 ] = v2;
300- db-> arc_pts [i][ 1 ] = v3;
299+ arc-> endpoint_1 = v2;
300+ arc-> endpoint_2 = v3;
301301 break ;
302-
303302 case 2 :
304- db-> arc_pts [i][ 0 ] = v2;
305- db-> arc_pts [i][ 1 ] = v4;
303+ arc-> endpoint_1 = v2;
304+ arc-> endpoint_2 = v4;
306305 break ;
307306
308307 default :
309- Int3 ( );
308+ UNREACHABLE ( " Unhandled case %d for electrical arc creation in debris_process_post()! " , n );
310309 }
311-
312- n++;
313- if ( n == n_arcs )
314- break ; // Don't need to create anymore
315310 }
316311 }
317312
318-
319313 // rotate v2 out of local coordinates into world.
320314 // Use v2 since it is used in every bolt. See above switch().
321315 vec3d snd_pos;
@@ -342,16 +336,20 @@ void debris_process_post(object * obj, float frame_time)
342336 }
343337 }
344338
345- for (int i= 0 ; i<MAX_DEBRIS_ARCS; ++i) {
346- if ( db-> arc_timestamp [i]. isValid () ) {
347- if ( timestamp_elapsed ( db-> arc_timestamp [i] ) ) {
339+ for (auto &arc: db-> electrical_arcs ) {
340+ if (arc. timestamp . isValid ()) {
341+ if (timestamp_elapsed (arc. timestamp )) {
348342 // Kill off the spark
349- db-> arc_timestamp [i] = TIMESTAMP::invalid ();
343+ arc. timestamp = TIMESTAMP::invalid ();
350344 } else {
351345 // Maybe move a vertex.... 20% of the time maybe?
352346 int mr = Random::next ();
353347 if ( mr < Random::MAX_VALUE/5 ) {
354- db->arc_pts [i][mr % 2 ] = submodel_get_random_point (db->model_num , db->submodel_num );
348+ auto pt = submodel_get_random_point (db->model_num , db->submodel_num );
349+ if (mr % 2 == 0 )
350+ arc.endpoint_1 = pt;
351+ else
352+ arc.endpoint_2 = pt;
355353 }
356354 }
357355 }
@@ -595,15 +593,13 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
595593 db->ship_info_index = parent_ship_class;
596594 db->team = team;
597595 db->ambient_sound = (sip == nullptr ) ? gamesnd_id (-1 ) : sip->debris_ambient_sound ;
598- db->fire_timeout = TIMESTAMP::never (); // if not changed, timestamp_elapsed() will return false
596+ db->arc_timeout = TIMESTAMP::never (); // if not changed, timestamp_elapsed() will return false
599597 db->time_started = Missiontime;
600598 db->species = (sip == nullptr ) ? -1 : sip->species ;
601599 db->parent_alt_name = alt_type_index;
602600 db->damage_mult = 1 .0f ;
603601
604- for (int i=0 ; i<MAX_DEBRIS_ARCS; ++i) { // NOLINT
605- db->arc_timestamp [i] = TIMESTAMP::invalid ();
606- }
602+ db->electrical_arcs .clear ();
607603
608604 if ( db->is_hull ) {
609605 // Percent of debris pieces with arcs controlled via table (default 50%)
@@ -616,7 +612,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
616612 db->arc_frequency = 0 ;
617613 }
618614
619- db->next_fireball = _timestamp_rand (500 ,2000 ); // start one 1/2 - 2 secs later
615+ db->arc_next_time = _timestamp_rand (500 ,2000 ); // start one 1/2 - 2 secs later
620616
621617 flagset<Object::Object_Flags> default_flags;
622618 default_flags.set (Object::Object_Flags::Renders);
@@ -677,12 +673,12 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
677673 // limit the amount of time that fireballs appear
678674 // let fireball length be linked to radius of ship. Range is .33 radius => 3.33 radius seconds.
679675 if (spark_timeout >= 0 ) {
680- db->fire_timeout = _timestamp (spark_timeout);
676+ db->arc_timeout = _timestamp (spark_timeout);
681677 } else if (parent_objnum >= 0 ) {
682678 float t = 1000 *Objects[parent_objnum].radius /3 + (fl2i (1000 *3 *Objects[parent_objnum].radius ) == 0 ? 0 : Random::next (fl2i (1000 *3 *Objects[parent_objnum].radius )));
683- db->fire_timeout = _timestamp (fl2i (t)); // fireballs last from 5 - 30 seconds
679+ db->arc_timeout = _timestamp (fl2i (t)); // fireballs last from 5 - 30 seconds
684680 } else {
685- db->fire_timeout = TIMESTAMP::immediate ();
681+ db->arc_timeout = TIMESTAMP::immediate ();
686682 }
687683
688684 if (parent_objnum >= 0 && Objects[parent_objnum].radius >= MIN_RADIUS_FOR_PERSISTENT_DEBRIS) {
@@ -1168,7 +1164,7 @@ void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs,
11681164*/
11691165void debris_render (object * obj, model_draw_list *scene)
11701166{
1171- int i, num, swapped;
1167+ int num, swapped;
11721168 debris *db;
11731169
11741170 swapped = -1 ;
@@ -1203,9 +1199,9 @@ void debris_render(object * obj, model_draw_list *scene)
12031199
12041200 // Only render electrical arcs if within 500m of the eye (for a 10m piece)
12051201 if ( vm_vec_dist_quick ( &obj->pos , &Eye_position ) < obj->radius *50 .0f ) {
1206- for (i= 0 ; i<MAX_DEBRIS_ARCS; i++ ) {
1207- if ( db-> arc_timestamp [i] .isValid () ) {
1208- model_instance_add_arc ( pm, pmi, db->submodel_num , &db-> arc_pts [i][ 0 ] , &db-> arc_pts [i][ 1 ] , MARC_TYPE_DAMAGED );
1202+ for (auto &arc: db-> electrical_arcs ) {
1203+ if ( arc. timestamp .isValid () ) {
1204+ model_instance_add_arc ( pm, pmi, db->submodel_num , &arc. endpoint_1 , &arc. endpoint_2 , nullptr , MARC_TYPE_DAMAGED );
12091205 }
12101206 }
12111207 }
@@ -1256,3 +1252,23 @@ void create_generic_debris(object* ship_objp, const vec3d* pos, float min_num_de
12561252 debris_create (ship_objp, model_num, -1 , &create_pos, pos, 0 , speed_mult);
12571253 }
12581254}
1255+
1256+ debris_electrical_arc *debris_find_or_create_electrical_arc_slot (debris *db, bool no_create)
1257+ {
1258+ size_t i = 0 ;
1259+ for (auto & ii : db->electrical_arcs )
1260+ {
1261+ if (!ii.timestamp .isValid ())
1262+ break ;
1263+ i++;
1264+ }
1265+
1266+ if (i == db->electrical_arcs .size ())
1267+ {
1268+ if (no_create)
1269+ return nullptr ;
1270+ db->electrical_arcs .emplace_back ();
1271+ }
1272+
1273+ return &db->electrical_arcs [i];
1274+ }
0 commit comments