Index: code/ship/ship.cpp
===================================================================
--- code/ship/ship.cpp	(revision 7100)
+++ code/ship/ship.cpp	(working copy)
@@ -704,6 +704,11 @@
 	sip->explosion_propagates = 0;
 	sip->big_exp_visual_rad = -1.0f;
 	sip->prop_exp_rad_mult = 1.0f;
+	sip->death_roll_base_time = 3000;
+	sip->death_roll_r_mult = 1.0f;
+	sip->death_roll_time_mult = 1.0f;
+	sip->death_fx_r_mult = 1.0f;
+	sip->death_fx_count = 6;
 	sip->vaporize_chance = 0;
 	sip->shockwave_count = 1;
 	sip->explosion_bitmap_anims.clear();
@@ -883,27 +888,55 @@
 	sip->subsystems = NULL;
 
 	// default values from shipfx.cpp
-	sip->ispew_max_particles = 30;
-	sip->ispew_min_particles = 25;
-	sip->ispew_rad_max = 0.5f;
-	sip->ispew_rad_min = 0.2f;
-	sip->ispew_life_max = 0.55f;
-	sip->ispew_life_min = 0.05f;
-	sip->ispew_vel_max = 12.0f;
-	sip->ispew_vel_min = 2.0f;
-	sip->ispew_normal_variance = 1.0f;
+	sip->impact_spew.n_high = 30;
+	sip->impact_spew.n_low = 25;
+	sip->impact_spew.max_rad = 0.5f;
+	sip->impact_spew.min_rad = 0.2f;
+	sip->impact_spew.max_life = 0.55f;
+	sip->impact_spew.min_life = 0.05f;
+	sip->impact_spew.max_vel = 12.0f;
+	sip->impact_spew.min_vel = 2.0f;
+	sip->impact_spew.variance = 1.0f;
 	
 	// default values from shipfx.cpp
-	sip->dspew_max_particles = 50;
-	sip->dspew_min_particles = 20;
-	sip->dspew_rad_max = 1.3f;
-	sip->dspew_rad_min = 0.7f;
-	sip->dspew_life_max = 1.5f;
-	sip->dspew_life_min = 0.7f;
-	sip->dspew_vel_max = 12.0f;
-	sip->dspew_vel_min = 3.0f;
-	sip->dspew_normal_variance = 0.2f;
+	sip->damage_spew.n_high = 50;
+	sip->damage_spew.n_low = 20;
+	sip->damage_spew.max_rad = 1.3f;
+	sip->damage_spew.min_rad = 0.7f;
+	sip->damage_spew.max_life = 1.5f;
+	sip->damage_spew.min_life = 0.7f;
+	sip->damage_spew.max_vel = 12.0f;
+	sip->damage_spew.min_vel = 3.0f;
+	sip->damage_spew.variance = 0.2f;
 
+	sip->knossos_end_particles.n_high = 30;
+	sip->knossos_end_particles.n_low = 15;
+	sip->knossos_end_particles.max_rad = 100.0f;
+	sip->knossos_end_particles.min_rad = 30.0f;
+	sip->knossos_end_particles.max_life = 12.0f;
+	sip->knossos_end_particles.min_life = 2.0f;
+	sip->knossos_end_particles.max_vel = 350.0f;
+	sip->knossos_end_particles.min_vel = 50.0f;
+	sip->knossos_end_particles.variance = 2.0f;
+
+	sip->split_particles.n_high = 80;
+	sip->split_particles.n_low = 40;
+	sip->split_particles.max_rad = 1.5f;
+	sip->split_particles.min_rad = 0.5f;
+	sip->split_particles.max_life = 6.0f;
+	sip->split_particles.min_life = 0.5f;
+	sip->split_particles.variance = 2.0f;
+
+	sip->regular_end_particles.n_high = 100;
+	sip->regular_end_particles.n_low = 50;
+	sip->regular_end_particles.max_rad = 1.5f;
+	sip->regular_end_particles.min_rad = 0.1f;
+	sip->regular_end_particles.max_life = 4.0f;
+	sip->regular_end_particles.min_life = 0.5f;
+	sip->regular_end_particles.max_vel = 20.0f;
+	sip->regular_end_particles.min_vel = 0.0f;
+	sip->regular_end_particles.variance = 2.0f;
+
 	sip->cockpit_model_num = -1;
 	sip->model_num = -1;
 	sip->model_num_hud = -1;
@@ -1434,14 +1467,15 @@
 	{
 		float tempf;
 		int temp;
+		particle_effect *pe = &sip->impact_spew;
 		if(optional_string("+Max particles:"))
 		{
 			stuff_int(&temp);
 			if (temp < 0) {
 				Warning(LOCATION,"Bad value %i, defined as impact spew particle number (max) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
 			} else {
-				sip->ispew_max_particles = temp;
-				if (sip->ispew_max_particles == 0) {
+				pe->n_high = temp;
+				if (pe->n_high == 0) {
 					// notification for disabling the particles
 					mprintf(("Impact spew particles disabled on ship '%s'.\n", sip->name));
 				}
@@ -1453,11 +1487,11 @@
 			if (temp < 0) {
 				Warning(LOCATION,"Bad value %i, defined as impact spew particle number (min) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
 			} else {
-				sip->ispew_min_particles = temp;
+				pe->n_low = temp;
 			}
 		}
-		if (sip->ispew_min_particles > sip->ispew_max_particles)
-			sip->ispew_min_particles = sip->ispew_max_particles;
+		if (pe->n_low > pe->n_high)
+			pe->n_low = pe->n_high;
 
 		if(optional_string("+Max Radius:"))
 		{
@@ -1465,7 +1499,7 @@
 			if (tempf <= 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as impact spew particle radius (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
 			} else {
-				sip->ispew_rad_max = tempf;
+				pe->max_rad = tempf;
 			}
 		}
 		if(optional_string("+Min Radius:"))
@@ -1474,11 +1508,11 @@
 			if (tempf < 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as impact spew particle radius (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
 			} else {
-				sip->ispew_rad_min = tempf;
+				pe->min_rad = tempf;
 			}
 		}
-		if (sip->ispew_rad_min > sip->ispew_rad_max)
-			sip->ispew_rad_min = sip->ispew_rad_max;
+		if (pe->min_rad > pe->max_rad)
+			pe->min_rad = pe->max_rad;
 
 		if(optional_string("+Max Lifetime:"))
 		{
@@ -1486,7 +1520,7 @@
 			if (tempf <= 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as impact spew particle lifetime (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
 			} else {
-				sip->ispew_life_max = tempf;
+				pe->max_life = tempf;
 			}
 		}
 		if(optional_string("+Min Lifetime:"))
@@ -1495,11 +1529,11 @@
 			if (tempf < 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as impact spew particle lifetime (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
 			} else {
-				sip->ispew_life_min = tempf;
+				pe->min_life = tempf;
 			}
 		}
-		if (sip->ispew_life_min > sip->ispew_life_max)
-			sip->ispew_life_min = sip->ispew_life_max;
+		if (pe->min_life > pe->max_life)
+			pe->min_life = pe->max_life;
 
 		if(optional_string("+Max Velocity:"))
 		{
@@ -1507,7 +1541,7 @@
 			if (tempf < 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as impact spew particle velocity (max) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
 			} else {
-				sip->ispew_vel_max = tempf;
+				pe->max_vel = tempf;
 			}
 		}
 		if(optional_string("+Min Velocity:"))
@@ -1516,17 +1550,17 @@
 			if (tempf < 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as impact spew particle velocity (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
 			} else {
-				sip->ispew_vel_min = tempf;
+				pe->min_vel = tempf;
 			}
 		}
-		if (sip->ispew_vel_min > sip->ispew_vel_max)
-			sip->ispew_vel_min = sip->ispew_vel_max;
+		if (pe->min_vel > pe->max_vel)
+			pe->min_vel = pe->max_vel;
 
 		if(optional_string("+Normal Variance:"))
 		{
 			stuff_float(&tempf);
 			if ((tempf >= 0.0f) && (tempf <= 2.0f)) {
-				sip->ispew_normal_variance = tempf;
+				pe->variance = tempf;
 			} else {
 				Warning(LOCATION,"Bad value %f, defined as impact spew particle normal variance in ship '%s'.\nValue should be a float from 0.0 to 2.0.\n", tempf, sip->name);
 			}
@@ -1536,14 +1570,15 @@
 	{
 		float tempf;
 		int temp;
+		particle_effect *pe = &sip->damage_spew;
 		if(optional_string("+Max particles:"))
 		{
 			stuff_int(&temp);
 			if (temp < 0) {
 				Warning(LOCATION,"Bad value %i, defined as damage spew particle number (max) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
 			} else {
-				sip->dspew_max_particles = temp;
-				if (sip->dspew_max_particles == 0) {
+				pe->n_high = temp;
+				if (pe->n_high == 0) {
 					// notification for disabling the particles
 					mprintf(("Damage spew particles disabled on ship '%s'.\n", sip->name));
 				}
@@ -1555,11 +1590,11 @@
 			if (temp < 0) {
 				Warning(LOCATION,"Bad value %i, defined as damage spew particle number (min) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
 			} else {
-				sip->dspew_min_particles = temp;
+				pe->n_low = temp;
 			}
 		}
-		if (sip->dspew_min_particles > sip->dspew_max_particles)
-			sip->dspew_min_particles = sip->dspew_max_particles;
+		if (pe->n_low > pe->n_high)
+			pe->n_low = pe->n_high;
 
 		if(optional_string("+Max Radius:"))
 		{
@@ -1567,7 +1602,7 @@
 			if (tempf <= 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as damage spew particle radius (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
 			} else {
-				sip->dspew_rad_max = tempf;
+				pe->max_rad = tempf;
 			}
 		}
 		if(optional_string("+Min Radius:"))
@@ -1576,11 +1611,11 @@
 			if (tempf < 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as damage spew particle radius (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
 			} else {
-				sip->dspew_rad_min = tempf;
+				pe->min_rad = tempf;
 			}
 		}
-		if (sip->dspew_rad_min > sip->dspew_rad_max)
-			sip->dspew_rad_min = sip->dspew_rad_max;
+		if (pe->min_rad > pe->max_rad)
+			pe->min_rad = pe->max_rad;
 
 		if(optional_string("+Max Lifetime:"))
 		{
@@ -1588,7 +1623,7 @@
 			if (tempf <= 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as damage spew particle lifetime (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
 			} else {
-				sip->dspew_life_max = tempf;
+				pe->max_life = tempf;
 			}
 		}
 		if(optional_string("+Min Lifetime:"))
@@ -1597,11 +1632,11 @@
 			if (tempf < 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as damage spew particle lifetime (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
 			} else {
-				sip->dspew_life_min = tempf;
+				pe->min_life = tempf;
 			}
 		}
-		if (sip->dspew_life_min > sip->dspew_life_max)
-			sip->dspew_life_min = sip->dspew_life_max;
+		if (pe->min_life > pe->max_life)
+			pe->min_life = pe->max_life;
 
 		if(optional_string("+Max Velocity:"))
 		{
@@ -1609,7 +1644,7 @@
 			if (tempf < 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as damage spew particle velocity (max) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
 			} else {
-				sip->dspew_vel_max = tempf;
+				pe->max_vel = tempf;
 			}
 		}
 		if(optional_string("+Min Velocity:"))
@@ -1618,17 +1653,17 @@
 			if (tempf < 0.0f) {
 				Warning(LOCATION,"Bad value %f, defined as damage spew particle velocity (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
 			} else {
-				sip->dspew_vel_min = tempf;
+				pe->min_vel = tempf;
 			}
 		}
-		if (sip->dspew_vel_min > sip->dspew_vel_max)
-			sip->dspew_vel_min = sip->dspew_vel_max;
+		if (pe->min_vel > pe->max_vel)
+			pe->min_vel = pe->max_vel;
 
 		if(optional_string("+Normal Variance:"))
 		{
 			stuff_float(&tempf);
 			if ((tempf >= 0.0f) && (tempf <= 2.0f)) {
-				sip->dspew_normal_variance = tempf;
+				pe->variance = tempf;
 			} else {
 				Warning(LOCATION,"Bad value %f, defined as damage spew particle normal variance in ship '%s'.\nValue should be a float from 0.0 to 2.0.\n", tempf, sip->name);
 			}
@@ -2053,6 +2088,327 @@
 		stuff_float(&sip->big_exp_visual_rad);
 	}
 
+	if(optional_string("$Base Death-Roll Time:")){
+		stuff_int(&sip->death_roll_base_time);
+		if (sip->death_roll_base_time < 2)
+			sip->death_roll_base_time = 2;
+	}
+
+	if(optional_string("$Death-Roll Explosion Radius Mult:")){
+		stuff_float(&sip->death_roll_r_mult);
+		if (sip->death_roll_r_mult < 0)
+			sip->death_roll_r_mult = 0;
+	}
+
+	if(optional_string("$Death-Roll Explosion Intensity Mult:")){
+		stuff_float(&sip->death_roll_time_mult);
+		if (sip->death_roll_time_mult <= 0)
+			sip->death_roll_time_mult = 1.0f;
+	}
+
+	if(optional_string("$Death FX Explosion Radius Mult:")){
+		stuff_float(&sip->death_fx_r_mult);
+		if (sip->death_fx_r_mult < 0)
+			sip->death_fx_r_mult = 0;
+	}
+
+	if(optional_string("$Death FX Explosion Count:")){
+		stuff_int(&sip->death_fx_count);
+		if (sip->death_fx_count < 0)
+			sip->death_fx_count = 0;
+	}
+
+	if(optional_string("$Ship Splitting Particles:"))
+	{
+		float tempf;
+		int temp;
+		particle_effect *pe = &sip->split_particles;
+		if(optional_string("+Max particles:"))
+		{
+			stuff_int(&temp);
+			if (temp < 0) {
+				Warning(LOCATION,"Bad value %i, defined as ship split spew particle number (max) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
+			} else {
+				pe->n_high = temp;
+				if (pe->n_high == 0) {
+					// notification for disabling the particles
+					mprintf(("Ship split spew particles disabled on ship '%s'.\n", sip->name));
+				}
+			}
+		}
+		if(optional_string("+Min particles:"))
+		{
+			stuff_int(&temp);
+			if (temp < 0) {
+				Warning(LOCATION,"Bad value %i, defined as ship split spew particle number (min) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
+			} else {
+				pe->n_low = temp;
+			}
+		}
+		if (pe->n_low > pe->n_high)
+			pe->n_low = pe->n_high;
+
+		if(optional_string("+Max Radius:"))
+		{
+			stuff_float(&tempf);
+			if (tempf <= 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship split spew particle radius (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
+			} else {
+				pe->max_rad = tempf;
+			}
+		}
+		if(optional_string("+Min Radius:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship split spew particle radius (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->min_rad = tempf;
+			}
+		}
+		if (pe->min_rad > pe->max_rad)
+			pe->min_rad = pe->max_rad;
+
+		if(optional_string("+Max Lifetime:"))
+		{
+			stuff_float(&tempf);
+			if (tempf <= 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship split spew particle lifetime (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
+			} else {
+				pe->max_life = tempf;
+			}
+		}
+		if(optional_string("+Min Lifetime:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship split spew particle lifetime (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->min_life = tempf;
+			}
+		}
+		if (pe->min_life > pe->max_life)
+			pe->min_life = pe->max_life;
+
+		if(optional_string("+Normal Variance:"))
+		{
+			stuff_float(&tempf);
+			if ((tempf >= 0.0f) && (tempf <= 2.0f)) {
+				pe->variance = tempf;
+			} else {
+				Warning(LOCATION,"Bad value %f, defined as ship split spew particle normal variance in ship '%s'.\nValue should be a float from 0.0 to 2.0.\n", tempf, sip->name);
+			}
+		}
+	}
+
+	if(optional_string("$Ship Death Particles:"))
+	{
+		float tempf;
+		int temp;
+		particle_effect *pe = &sip->regular_end_particles;
+		if(optional_string("+Max particles:"))
+		{
+			stuff_int(&temp);
+			if (temp < 0) {
+				Warning(LOCATION,"Bad value %i, defined as ship death spew particle number (max) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
+			} else {
+				pe->n_high = temp;
+				if (pe->n_high == 0) {
+					// notification for disabling the particles
+					mprintf(("Ship death spew particles disabled on ship '%s'.\n", sip->name));
+				}
+			}
+		}
+		if(optional_string("+Min particles:"))
+		{
+			stuff_int(&temp);
+			if (temp < 0) {
+				Warning(LOCATION,"Bad value %i, defined as ship death spew particle number (min) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
+			} else {
+				pe->n_low = temp;
+			}
+		}
+		if (pe->n_low > pe->n_high)
+			pe->n_low = pe->n_high;
+
+		if(optional_string("+Max Radius:"))
+		{
+			stuff_float(&tempf);
+			if (tempf <= 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship death spew particle radius (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
+			} else {
+				pe->max_rad = tempf;
+			}
+		}
+		if(optional_string("+Min Radius:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship death spew particle radius (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->min_rad = tempf;
+			}
+		}
+		if (pe->min_rad > pe->max_rad)
+			pe->min_rad = pe->max_rad;
+
+		if(optional_string("+Max Lifetime:"))
+		{
+			stuff_float(&tempf);
+			if (tempf <= 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship death spew particle lifetime (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
+			} else {
+				pe->max_life = tempf;
+			}
+		}
+		if(optional_string("+Min Lifetime:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship death spew particle lifetime (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->min_life = tempf;
+			}
+		}
+		if (pe->min_life > pe->max_life)
+			pe->min_life = pe->max_life;
+
+		if(optional_string("+Max Velocity:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship death spew particle velocity (max) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->max_vel = tempf;
+			}
+		}
+		if(optional_string("+Min Velocity:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as ship death spew particle velocity (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->min_vel = tempf;
+			}
+		}
+		if (pe->min_vel > pe->max_vel)
+			pe->min_vel = pe->max_vel;
+
+		if(optional_string("+Normal Variance:"))
+		{
+			stuff_float(&tempf);
+			if ((tempf >= 0.0f) && (tempf <= 2.0f)) {
+				pe->variance = tempf;
+			} else {
+				Warning(LOCATION,"Bad value %f, defined as ship death spew particle normal variance in ship '%s'.\nValue should be a float from 0.0 to 2.0.\n", tempf, sip->name);
+			}
+		}
+	}
+
+	if(optional_string("$Alternate Death Particles:"))
+	{
+		float tempf;
+		int temp;
+		particle_effect *pe = &sip->knossos_end_particles;
+		if(optional_string("+Max particles:"))
+		{
+			stuff_int(&temp);
+			if (temp < 0) {
+				Warning(LOCATION,"Bad value %i, defined as alternate death spew particle number (max) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
+			} else {
+				pe->n_high = temp;
+				if (pe->n_high == 0) {
+					// notification for disabling the particles
+					mprintf(("Alternate split spew particles disabled on ship '%s'.\n", sip->name));
+				}
+			}
+		}
+		if(optional_string("+Min particles:"))
+		{
+			stuff_int(&temp);
+			if (temp < 0) {
+				Warning(LOCATION,"Bad value %i, defined as alternate death spew particle number (min) in ship '%s'.\nValue should be a non-negative integer.\n", temp, sip->name);
+			} else {
+				pe->n_low = temp;
+			}
+		}
+		if (pe->n_low > pe->n_high)
+			pe->n_low = pe->n_high;
+
+		if(optional_string("+Max Radius:"))
+		{
+			stuff_float(&tempf);
+			if (tempf <= 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as alternate death spew particle radius (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
+			} else {
+				pe->max_rad = tempf;
+			}
+		}
+		if(optional_string("+Min Radius:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as alternate death spew particle radius (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->min_rad = tempf;
+			}
+		}
+		if (pe->min_rad > pe->max_rad)
+			pe->min_rad = pe->max_rad;
+
+		if(optional_string("+Max Lifetime:"))
+		{
+			stuff_float(&tempf);
+			if (tempf <= 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as alternate death spew particle lifetime (max) in ship '%s'.\nValue should be a positive float.\n", tempf, sip->name);
+			} else {
+				pe->max_life = tempf;
+			}
+		}
+		if(optional_string("+Min Lifetime:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as alternate death spew particle lifetime (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->min_life = tempf;
+			}
+		}
+		if (pe->min_life > pe->max_life)
+			pe->min_life = pe->max_life;
+
+		if(optional_string("+Max Velocity:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as alternate death spew particle velocity (max) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->max_vel = tempf;
+			}
+		}
+		if(optional_string("+Min Velocity:"))
+		{
+			stuff_float(&tempf);
+			if (tempf < 0.0f) {
+				Warning(LOCATION,"Bad value %f, defined as alternate death spew particle velocity (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, sip->name);
+			} else {
+				pe->min_vel = tempf;
+			}
+		}
+		if (pe->min_vel > pe->max_vel)
+			pe->min_vel = pe->max_vel;
+
+		if(optional_string("+Normal Variance:"))
+		{
+			stuff_float(&tempf);
+			if ((tempf >= 0.0f) && (tempf <= 2.0f)) {
+				pe->variance = tempf;
+			} else {
+				Warning(LOCATION,"Bad value %f, defined as alternate death spew particle normal variance in ship '%s'.\nValue should be a float from 0.0 to 2.0.\n", tempf, sip->name);
+			}
+		}
+	}
+
 	if(optional_string("$Vaporize Percent Chance:")){
 		stuff_float(&sip->vaporize_chance);
 		if (sip->vaporize_chance < 0.0f || sip->vaporize_chance > 100.0f) {
@@ -7145,7 +7501,7 @@
 		objp->phys_info.desired_rotvel = shipp->deathroll_rotvel;
 
 		// Do fireballs for Big ship with propagating explostion, but not Kamikaze
-		if (!(Ai_info[shipp->ai_index].ai_flags & AIF_KAMIKAZE) && ship_get_exp_propagates(shipp)) {
+		if (!(Ai_info[shipp->ai_index].ai_flags & AIF_KAMIKAZE) && ship_get_exp_propagates(shipp) && (sip->death_roll_r_mult > 0.0f)) {
 			if ( timestamp_elapsed(shipp->next_fireball))	{
 				vec3d outpnt, pnt1, pnt2;
 				polymodel *pm = model_get(sip->model_num);
@@ -7158,14 +7514,25 @@
 
 				float rad = objp->radius*0.1f;
 				
+				if (sip->death_roll_r_mult != 1.0f)
+					rad *= sip->death_roll_r_mult;
+
 				int fireball_type = fireball_ship_explosion_type(sip);
 				if(fireball_type < 0) {
 					fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS;
 				}
 				fireball_create( &outpnt, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), rad, 0, &objp->phys_info.vel );
 				// start the next fireball up in the next 50 - 200 ms (2-3 per frame)
-				shipp->next_fireball = timestamp_rand(333,500);
+				int min_time = 333;
+				int max_time = 500;
 
+				if (sip->death_roll_time_mult != 1.0f) {
+					min_time = (int) (min_time / sip->death_roll_time_mult);
+					max_time = (int) (max_time / sip->death_roll_time_mult);
+				}
+
+				shipp->next_fireball = timestamp_rand(min_time,max_time);
+
 				// do sound - maybe start a random sound, if it has played far enough.
 				do_sub_expl_sound(objp->radius, &outpnt, shipp->sub_expl_sound_handle);
 			}
@@ -7195,6 +7562,7 @@
 
 				// emit particles
 				particle_emitter	pe;
+				particle_effect		pef = sip->knossos_end_particles;
 
 				pe.num_low = 15;					// Lowest number of particles to create
 				pe.num_high = 30;				// Highest number of particles to create
@@ -7208,6 +7576,19 @@
 				pe.max_vel = 350.0f;
 				pe.min_rad = 30.0f;	// * objp->radius;
 				pe.max_rad = 100.0f; // * objp->radius;
+				
+				pe.num_low = pef.n_low;					// Lowest number of particles to create
+				pe.num_high = pef.n_high;				// Highest number of particles to create
+				pe.pos = outpnt;				// Where the particles emit from
+				pe.vel = objp->phys_info.vel;	// Initial velocity of all the particles
+				pe.min_life = pef.min_life;	// How long the particles live
+				pe.max_life = pef.max_life;	// How long the particles live
+				pe.normal = objp->orient.vec.uvec;	// What normal the particle emit around
+				pe.normal_variance = pef.variance;		//	How close they stick to that normal 0=on normal, 1=180, 2=360 degree
+				pe.min_vel = pef.min_vel;
+				pe.max_vel = pef.max_vel;
+				pe.min_rad = pef.min_rad;	// * objp->radius;
+				pe.max_rad = pef.max_rad; // * objp->radius;
 				particle_emit( &pe, PARTICLE_SMOKE2, 0, 50 );
 
 				// do sound - maybe start a random sound, if it has played far enough.
@@ -7235,11 +7616,17 @@
 				ship_blow_up_area_apply_blast( objp );
 			}
 
-			for (int zz=0; zz<6; zz++ ) {
+			int zz_max = sip->death_fx_count;
+
+			for (int zz=0; zz<zz_max; zz++ ) {
 				// don't make sequence of fireballs for knossos
 				if (knossos_ship) {
 					break;
 				}
+
+				if (sip->death_fx_r_mult <= 0.0f) {
+					break;
+				}
 				// Find two random vertices on the model, then average them
 				// and make the piece start there.
 				vec3d tmp, outpnt, pnt1, pnt2;
@@ -7250,9 +7637,11 @@
 				vm_vec_avg( &tmp, &pnt1, &pnt2 );
 				model_find_world_point(&outpnt, &tmp, pm->id, pm->detail[0], &objp->orient, &objp->pos );
 
-				float rad = frand()*0.30f;
-				rad += objp->radius*0.40f;
+				//float rad = frand()*0.30f; //this line never really did anything - better off without it
+				float rad = objp->radius*0.40f;
 
+				rad *= sip->death_fx_r_mult;
+
 				int fireball_type = fireball_ship_explosion_type(sip);
 				if(fireball_type < 0) {
 					fireball_type = FIREBALL_EXPLOSION_MEDIUM;
@@ -7297,19 +7686,20 @@
 
 			// play a random explosion
 			particle_emitter	pe;
+			particle_effect		pef = sip->regular_end_particles;
 
-			pe.num_low = 50;					// Lowest number of particles to create
-			pe.num_high = 100;				// Highest number of particles to create
+			pe.num_low = pef.n_low;					// Lowest number of particles to create
+			pe.num_high = pef.n_high;				// Highest number of particles to create
 			pe.pos = objp->pos;				// Where the particles emit from
 			pe.vel = objp->phys_info.vel;	// Initial velocity of all the particles
-			pe.min_life = 0.5f;				// How long the particles live
-			pe.max_life = 4.0f;				// How long the particles live
+			pe.min_life = pef.min_life;				// How long the particles live
+			pe.max_life = pef.max_life;				// How long the particles live
 			pe.normal = objp->orient.vec.uvec;	// What normal the particle emit around
-			pe.normal_variance = 2.0f;		//	How close they stick to that normal 0=on normal, 1=180, 2=360 degree
-			pe.min_vel = 0.0f;				// How fast the slowest particle can move
-			pe.max_vel = 20.0f;				// How fast the fastest particle can move
-			pe.min_rad = 0.1f;				// Min radius
-			pe.max_rad = 1.5f;				// Max radius
+			pe.normal_variance = pef.variance;		//	How close they stick to that normal 0=on normal, 1=180, 2=360 degree
+			pe.min_vel = pef.min_vel;				// How fast the slowest particle can move
+			pe.max_vel = pef.max_vel;				// How fast the fastest particle can move
+			pe.min_rad = pef.min_rad;				// Min radius
+			pe.max_rad = pef.max_rad;				// Max radius
 
 			if (!knossos_ship) {
 				particle_emit( &pe, PARTICLE_SMOKE2, 0 );
Index: code/ship/ship.h
===================================================================
--- code/ship/ship.h	(revision 7100)
+++ code/ship/ship.h	(working copy)
@@ -910,6 +910,17 @@
 	float		variance;
 } thruster_particles;
 
+typedef struct particle_effect {
+	int				n_low;
+	int				n_high;
+	float			min_rad;
+	float			max_rad;
+	float			min_life;
+	float			max_life;
+	float			min_vel;
+	float			max_vel;
+	float			variance;
+} particle_effect;
 
 #define STI_MSG_COUNTS_FOR_ALONE		(1<<0)
 #define STI_MSG_PRAISE_DESTRUCTION		(1<<1)
@@ -1163,28 +1174,20 @@
 	int	explosion_propagates;				// If true, then the explosion propagates
 	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;
+	int death_roll_base_time;
+	int death_fx_count;
 	int	shockwave_count;					// the # of total shockwaves
 	SCP_vector<int> explosion_bitmap_anims;
 	float vaporize_chance;					
 
-	int			ispew_max_particles;						//Temp field until someone works on particles -C
-	int			ispew_min_particles;
-	float		ispew_rad_max;
-	float		ispew_rad_min;
-	float		ispew_life_max;
-	float		ispew_life_min;
-	float		ispew_vel_max;
-	float		ispew_vel_min;	
-	float		ispew_normal_variance;
-	int			dspew_max_particles;						//Temp field until someone works on particles -C
-	int			dspew_min_particles;
-	float		dspew_rad_max;
-	float		dspew_rad_min;
-	float		dspew_life_max;
-	float		dspew_life_min;
-	float		dspew_vel_max;
-	float		dspew_vel_min;
-	float		dspew_normal_variance;
+	particle_effect		impact_spew;
+	particle_effect		damage_spew;
+	particle_effect		split_particles;
+	particle_effect		knossos_end_particles;
+	particle_effect		regular_end_particles;
 
 	//Debris stuff
 	float			debris_min_lifetime;
Index: code/ship/shipfx.cpp
===================================================================
--- code/ship/shipfx.cpp	(revision 7100)
+++ code/ship/shipfx.cpp	(working copy)
@@ -1746,10 +1746,10 @@
 	float ship_radius, spark_scale_factor;
 
 	ship_info *sip = &Ship_info[shipp->ship_info_index];
-	if(sn > -1 && sip->ispew_max_particles <= 0)
+	if(sn > -1 && sip->impact_spew.n_high <= 0)
 		return;
 
-	if(sn < 0 && sip->dspew_max_particles <= 0)
+	if(sn < 0 && sip->damage_spew.n_high <= 0)
 		return;
 	
 	if ( shipp->num_hits <= 0 )
@@ -1837,6 +1837,7 @@
 	if ( create_spark )	{
 
 		particle_emitter	pe;
+		particle_effect		pef;
 
 		pe.pos = outpnt;				// Where the particles emit from
 
@@ -1870,6 +1871,22 @@
 				
 		pe.normal = tmp_norm;			// What normal the particle emit around
 
+		if (sn > -1)
+			pef = sip->impact_spew;
+		else
+			pef = sip->damage_spew;
+
+		pe.min_rad = pef.min_rad;
+		pe.max_rad = pef.max_rad;
+		pe.num_low = pef.n_low;				// Lowest number of particles to create (hardware)
+		pe.num_high = pef.n_high;
+		pe.normal_variance = pef.variance;	//	How close they stick to that normal 0=good, 1=360 degree
+		pe.min_vel = pef.min_vel;				// How fast the slowest particle can move
+		pe.max_vel = pef.max_vel;				// How fast the fastest particle can move
+		pe.min_life = pef.min_life;				// How long the particles live
+		pe.max_life = pef.max_life;				// How long the particles live
+
+
 		// first time through - set up end time and make heavier initially
 		if ( sn > -1 )	{
 			// Sparks for first time at this spot
@@ -1884,28 +1901,13 @@
 				}
 			}
 
-			pe.min_rad = sip->ispew_rad_min;
-			pe.max_rad = sip->ispew_rad_max;
-			pe.num_low = sip->ispew_min_particles;				// Lowest number of particles to create (hardware)
-			pe.num_high = sip->ispew_max_particles;
-			pe.normal_variance = sip->ispew_normal_variance;	//	How close they stick to that normal 0=good, 1=360 degree
-			pe.min_vel = sip->ispew_vel_min;				// How fast the slowest particle can move
-			pe.max_vel = sip->ispew_vel_max;				// How fast the fastest particle can move
-			pe.min_life = sip->ispew_life_min;				// How long the particles live
-			pe.max_life = sip->ispew_life_max;				// How long the particles live
-
 			particle_emit( &pe, PARTICLE_FIRE, 0 );
 		} else {
-
-			pe.min_rad = sip->dspew_rad_min;				// Min radius
-			pe.max_rad = sip->dspew_rad_max;				// Max radius
-			pe.num_low  = int (sip->dspew_min_particles * spark_num_scale);		// Lowest number of particles to create (hardware)
-			pe.num_high = int (sip->dspew_max_particles * spark_num_scale);		// Highest number of particles to create (hardware)
-			pe.normal_variance = sip->dspew_normal_variance * spark_width_scale;		//	How close they stick to that normal 0=good, 1=360 degree
-			pe.min_vel = sip->dspew_vel_min;				// How fast the slowest particle can move
-			pe.max_vel = sip->dspew_vel_max;				// How fast the fastest particle can move
-			pe.min_life = sip->dspew_life_min * spark_time_scale;		// How long the particles live
-			pe.max_life = sip->dspew_life_max * spark_time_scale;		// How long the particles live
+			pe.num_low  = int (pe.num_low * spark_num_scale);
+			pe.num_high = int (pe.num_high * spark_num_scale);
+			pe.normal_variance *= spark_width_scale;
+			pe.min_life *= spark_time_scale;
+			pe.max_life *= spark_time_scale;
 			
 			particle_emit( &pe, PARTICLE_SMOKE, 0 );
 		}
@@ -2498,9 +2500,10 @@
 
 			// do particles
 			particle_emitter	pe;
+			particle_effect		pef = sip->split_particles;
 
-			pe.num_low = 40;					// Lowest number of particles to create
-			pe.num_high = 80;				// Highest number of particles to create
+			pe.num_low = pef.n_low;					// Lowest number of particles to create
+			pe.num_high = pef.n_high;				// Highest number of particles to create
 			pe.pos = model_clip_plane_pt;	// Where the particles emit from
 			pe.vel = half_ship->phys_info.vel;		// Initial velocity of all the particles
 
@@ -2514,11 +2517,11 @@
 			pe.min_life = 2.0f*range;				// How long the particles live
 			pe.max_life = 10.0f*range;				// How long the particles live
 #else
-			pe.min_life = 0.5f*range;				// How long the particles live
-			pe.max_life = 6.0f*range;				// How long the particles live
+			pe.min_life = pef.min_life*range;				// How long the particles live
+			pe.max_life = pef.max_life*range;				// How long the particles live
 #endif
 			pe.normal = vmd_x_vector;		// What normal the particle emit around
-			pe.normal_variance = 2.0f;		//	How close they stick to that normal 0=on normal, 1=180, 2=360 degree
+			pe.normal_variance = pef.variance;		//	How close they stick to that normal 0=on normal, 1=180, 2=360 degree
 			pe.min_vel = 0.0f;				// How fast the slowest particle can move
 			pe.max_vel = half_ship->explosion_vel;				// How fast the fastest particle can move
 
@@ -2527,8 +2530,8 @@
 #else
 			float scale = half_ship->parent_obj->radius * 0.01f;
 #endif
-			pe.min_rad = 0.5f*scale;				// Min radius
-			pe.max_rad = 1.5f*scale;				// Max radius
+			pe.min_rad = pef.min_rad*scale;				// Min radius
+			pe.max_rad = pef.max_rad*scale;				// Max radius
 
 			particle_emit( &pe, PARTICLE_SMOKE2, 0, range );
 
Index: code/ship/shiphit.cpp
===================================================================
--- code/ship/shiphit.cpp	(revision 7100)
+++ code/ship/shiphit.cpp	(working copy)
@@ -1313,7 +1313,7 @@
 }
 
 
-#define	DEATHROLL_TIME						3000			//	generic deathroll is 3 seconds (3 * 1000 milliseconds)
+//#define	DEATHROLL_TIME						3000			//	generic deathroll is 3 seconds (3 * 1000 milliseconds) - Moved to ships.tbl
 #define	MIN_PLAYER_DEATHROLL_TIME		1000			// at least one second deathroll for a player
 #define	DEATHROLL_ROTVEL_CAP				6.3f			// maximum added deathroll rotvel in rad/sec (about 1 rev / sec)
 #define	DEATHROLL_ROTVEL_MIN				0.8f			// minimum added deathroll rotvel in rad/sec (about 1 rev / 12 sec)
@@ -1357,7 +1357,7 @@
 
 	sp->flags |= SF_DYING;
 	objp->phys_info.flags |= (PF_DEAD_DAMP | PF_REDUCED_DAMP);
-	delta_time = (int) (DEATHROLL_TIME);
+	delta_time = (int) (sip->death_roll_base_time);
 
 	//	For smaller ships, subtract off time proportional to excess damage delivered.
 	if (objp->radius < BIG_SHIP_MIN_RADIUS)
@@ -1741,6 +1741,7 @@
 	float	percent_killed;
 	int	delta_time, time_remaining;
 	ship	*shipp = &Ships[ship_obj->instance];
+	ship_info *sip = &Ship_info[shipp->ship_info_index];
 
 	// Since the explosion has two phases (final_death_time and really_final_death_time)
 	// we should only shorten the deathroll time if that is the phase we're in.
@@ -1763,7 +1764,7 @@
 	if (percent_killed > 1.0f)
 		percent_killed = 1.0f;
 
-	delta_time = (int) (4 * DEATHROLL_TIME * percent_killed);
+	delta_time = (int) (4 * sip->death_roll_base_time * percent_killed);
 	time_remaining = timestamp_until(shipp->final_death_time);
 
 	//nprintf(("AI", "Gametime = %7.3f, Time until %s dies = %7.3f, delta = %7.3f\n", f2fl(Missiontime), Ships[ship_obj->instance].ship_name, (float)time_remaining/1000.0f, delta_time));