diff --git a/code/__DEFINES/_helpers.dm b/code/__DEFINES/_helpers.dm
index 22ca001ae4e..bcea96cc598 100644
--- a/code/__DEFINES/_helpers.dm
+++ b/code/__DEFINES/_helpers.dm
@@ -7,3 +7,6 @@
//Returns an integer given a hex input, supports negative values "-ff"
//skips preceding invalid characters
#define hex2num(X) text2num(X, 16)
+
+/// Stringifies whatever you put into it.
+#define STRINGIFY(argument) #argument
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index e03fd64be6f..4e269c649ef 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -237,11 +237,8 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define HIS_GRACE_FORCE_BONUS 4 //How much force is gained per kill.
-#define EXPLODE_NONE 0 //Don't even ask me why we need this.
-#define EXPLODE_DEVASTATE 1
-#define EXPLODE_HEAVY 2
-#define EXPLODE_LIGHT 3
-#define EXPLODE_GIB_THRESHOLD 50 //ex_act() with EXPLODE_DEVASTATE severity will gib mobs with less than this much bomb armor
+/// ex_act() with EXPLODE_DEVASTATE severity will gib mobs with less than this much bomb armor
+#define EXPLODE_GIB_THRESHOLD 50
#define EMP_HEAVY 1
#define EMP_LIGHT 2
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index ee70d6613ba..05df0e26a13 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -162,6 +162,15 @@
///from obj/machinery/bsa/full/proc/fire(): ()
#define COMSIG_ATOM_BSA_BEAM "atom_bsa_beam_pass"
#define COMSIG_ATOM_BLOCKS_BSA_BEAM (1<<0)
+
+///from [/datum/controller/subsystem/explosions/proc/explode]: (/list(/atom, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, adminlog, ignorecap, silent, smoke))
+#define COMSIG_ATOM_EXPLODE "atom_explode"
+///from [/datum/controller/subsystem/explosions/proc/explode]: (/list(/atom, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, adminlog, ignorecap, silent, smoke))
+#define COMSIG_ATOM_INTERNAL_EXPLOSION "atom_internal_explosion"
+///from [/datum/controller/subsystem/explosions/proc/explode]: (/list(/atom, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, adminlog, ignorecap, silent, smoke))
+#define COMSIG_AREA_INTERNAL_EXPLOSION "area_internal_explosion"
+ /// When returned on a signal hooked to [COMSIG_ATOM_EXPLODE], [COMSIG_ATOM_INTERNAL_EXPLOSION], or [COMSIG_AREA_INTERNAL_EXPLOSION] it prevents the explosion from being propagated further.
+ #define COMSIG_CANCEL_EXPLOSION (1<<0)
///from /obj/machinery/doppler_array/proc/sense_explosion(...): Runs when an explosion is succesfully detected by a doppler array(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
#define COMSIG_DOPPLER_ARRAY_EXPLOSION_DETECTED "atom_dopplerarray_explosion_detected"
diff --git a/code/__DEFINES/explosions.dm b/code/__DEFINES/explosions.dm
new file mode 100644
index 00000000000..a05e3bd33c7
--- /dev/null
+++ b/code/__DEFINES/explosions.dm
@@ -0,0 +1,32 @@
+// The severity of explosions. Why are these inverted? I have no idea, but git blame doesn't go back far enough for me to find out.
+/// The (current) highest possible explosion severity.
+#define EXPLODE_DEVASTATE 3
+/// The (current) middling explosion severity.
+#define EXPLODE_HEAVY 2
+/// The (current) lowest possible explosion severity.
+#define EXPLODE_LIGHT 1
+/// The default explosion severity used to mark that an object is beyond the impact range of the explosion.
+#define EXPLODE_NONE 0
+
+// Internal explosion argument list keys.
+// Must match the arguments to [/datum/controller/subsystem/explosions/proc/propagate_blastwave]
+/// The origin atom of the explosion.
+#define EXARG_KEY_ORIGIN "origin"
+/// The devastation range of the explosion.
+#define EXARG_KEY_DEV_RANGE STRINGIFY(devastation_range)
+/// The heavy impact range of the explosion.
+#define EXARG_KEY_HEAVY_RANGE STRINGIFY(heavy_impact_range)
+/// The light impact range of the explosion.
+#define EXARG_KEY_LIGHT_RANGE STRINGIFY(light_impact_range)
+/// The flame range of the explosion.
+#define EXARG_KEY_FLAME_RANGE STRINGIFY(flame_range)
+/// The flash range of the explosion.
+#define EXARG_KEY_FLASH_RANGE STRINGIFY(flash_range)
+/// Whether or not the explosion should be logged.
+#define EXARG_KEY_ADMIN_LOG STRINGIFY(adminlog)
+/// Whether or not the explosion should ignore the bombcap.
+#define EXARG_KEY_IGNORE_CAP STRINGIFY(ignorecap)
+/// Whether or not the explosion should produce sound effects and screenshake if it is large enough to warrant it.
+#define EXARG_KEY_SILENT STRINGIFY(silent)
+/// Whether or not the explosion should produce smoke if it is large enough to warrant it.
+#define EXARG_KEY_SMOKE STRINGIFY(smoke)
diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm
index 010e57be1f4..1354a4fabff 100644
--- a/code/controllers/subsystem/explosions.dm
+++ b/code/controllers/subsystem/explosions.dm
@@ -153,12 +153,12 @@ SUBSYSTEM_DEF(explosions)
A.color = null
A.maptext = ""
-/proc/dyn_explosion(turf/epicenter, power, flash_range, adminlog = TRUE, ignorecap = TRUE, flame_range = 0, silent = FALSE, smoke = TRUE)
+/proc/dyn_explosion(turf/epicenter, power, flame_range = 0, flash_range = null, adminlog = TRUE, ignorecap = TRUE, silent = FALSE, smoke = TRUE)
if(!power)
return
var/range = 0
range = round((2 * power)**GLOB.DYN_EX_SCALE)
- explosion(epicenter, round(range * 0.25), round(range * 0.5), round(range), flash_range*range, adminlog, ignorecap, flame_range*range, silent, smoke)
+ explosion(epicenter, devastation_range = round(range * 0.25), heavy_impact_range = round(range * 0.5), light_impact_range = round(range), flame_range = flame_range*range, flash_range = flash_range*range, adminlog = adminlog, ignorecap = ignorecap, silent = silent, smoke = smoke)
// Using default dyn_ex scale:
// 100 explosion power is a (5, 10, 20) explosion.
@@ -169,20 +169,86 @@ SUBSYSTEM_DEF(explosions)
// 5 explosion power is a (0, 1, 3) explosion.
// 1 explosion power is a (0, 0, 1) explosion.
-/proc/explosion(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = TRUE, ignorecap = FALSE, flame_range = 0, silent = FALSE, smoke = FALSE)
+/**
+ * Makes a given atom explode.
+ *
+ * Arguments:
+ * - [origin][/atom]: The atom that's exploding.
+ * - devastation_range: The range at which the effects of the explosion are at their strongest.
+ * - heavy_impact_range: The range at which the effects of the explosion are relatively severe.
+ * - light_impact_range: The range at which the effects of the explosion are relatively weak.
+ * - flash_range: The range at which the explosion flashes people.
+ * - adminlog: Whether to log the explosion/report it to the administration.
+ * - ignorecap: Whether to ignore the relevant bombcap. Defaults to FALSE.
+ * - flame_range: The range at which the explosion should produce hotspots.
+ * - silent: Whether to generate/execute sound effects.
+ * - smoke: Whether to generate a smoke cloud provided the explosion is powerful enough to warrant it.
+ */
+/proc/explosion(atom/origin, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 0, flame_range = 0, flash_range = 0, adminlog = TRUE, ignorecap = FALSE, silent = FALSE, smoke = FALSE)
. = SSexplosions.explode(arglist(args))
-#define CREAK_DELAY 5 SECONDS //Time taken for the creak to play after explosion, if applicable.
-#define DEVASTATION_PROB 30 //The probability modifier for devistation, maths!
-#define HEAVY_IMPACT_PROB 5 //ditto
-#define FAR_UPPER 60 //Upper limit for the far_volume, distance, clamped.
-#define FAR_LOWER 40 //lower limit for the far_volume, distance, clamped.
-#define PROB_SOUND 75 //The probability modifier for a sound to be an echo, or a far sound. (0-100)
-#define SHAKE_CLAMP 2.5 //The limit for how much the camera can shake for out of view booms.
-#define FREQ_UPPER 40 //The upper limit for the randomly selected frequency.
-#define FREQ_LOWER 25 //The lower of the above.
-/datum/controller/subsystem/explosions/proc/explode(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, ignorecap, flame_range, silent, smoke)
+/**
+ * Makes a given atom explode. Now on the explosions subsystem!
+ *
+ * Arguments:
+ * - [origin][/atom]: The atom that's exploding.
+ * - devastation_range: The range at which the effects of the explosion are at their strongest.
+ * - heavy_impact_range: The range at which the effects of the explosion are relatively severe.
+ * - light_impact_range: The range at which the effects of the explosion are relatively weak.
+ * - flash_range: The range at which the explosion flashes people.
+ * - adminlog: Whether to log the explosion/report it to the administration.
+ * - ignorecap: Whether to ignore the relevant bombcap. Defaults to FALSE.
+ * - flame_range: The range at which the explosion should produce hotspots.
+ * - silent: Whether to generate/execute sound effects.
+ * - smoke: Whether to generate a smoke cloud provided the explosion is powerful enough to warrant it.
+ */
+/datum/controller/subsystem/explosions/proc/explode(atom/origin, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 0, flame_range = 0, flash_range = 0, adminlog = TRUE, ignorecap = FALSE, silent = FALSE, smoke = FALSE)
+ var/list/arguments = list(EXARG_KEY_ORIGIN = origin, EXARG_KEY_DEV_RANGE = devastation_range, EXARG_KEY_HEAVY_RANGE = heavy_impact_range, EXARG_KEY_LIGHT_RANGE = light_impact_range, EXARG_KEY_FLAME_RANGE = flame_range, EXARG_KEY_FLASH_RANGE = flash_range, EXARG_KEY_ADMIN_LOG = adminlog, EXARG_KEY_IGNORE_CAP = ignorecap, EXARG_KEY_SILENT = silent, EXARG_KEY_SMOKE = smoke)
+ var/atom/location = isturf(origin) ? origin : origin.loc
+ if(SEND_SIGNAL(origin, COMSIG_ATOM_EXPLODE, arguments) & COMSIG_CANCEL_EXPLOSION)
+ return // Signals are incompatible with `arglist(...)` so we can't actually use that for these. Additionally,
+
+ while(location)
+ var/next_loc = location.loc
+ if(SEND_SIGNAL(location, COMSIG_ATOM_INTERNAL_EXPLOSION, arguments) & COMSIG_CANCEL_EXPLOSION)
+ return
+ if(isturf(location))
+ break
+ location = next_loc
+
+ if(!location)
+ return
+
+ var/area/epicenter_area = get_area(location)
+ if(SEND_SIGNAL(epicenter_area, COMSIG_AREA_INTERNAL_EXPLOSION, arguments) & COMSIG_CANCEL_EXPLOSION)
+ return
+
+ arguments -= EXARG_KEY_ORIGIN
+ propagate_blastwave(arglist(list(location) + arguments))
+
+
+/**
+ * Handles the effects of an explosion originating from a given point.
+ *
+ * Primarily handles popagating the balstwave of the explosion to the relevant turfs.
+ * Also handles the fireball from the explosion.
+ * Also handles the smoke cloud from the explosion.
+ * Also handles sfx and screenshake.
+ *
+ * Arguments:
+ * - [epicenter][/atom]: The location of the explosion rounded to the nearest turf.
+ * - devastation_range: The range at which the effects of the explosion are at their strongest.
+ * - heavy_impact_range: The range at which the effects of the explosion are relatively severe.
+ * - light_impact_range: The range at which the effects of the explosion are relatively weak.
+ * - flash_range: The range at which the explosion flashes people.
+ * - adminlog: Whether to log the explosion/report it to the administration.
+ * - ignorecap: Whether to ignore the relevant bombcap. Defaults to TRUE for some mysterious reason.
+ * - flame_range: The range at which the explosion should produce hotspots.
+ * - silent: Whether to generate/execute sound effects.
+ * - smoke: Whether to generate a smoke cloud provided the explosion is powerful enough to warrant it.
+ */
+/datum/controller/subsystem/explosions/proc/propagate_blastwave(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, adminlog, ignorecap, silent, smoke)
epicenter = get_turf(epicenter)
if(!epicenter)
return
@@ -197,7 +263,7 @@ SUBSYSTEM_DEF(explosions)
var/orig_heavy_range = heavy_impact_range
var/orig_light_range = light_impact_range
- var/orig_max_distance = max(devastation_range, heavy_impact_range, light_impact_range, flash_range, flame_range)
+ var/orig_max_distance = max(devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range)
//Zlevel specific bomb cap multiplier
var/cap_multiplier = SSmapping.level_trait(epicenter.z, ZTRAIT_BOMBCAP_MULTIPLIER)
@@ -221,7 +287,7 @@ SUBSYSTEM_DEF(explosions)
var/y0 = epicenter.y
var/z0 = epicenter.z
var/area/areatype = get_area(epicenter)
- SSblackbox.record_feedback("associative", "explosion", 1, list("dev" = devastation_range, "heavy" = heavy_impact_range, "light" = light_impact_range, "flash" = flash_range, "flame" = flame_range, "orig_dev" = orig_dev_range, "orig_heavy" = orig_heavy_range, "orig_light" = orig_light_range, "x" = x0, "y" = y0, "z" = z0, "area" = areatype.type, "time" = time_stamp("YYYY-MM-DD hh:mm:ss", 1)))
+ SSblackbox.record_feedback("associative", "explosion", 1, list("dev" = devastation_range, "heavy" = heavy_impact_range, "light" = light_impact_range, "flame" = flame_range, "flash" = flash_range, "orig_dev" = orig_dev_range, "orig_heavy" = orig_heavy_range, "orig_light" = orig_light_range, "x" = x0, "y" = y0, "z" = z0, "area" = areatype.type, "time" = time_stamp("YYYY-MM-DD hh:mm:ss", 1)))
// Play sounds; we want sounds to be different depending on distance so we will manually do it ourselves.
// Stereo users will also hear the direction of the explosion!
@@ -234,56 +300,7 @@ SUBSYSTEM_DEF(explosions)
far_dist += devastation_range * 20
if(!silent)
- var/frequency = get_rand_frequency()
- var/sound/explosion_sound = sound(get_sfx("explosion"))
- var/sound/far_explosion_sound = sound('sound/effects/explosionfar.ogg')
- var/sound/creaking_explosion_sound = sound(get_sfx("explosion_creaking"))
- var/sound/hull_creaking_sound = sound(get_sfx("hull_creaking"))
- var/sound/explosion_echo_sound = sound('sound/effects/explosion_distant.ogg')
- var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION)
- var/creaking_explosion = FALSE
-
- if(prob(devastation_range*DEVASTATION_PROB+heavy_impact_range*HEAVY_IMPACT_PROB) && on_station) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might.
- creaking_explosion = TRUE // prob over 100 always returns true
-
- for(var/MN in GLOB.player_list)
- var/mob/M = MN
- // Double check for client
- var/turf/M_turf = get_turf(M)
- if(M_turf && M_turf.z == z0)
- var/dist = get_dist(M_turf, epicenter)
- var/baseshakeamount
- if(orig_max_distance - dist > 0)
- baseshakeamount = sqrt((orig_max_distance - dist)*0.1)
- // If inside the blast radius + world.view - 2
- if(dist <= round(max_range + world.view - 2, 1))
- M.playsound_local(epicenter, null, 100, 1, frequency, S = explosion_sound)
- if(baseshakeamount > 0)
- shake_camera(M, 25, clamp(baseshakeamount, 0, 10))
- // You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
- else if(dist <= far_dist)
- var/far_volume = clamp(far_dist/2, FAR_LOWER, FAR_UPPER) // Volume is based on explosion size and dist
- if(creaking_explosion)
- M.playsound_local(epicenter, null, far_volume, 1, frequency, S = creaking_explosion_sound, distance_multiplier = 0)
- else if(prob(PROB_SOUND)) // Sound variety during meteor storm/tesloose/other bad event
- M.playsound_local(epicenter, null, far_volume, 1, frequency, S = far_explosion_sound, distance_multiplier = 0) // Far sound
- else
- M.playsound_local(epicenter, null, far_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0) // Echo sound
-
- if(baseshakeamount > 0 || devastation_range)
- if(!baseshakeamount) // Devastating explosions rock the station and ground
- baseshakeamount = devastation_range*3
- shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, SHAKE_CLAMP))
- else if(!isspaceturf(get_turf(M)) && heavy_impact_range) // Big enough explosions echo throughout the hull
- var/echo_volume = 40
- if(devastation_range)
- baseshakeamount = devastation_range
- shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, SHAKE_CLAMP))
- echo_volume = 60
- M.playsound_local(epicenter, null, echo_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0)
-
- if(creaking_explosion) // 5 seconds after the bang, the station begins to creak
- addtimer(CALLBACK(M, /mob/proc/playsound_local, epicenter, null, rand(FREQ_LOWER, FREQ_UPPER), 1, frequency, null, null, FALSE, hull_creaking_sound, 0), CREAK_DELAY)
+ shake_the_room(epicenter, orig_max_distance, far_dist, devastation_range, heavy_impact_range)
if(heavy_impact_range > 1)
var/datum/effect_system/explosion/E
@@ -383,13 +400,110 @@ SUBSYSTEM_DEF(explosions)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_EXPLOSION, epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
+// Explosion SFX defines...
+/// The probability that a quaking explosion will make the station creak per unit. Maths!
+#define QUAKE_CREAK_PROB 30
+/// The probability that an echoing explosion will make the station creak per unit.
+#define ECHO_CREAK_PROB 5
+/// Time taken for the hull to begin to creak after an explosion, if applicable.
+#define CREAK_DELAY (5 SECONDS)
+/// Lower limit for far explosion SFX volume.
+#define FAR_LOWER 40
+/// Upper limit for far explosion SFX volume.
+#define FAR_UPPER 60
+/// The probability that a distant explosion SFX will be a far explosion sound rather than an echo. (0-100)
+#define FAR_SOUND_PROB 75
+/// The upper limit on screenshake amplitude for nearby explosions.
+#define NEAR_SHAKE_CAP 10
+/// The upper limit on screenshake amplifude for distant explosions.
+#define FAR_SHAKE_CAP 2.5
+/// The duration of the screenshake for nearby explosions.
+#define NEAR_SHAKE_DURATION (2.5 SECONDS)
+/// The duration of the screenshake for distant explosions.
+#define FAR_SHAKE_DURATION (1 SECONDS)
+/// The lower limit for the randomly selected hull creaking frequency.
+#define FREQ_LOWER 25
+/// The upper limit for the randomly selected hull creaking frequency.
+#define FREQ_UPPER 40
+
+/**
+ * Handles the sfx and screenshake caused by an explosion.
+ *
+ * Arguments:
+ * - [epicenter][/turf]: The location of the explosion.
+ * - near_distance: How close to the explosion you need to be to get the full effect of the explosion.
+ * - far_distance: How close to the explosion you need to be to hear more than echos.
+ * - quake_factor: Main scaling factor for screenshake.
+ * - echo_factor: Whether to make the explosion echo off of very distant parts of the station.
+ * - creaking: Whether to make the station creak. Autoset if null.
+ * - [near_sound][/sound]: The sound that plays if you are close to the explosion.
+ * - [far_sound][/sound]: The sound that plays if you are far from the explosion.
+ * - [echo_sound][/sound]: The sound that plays as echos for the explosion.
+ * - [creaking_sound][/sound]: The sound that plays when the station creaks during the explosion.
+ * - [hull_creaking_sound][/sound]: The sound that plays when the station creaks after the explosion.
+ */
+/datum/controller/subsystem/explosions/proc/shake_the_room(turf/epicenter, near_distance, far_distance, quake_factor, echo_factor, creaking, sound/near_sound = sound(get_sfx("explosion")), sound/far_sound = sound('sound/effects/explosionfar.ogg'), sound/echo_sound = sound('sound/effects/explosion_distant.ogg'), sound/creaking_sound = sound(get_sfx("explosion_creaking")), hull_creaking_sound = sound(get_sfx("hull_creaking")))
+ var/frequency = get_rand_frequency()
+ var/blast_z = epicenter.z
+ if(isnull(creaking)) // Autoset creaking.
+ var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION)
+ if(on_station && prob((quake_factor * QUAKE_CREAK_PROB) + (echo_factor * ECHO_CREAK_PROB))) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might.
+ creaking = TRUE // prob over 100 always returns true
+ else
+ creaking = FALSE
+
+ for(var/mob/listener as anything in GLOB.player_list)
+ var/turf/listener_turf = get_turf(listener)
+ if(!listener_turf || listener_turf.z != blast_z)
+ continue
+
+ var/distance = get_dist(epicenter, listener_turf)
+ var/base_shake_amount
+ if(near_distance > distance)
+ base_shake_amount = sqrt((near_distance - distance) / 10)
+
+ if(distance <= round(near_distance + world.view - 2, 1)) // If you are close enough to see the effects of the explosion first-hand (ignoring walls)
+ listener.playsound_local(epicenter, null, 100, TRUE, frequency, S = near_sound)
+ if(base_shake_amount > 0)
+ shake_camera(listener, NEAR_SHAKE_DURATION, clamp(base_shake_amount, 0, NEAR_SHAKE_CAP))
+
+ else if(distance < far_distance) // You can hear a far explosion if you are outside the blast radius. Small explosions shouldn't be heard throughout the station.
+ var/far_volume = clamp(far_distance / 2, FAR_LOWER, FAR_UPPER)
+ if(creaking)
+ listener.playsound_local(epicenter, null, far_volume, TRUE, frequency, S = creaking_sound, distance_multiplier = 0)
+ else if(prob(FAR_SOUND_PROB)) // Sound variety during meteor storm/tesloose/other bad event
+ listener.playsound_local(epicenter, null, far_volume, TRUE, frequency, S = far_sound, distance_multiplier = 0)
+ else
+ listener.playsound_local(epicenter, null, far_volume, TRUE, frequency, S = echo_sound, distance_multiplier = 0)
+
+ if(base_shake_amount || quake_factor)
+ if(!base_shake_amount) // Devastating explosions rock the station and ground
+ base_shake_amount = quake_factor * 3
+ shake_camera(listener, FAR_SHAKE_DURATION, clamp(base_shake_amount / 4, 0, FAR_SHAKE_CAP))
+
+ else if(!isspaceturf(listener_turf) && echo_factor) // Big enough explosions echo through the hull.
+ var/echo_volume
+ if(quake_factor)
+ base_shake_amount = quake_factor
+ echo_volume = 60
+ shake_camera(listener, FAR_SHAKE_DURATION, clamp(base_shake_amount / 4, 0, FAR_SHAKE_CAP))
+ else
+ echo_volume = 40
+ listener.playsound_local(epicenter, null, echo_volume, TRUE, frequency, S = echo_sound, distance_multiplier = 0)
+
+ if(creaking) // 5 seconds after the bang, the station begins to creak
+ addtimer(CALLBACK(listener, /mob/proc/playsound_local, epicenter, null, rand(FREQ_LOWER, FREQ_UPPER), TRUE, frequency, null, null, FALSE, hull_creaking_sound, 0), CREAK_DELAY)
+
#undef CREAK_DELAY
-#undef DEVASTATION_PROB
-#undef HEAVY_IMPACT_PROB
+#undef QUAKE_CREAK_PROB
+#undef ECHO_CREAK_PROB
#undef FAR_UPPER
#undef FAR_LOWER
-#undef PROB_SOUND
-#undef SHAKE_CLAMP
+#undef FAR_SOUND_PROB
+#undef NEAR_SHAKE_CAP
+#undef FAR_SHAKE_CAP
+#undef NEAR_SHAKE_DURATION
+#undef FAR_SHAKE_DURATION
#undef FREQ_UPPER
#undef FREQ_LOWER
diff --git a/code/datums/components/explodable.dm b/code/datums/components/explodable.dm
index 360ab1dca84..0bc8214c2fc 100644
--- a/code/datums/components/explodable.dm
+++ b/code/datums/components/explodable.dm
@@ -1,14 +1,21 @@
///Component specifically for explosion sensetive things, currently only applies to heat based explosions but can later perhaps be used for things that are dangerous to handle carelessly like nitroglycerin.
/datum/component/explodable
+ /// The devastation range of the resulting explosion.
var/devastation_range = 0
+ /// The heavy impact range of the resulting explosion.
var/heavy_impact_range = 0
+ /// The light impact range of the resulting explosion.
var/light_impact_range = 2
+ /// The flame range of the resulting explosion.
+ var/flame_range = 0
+ /// The flash range of the resulting explosion.
var/flash_range = 3
- var/equipped_slot //For items, lets us determine where things should be hit.
- ///wheter we always delete. useful for nukes turned plasma and such, so they don't default delete and can survive
+ /// For items, lets us determine where things should be hit.
+ var/equipped_slot
+ /// Whether we always delete. Useful for nukes turned plasma and such, so they don't default delete and can survive
var/always_delete
-/datum/component/explodable/Initialize(devastation_range_override, heavy_impact_range_override, light_impact_range_override, flash_range_override, _always_delete = TRUE)
+/datum/component/explodable/Initialize(devastation_range_override, heavy_impact_range_override, light_impact_range_override, flame_range_override, flash_range_override, _always_delete = TRUE)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
@@ -31,6 +38,8 @@
heavy_impact_range = heavy_impact_range_override
if(light_impact_range_override)
light_impact_range = light_impact_range_override
+ if(flame_range_override)
+ flame_range = flame_range_override
if(flash_range_override)
flash_range = flash_range_override
always_delete = _always_delete
@@ -123,7 +132,7 @@
var/log = TRUE
if(light_impact_range < 1)
log = FALSE
- explosion(A, devastation_range, heavy_impact_range, light_impact_range, flash_range, log) //epic explosion time
+ explosion(A, devastation_range, heavy_impact_range, light_impact_range, flame_range, flash_range, log) //epic explosion time
if(always_delete)
qdel(A)
diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm
index 009ad1ecc90..064f39c8888 100644
--- a/code/datums/components/uplink.dm
+++ b/code/datums/components/uplink.dm
@@ -354,5 +354,5 @@
return
message_admins("[ADMIN_LOOKUPFLW(user)] has triggered an uplink failsafe explosion at [AREACOORD(T)] The owner of the uplink was [ADMIN_LOOKUPFLW(owner)].")
log_game("[key_name(user)] triggered an uplink failsafe explosion. The owner of the uplink was [key_name(owner)].")
- explosion(T,1,2,3)
+ explosion(parent, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3)
qdel(parent) //Alternatively could brick the uplink.
diff --git a/code/datums/diseases/advance/symptoms/fire.dm b/code/datums/diseases/advance/symptoms/fire.dm
index 7424c155d46..fa446eb077a 100644
--- a/code/datums/diseases/advance/symptoms/fire.dm
+++ b/code/datums/diseases/advance/symptoms/fire.dm
@@ -147,7 +147,7 @@ Bonus
if(4)
if(M.fire_stacks < 0)
M.visible_message("[M]'s sweat sizzles and pops on contact with water!")
- explosion(get_turf(M),-1,(-1 + explosion_power),(2 * explosion_power))
+ explosion(M, devastation_range = -1, heavy_impact_range = (-1 + explosion_power), light_impact_range = (2 * explosion_power))
Alkali_fire_stage_4(M, A)
M.IgniteMob()
to_chat(M, "Your sweat bursts into flames!")
@@ -155,7 +155,7 @@ Bonus
if(5)
if(M.fire_stacks < 0)
M.visible_message("[M]'s sweat sizzles and pops on contact with water!")
- explosion(get_turf(M),-1,(-1 + explosion_power),(2 * explosion_power))
+ explosion(M, devastation_range = -1, heavy_impact_range = (-1 + explosion_power), light_impact_range = (2 * explosion_power))
Alkali_fire_stage_5(M, A)
M.IgniteMob()
to_chat(M, "Your skin erupts into an inferno!")
diff --git a/code/datums/diseases/rhumba_beat.dm b/code/datums/diseases/rhumba_beat.dm
index 32c81f43be2..91c06097bcc 100644
--- a/code/datums/diseases/rhumba_beat.dm
+++ b/code/datums/diseases/rhumba_beat.dm
@@ -39,4 +39,4 @@
if(5)
to_chat(affected_mob, "Your body is unable to contain the Rhumba Beat...")
if(DT_PROB(29, delta_time))
- explosion(get_turf(affected_mob), -1, 0, 2, 3, 0, 2) // This is equivalent to a lvl 1 fireball
+ explosion(affected_mob, devastation_range = -1, light_impact_range = 2, flame_range = 2, flash_range = 3, adminlog = FALSE) // This is equivalent to a lvl 1 fireball
diff --git a/code/datums/martial/plasma_fist.dm b/code/datums/martial/plasma_fist.dm
index 5f06345acd2..71799e7f0fa 100644
--- a/code/datums/martial/plasma_fist.dm
+++ b/code/datums/martial/plasma_fist.dm
@@ -84,10 +84,10 @@
animate(A, color = oldcolor, time = 3 SECONDS)
-/datum/martial_art/plasma_fist/proc/Apotheosis(mob/living/A, mob/living/D)
- A.say("APOTHEOSIS!!", forced="plasma fist")
- if (ishuman(A))
- var/mob/living/carbon/human/human_attacker = A
+/datum/martial_art/plasma_fist/proc/Apotheosis(mob/living/user, mob/living/target)
+ user.say("APOTHEOSIS!!", forced="plasma fist")
+ if (ishuman(user))
+ var/mob/living/carbon/human/human_attacker = user
human_attacker.set_species(/datum/species/plasmaman)
human_attacker.dna.species.species_traits += TRAIT_BOMBIMMUNE
human_attacker.unequip_everything()
@@ -95,20 +95,20 @@
human_attacker.undershirt = "Nude"
human_attacker.socks = "Nude"
human_attacker.update_body()
- var/turf/boomspot = get_turf(A)
+ var/turf/boomspot = get_turf(user)
//before ghosting to prevent issues
- log_combat(A, A, "triggered final plasma explosion with size [plasma_power], [plasma_power*2], [plasma_power*4] (Plasma Fist)")
- message_admins("[key_name_admin(A)] triggered final plasma explosion with size [plasma_power], [plasma_power*2], [plasma_power*4].")
+ log_combat(user, user, "triggered final plasma explosion with size [plasma_power], [plasma_power*2], [plasma_power*4] (Plasma Fist)")
+ message_admins("[key_name_admin(user)] triggered final plasma explosion with size [plasma_power], [plasma_power*2], [plasma_power*4].")
- to_chat(A, "The explosion knocks your soul out of your body!")
- A.ghostize(FALSE) //prevents... horrible memes just believe me
+ to_chat(user, "The explosion knocks your soul out of your body!")
+ user.ghostize(FALSE) //prevents... horrible memes just believe me
- A.apply_damage(rand(50,70), BRUTE)
+ user.apply_damage(rand(50,70), BRUTE)
- addtimer(CALLBACK(src,.proc/Apotheosis_end, A), 6 SECONDS)
+ addtimer(CALLBACK(src,.proc/Apotheosis_end, user), 6 SECONDS)
playsound(boomspot, 'sound/weapons/punch1.ogg', 50, TRUE, -1)
- explosion(boomspot,plasma_power,plasma_power*2,plasma_power*4,ignorecap = TRUE)
+ explosion(user, devastation_range = plasma_power, heavy_impact_range = plasma_power*2, light_impact_range = plasma_power*4, ignorecap = TRUE)
plasma_power = 1 //just in case there is any clever way to cause it to happen again
/datum/martial_art/plasma_fist/proc/Apotheosis_end(mob/living/dying)
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index 4cad06fe31c..0f4765cdeea 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -120,7 +120,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
. = ..()
if(ismovable(source))
source.AddElement(/datum/element/firestacker, amount=1)
- source.AddComponent(/datum/component/explodable, 0, 0, amount / 2500, amount / 1250)
+ source.AddComponent(/datum/component/explodable, 0, 0, amount / 2500, 0, amount / 1250)
/datum/material/plasma/on_removed(atom/source, amount, material_flags)
. = ..()
diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm
index 9adf316db83..e42eecf1229 100644
--- a/code/datums/mutations/body.dm
+++ b/code/datums/mutations/body.dm
@@ -451,7 +451,7 @@
for(var/obj/item/organ/I in organs)
qdel(I)
- explosion(get_turf(owner), 0, 0, 2, 0, TRUE)
+ explosion(owner, light_impact_range = 2, adminlog = TRUE)
for(var/mob/living/carbon/human/H in view(2,owner))
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 14c1efc82c8..3e6e381e9b5 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -728,7 +728,7 @@
/obj/machinery/zap_act(power, zap_flags)
if(prob(85) && (zap_flags & ZAP_MACHINE_EXPLOSIVE) && !(resistance_flags & INDESTRUCTIBLE))
- explosion(src, 1, 2, 4, flame_range = 2, adminlog = FALSE, smoke = FALSE)
+ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 2, adminlog = FALSE, smoke = FALSE)
else if(zap_flags & ZAP_OBJ_DAMAGE)
take_damage(power * 0.0005, BURN, ENERGY)
if(prob(40))
diff --git a/code/game/machinery/computer/arcade/arcade.dm b/code/game/machinery/computer/arcade/arcade.dm
index 604df2883e0..3ccf14fba3a 100644
--- a/code/game/machinery/computer/arcade/arcade.dm
+++ b/code/game/machinery/computer/arcade/arcade.dm
@@ -123,7 +123,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list(
else
empprize = pickweight(GLOB.arcade_prize_pool)
new empprize(loc)
- explosion(loc, -1, 0, 1+num_of_prizes, flame_range = 1+num_of_prizes)
+ explosion(src, devastation_range = -1, light_impact_range = 1+num_of_prizes, flame_range = 1+num_of_prizes)
/obj/machinery/computer/arcade/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/stack/arcadeticket))
diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm
index dc9f1e88dde..c418a8f5f69 100644
--- a/code/game/machinery/computer/arcade/orion.dm
+++ b/code/game/machinery/computer/arcade/orion.dm
@@ -531,7 +531,7 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events())
playsound(loc, 'sound/machines/buzz-sigh.ogg', 25, TRUE)
sleep(3.6)
visible_message("[src] explodes!")
- explosion(loc, 2,4,8, flame_range = 16)
+ explosion(src, devastation_range = 2, heavy_impact_range = 4, light_impact_range = 8, flame_range = 16)
qdel(src)
#undef ORION_TRAIL_WINTURN
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index b0052d8775b..8c7f26694b5 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -459,7 +459,7 @@
/obj/machinery/door/ex_act(severity, target)
//if it blows up a wall it should blow up a door
- return ..(severity ? max(1, severity - 1) : 0, target)
+ return ..(severity ? min(EXPLODE_DEVASTATE, severity + 1) : EXPLODE_NONE, target)
/obj/machinery/door/GetExplosionBlock()
return density ? real_explosion_block : 0
diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm
index 79510b3dc21..67e8af0ccd8 100644
--- a/code/game/machinery/doors/poddoor.dm
+++ b/code/game/machinery/doors/poddoor.dm
@@ -151,7 +151,7 @@
//"BLAST" doors are obviously stronger than regular doors when it comes to BLASTS.
/obj/machinery/door/poddoor/ex_act(severity, target)
- if(severity == EXPLODE_LIGHT)
+ if(severity <= EXPLODE_LIGHT)
return FALSE
return ..()
diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm
index 5cbb77270c1..5410e0bd566 100644
--- a/code/game/machinery/syndicatebomb.dm
+++ b/code/game/machinery/syndicatebomb.dm
@@ -298,7 +298,7 @@
if(adminlog)
message_admins(adminlog)
log_game(adminlog)
- explosion(src, range_heavy, range_medium, range_light, flame_range = range_flame)
+ explosion(src, range_heavy, range_medium, range_light, range_flame)
if(loc && istype(loc, /obj/machinery/syndicatebomb/))
qdel(loc)
qdel(src)
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index d651b767468..cfd9a318e42 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -75,7 +75,7 @@
return
/obj/effect/anomaly/ex_act(severity, target)
- if(severity == EXPLODE_DEVASTATE)
+ if(severity >= EXPLODE_DEVASTATE)
qdel(src)
/obj/effect/anomaly/proc/anomalyNeutralize()
@@ -192,7 +192,7 @@
/obj/effect/anomaly/flux/detonate()
if(explosive)
- explosion(src, 1, 4, 16, 18) //Low devastation, but hits a lot of stuff.
+ explosion(src, devastation_range = 1, heavy_impact_range = 4, light_impact_range = 16, flash_range = 18) //Low devastation, but hits a lot of stuff.
else
new /obj/effect/particle_effect/sparks(loc)
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index be1a4005910..0da93d9043e 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -69,10 +69,10 @@
else
return ..()
-/obj/effect/decal/cleanable/ex_act()
+/obj/effect/decal/cleanable/ex_act(severity)
if(reagents)
for(var/datum/reagent/R in reagents.reagent_list)
- R.on_ex_act()
+ R.on_ex_act(severity)
return ..()
/obj/effect/decal/cleanable/fire_act(exposed_temperature, exposed_volume)
diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm
index 847daa4766b..3272e3dd452 100644
--- a/code/game/objects/effects/decals/cleanable/misc.dm
+++ b/code/game/objects/effects/decals/cleanable/misc.dm
@@ -181,7 +181,7 @@
mergeable_decal = FALSE
/obj/effect/decal/cleanable/shreds/ex_act(severity, target)
- if(severity == EXPLODE_DEVASTATE) //so shreds created during an explosion aren't deleted by the explosion.
+ if(severity >= EXPLODE_DEVASTATE) //so shreds created during an explosion aren't deleted by the explosion.
qdel(src)
/obj/effect/decal/cleanable/shreds/Initialize(mapload, oldname)
diff --git a/code/game/objects/effects/effect_system/effects_other.dm b/code/game/objects/effects/effect_system/effects_other.dm
index 49b3869f140..bd8816b92da 100644
--- a/code/game/objects/effects/effect_system/effects_other.dm
+++ b/code/game/objects/effects/effect_system/effects_other.dm
@@ -105,4 +105,4 @@
location.visible_message("The solution violently explodes!", \
"You hear an explosion!")
- dyn_explosion(location, amount, flashing_factor)
+ dyn_explosion(location, amount, flash_range = flashing_factor)
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index fcb1d958789..e435b2937ca 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -72,13 +72,19 @@
/obj/effect/mine/explosive
name = "explosive mine"
+ /// The devastation range of the resulting explosion.
var/range_devastation = 0
+ /// The heavy impact range of the resulting explosion.
var/range_heavy = 1
+ /// The light impact range of the resulting explosion.
var/range_light = 2
+ /// The flame range of the resulting explosion.
+ var/range_flame = 0
+ /// The flash range of the resulting explosion.
var/range_flash = 3
/obj/effect/mine/explosive/mineEffect(mob/victim)
- explosion(loc, range_devastation, range_heavy, range_light, range_flash)
+ explosion(src, range_devastation, range_heavy, range_light, range_flame, range_flash)
/obj/effect/mine/stun
name = "stun mine"
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index 6042db68e20..a5eb11898c1 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -758,7 +758,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window())
addtimer(CALLBACK(src, .proc/detonate_pulse_explode), 50)
/obj/item/construction/rcd/proc/detonate_pulse_explode()
- explosion(src, 0, 0, 3, 1, flame_range = 1)
+ explosion(src, light_impact_range = 3, flame_range = 1, flash_range = 1)
qdel(src)
/obj/item/construction/rcd/update_overlays()
diff --git a/code/game/objects/items/crab17.dm b/code/game/objects/items/crab17.dm
index 12637a3e485..d57cf15d188 100644
--- a/code/game/objects/items/crab17.dm
+++ b/code/game/objects/items/crab17.dm
@@ -158,7 +158,7 @@
stop_dumping()
STOP_PROCESSING(SSfastprocess, src)
priority_announce("The credit deposit machine at [get_area(src)] has been destroyed. Station funds have stopped draining!", sender_override = "CRAB-17 Protocol")
- explosion(src, 0,0,1, flame_range = 2)
+ explosion(src, light_impact_range = 1, flame_range = 2)
SSeconomy.market_crashing = FALSE
return ..()
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index be9a6be50ee..9560494a9d7 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -1119,9 +1119,9 @@ GLOBAL_LIST_EMPTY(PDAs)
if(T)
T.hotspot_expose(700,125)
if(istype(cartridge, /obj/item/cartridge/virus/syndicate))
- explosion(T, -1, 1, 3, 4)
+ explosion(src, devastation_range = -1, heavy_impact_range = 1, light_impact_range = 3, flash_range = 4)
else
- explosion(T, -1, -1, 2, 3)
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flash_range = 3)
qdel(src)
return
diff --git a/code/game/objects/items/devices/portable_chem_mixer.dm b/code/game/objects/items/devices/portable_chem_mixer.dm
index 7e666969234..c1a4dbc7cd4 100644
--- a/code/game/objects/items/devices/portable_chem_mixer.dm
+++ b/code/game/objects/items/devices/portable_chem_mixer.dm
@@ -36,7 +36,7 @@
return ..()
/obj/item/storage/portable_chem_mixer/ex_act(severity, target)
- if(severity < EXPLODE_LIGHT)
+ if(severity > EXPLODE_LIGHT)
return ..()
/obj/item/storage/portable_chem_mixer/attackby(obj/item/I, mob/user, params)
diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm
index 76f8e95ac29..3681eecea2a 100644
--- a/code/game/objects/items/devices/powersink.dm
+++ b/code/game/objects/items/devices/powersink.dm
@@ -159,7 +159,7 @@
if(power_drained >= max_power)
STOP_PROCESSING(SSobj, src)
- explosion(src.loc, 4,8,16,32)
+ explosion(src, devastation_range = 4, heavy_impact_range = 8, light_impact_range = 16, flash_range = 32)
qdel(src)
#undef DISCONNECTED
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 1c1725057e5..0de5775ee96 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -19,6 +19,17 @@
/obj/item/transfer_valve/IsAssemblyHolder()
return TRUE
+/obj/item/transfer_valve/handle_atom_del(atom/deleted_atom)
+ . = ..()
+ if(deleted_atom == tank_one)
+ tank_one = null
+ update_appearance()
+ return
+ if(deleted_atom == tank_two)
+ tank_two = null
+ update_appearance()
+ return
+
/obj/item/transfer_valve/attackby(obj/item/item, mob/user, params)
if(istype(item, /obj/item/tank))
if(tank_one && tank_two)
diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm
index 4b285e7344e..3df423b7fdf 100644
--- a/code/game/objects/items/granters.dm
+++ b/code/game/objects/items/granters.dm
@@ -159,7 +159,7 @@
/obj/item/book/granter/spell/fireball/recoil(mob/user)
..()
- explosion(user.loc, 1, 0, 2, 3, FALSE, FALSE, 2)
+ explosion(user, devastation_range = 1, light_impact_range = 2, flame_range = 2, flash_range = 3, adminlog = FALSE)
qdel(src)
/obj/item/book/granter/spell/sacredflame
diff --git a/code/game/objects/items/grenades/festive.dm b/code/game/objects/items/grenades/festive.dm
index 4f68e7c1267..0ec661c9814 100644
--- a/code/game/objects/items/grenades/festive.dm
+++ b/code/game/objects/items/grenades/festive.dm
@@ -113,8 +113,7 @@
/obj/item/grenade/firecracker/detonate(mob/living/lanced_by)
. = ..()
update_mob()
- var/explosion_loc = get_turf(src)
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2)
qdel(src)
- explosion(explosion_loc,-1,-1,2)
diff --git a/code/game/objects/items/grenades/ghettobomb.dm b/code/game/objects/items/grenades/ghettobomb.dm
index c9fe83ae22f..d9cfcd1d9f6 100644
--- a/code/game/objects/items/grenades/ghettobomb.dm
+++ b/code/game/objects/items/grenades/ghettobomb.dm
@@ -66,7 +66,7 @@
/obj/item/grenade/iedcasing/detonate(mob/living/lanced_by) //Blowing that can up
. = ..()
update_mob()
- explosion(src.loc,-1,-1,2, flame_range = 4) // small explosion, plus a very large fireball.
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flame_range = 4) // small explosion, plus a very large fireball.
qdel(src)
/obj/item/grenade/iedcasing/change_det_time()
diff --git a/code/game/objects/items/grenades/grenade.dm b/code/game/objects/items/grenades/grenade.dm
index eae73e59817..23f90340409 100644
--- a/code/game/objects/items/grenades/grenade.dm
+++ b/code/game/objects/items/grenades/grenade.dm
@@ -122,7 +122,7 @@
SEND_SIGNAL(src, COMSIG_GRENADE_DETONATE, lanced_by)
if(ex_dev || ex_heavy || ex_light || ex_flame)
- explosion(loc, ex_dev, ex_heavy, ex_light, flame_range = ex_flame)
+ explosion(src, ex_dev, ex_heavy, ex_light, ex_flame)
/obj/item/grenade/proc/update_mob()
if(ismob(loc))
diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm
index b48ba4d4ecb..d9e0cb4a648 100644
--- a/code/game/objects/items/grenades/plastic.dm
+++ b/code/game/objects/items/grenades/plastic.dm
@@ -59,9 +59,9 @@
if(location)
if(directional && target?.density)
var/turf/T = get_step(location, aim_dir)
- explosion(get_step(T, aim_dir), boom_sizes[1], boom_sizes[2], boom_sizes[3])
+ explosion(get_step(T, aim_dir), devastation_range = boom_sizes[1], heavy_impact_range = boom_sizes[2], light_impact_range = boom_sizes[3])
else
- explosion(location, boom_sizes[1], boom_sizes[2], boom_sizes[3])
+ explosion(location, devastation_range = boom_sizes[1], heavy_impact_range = boom_sizes[2], light_impact_range = boom_sizes[3])
qdel(src)
//assembly stuff
@@ -148,7 +148,7 @@
log_game("[key_name(user)] suicided with [src] at [AREACOORD(user)]")
user.visible_message("[user] activates [src] and holds it above [user.p_their()] head! It looks like [user.p_theyre()] going out with a bang!")
shout_syndicate_crap(user)
- explosion(user,0,2,0) //Cheap explosion imitation because putting detonate() here causes runtimes
+ explosion(user, heavy_impact_range = 2) //Cheap explosion imitation because putting detonate() here causes runtimes
user.gib(1, 1)
qdel(src)
diff --git a/code/game/objects/items/hot_potato.dm b/code/game/objects/items/hot_potato.dm
index 1c0b3c0dbf5..02874eafad5 100644
--- a/code/game/objects/items/hot_potato.dm
+++ b/code/game/objects/items/hot_potato.dm
@@ -52,7 +52,7 @@
var/atom/location = loc
location.visible_message("[src] [detonate_explosion? "explodes" : "activates"]!", "[src] activates! You've ran out of time!")
if(detonate_explosion)
- explosion(src, detonate_dev_range, detonate_heavy_range, detonate_light_range, detonate_flash_range, flame_range = detonate_fire_range)
+ explosion(src, detonate_dev_range, detonate_heavy_range, detonate_light_range, detonate_fire_range, detonate_flash_range)
deactivate()
if(!reusable)
var/mob/M = loc
diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm
index f505dd338d3..c854193b042 100644
--- a/code/game/objects/items/implants/implant_explosive.dm
+++ b/code/game/objects/items/implants/implant_explosive.dm
@@ -51,7 +51,7 @@
message_admins("[ADMIN_LOOKUPFLW(imp_in)] has activated their [name] at [ADMIN_VERBOSEJMP(boomturf)], with cause of [cause].")
//If the delay is short, just blow up already jeez
if(delay <= 7)
- explosion(src,heavy,medium,weak,weak, flame_range = weak)
+ explosion(src, devastation_range = heavy, heavy_impact_range = medium, light_impact_range = weak, flame_range = weak, flash_range = weak)
if(imp_in)
imp_in.gib(1)
qdel(src)
@@ -86,7 +86,7 @@
sleep(delay*0.25)
playsound(loc, 'sound/items/timer.ogg', 30, FALSE)
sleep(delay*0.25)
- explosion(src,heavy,medium,weak,weak, flame_range = weak)
+ explosion(src, devastation_range = heavy, heavy_impact_range = medium, light_impact_range = weak, flame_range = weak, flash_range = weak)
if(imp_in)
imp_in.gib(1)
qdel(src)
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index 8f5d60ee69c..e8bb8593deb 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -473,7 +473,7 @@
P.say(pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-"))
playsound(src, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, TRUE, frequency = 2)
playsound(P, 'sound/magic/demon_dies.ogg', 50, TRUE, frequency = 2)
- explosion(P, 0, 0, 1)
+ explosion(P, light_impact_range = 1)
qdel(P)
clash_target = null
else
@@ -481,7 +481,7 @@
P.say(pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here."))
playsound(src, 'sound/magic/clockwork/anima_fragment_death.ogg', 62, TRUE, frequency = 2)
playsound(P, 'sound/magic/demon_attack1.ogg', 50, TRUE, frequency = 2)
- explosion(src, 0, 0, 1)
+ explosion(src, light_impact_range = 1)
qdel(src)
P.clashing = FALSE
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index f315b69e053..a0bcb731cb4 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -126,7 +126,7 @@
. += "It feels [descriptive]."
/obj/item/tank/deconstruct(disassembled = TRUE)
- var/turf/location = get_turf(src)
+ var/atom/location = loc
if(location)
location.assume_air(air_contents)
location.air_update_turf(FALSE, FALSE)
@@ -251,7 +251,7 @@
handle_tolerances(delta_time)
if(QDELETED(src) || !leaking || !air_contents)
return
- var/turf/location = get_turf(src)
+ var/atom/location = loc
if(!location)
return
var/datum/gas_mixture/leaked_gas = air_contents.remove_ratio(0.25)
@@ -298,10 +298,6 @@
if(!air_contents)
return ..()
- var/turf/location = get_turf(src)
- if(!location)
- return ..()
-
/// Handle fragmentation
var/pressure = air_contents.return_pressure()
if(pressure > TANK_FRAGMENT_PRESSURE)
@@ -312,7 +308,7 @@
pressure = air_contents.return_pressure()
var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE
- explosion(location, round(range*0.25), round(range*0.5), round(range), round(range*1.5))
+ explosion(src, devastation_range = round(range*0.25), heavy_impact_range = round(range*0.5), light_impact_range = round(range), flash_range = round(range*1.5))
return ..()
/obj/item/tank/rad_act(strength)
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 5997b2913ac..51a005aacaf 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -111,9 +111,8 @@
update_appearance()
/obj/item/weldingtool/proc/explode()
- var/turf/T = get_turf(loc)
var/plasmaAmount = reagents.get_reagent_amount(/datum/reagent/toxin/plasma)
- dyn_explosion(T, plasmaAmount/5)//20 plasma in a standard welder has a 4 power explosion. no breaches, but enough to kill/dismember holder
+ dyn_explosion(src, plasmaAmount/5)//20 plasma in a standard welder has a 4 power explosion. no breaches, but enough to kill/dismember holder
qdel(src)
/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/living/user)
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 103603c9ae4..fcd5860d152 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -1038,7 +1038,7 @@
playsound(src, 'sound/machines/alarm.ogg', 20, FALSE)
sleep(140)
user.visible_message("[src] violently explodes!")
- explosion(src, 0, 0, 1, 0)
+ explosion(src, light_impact_range = 1)
qdel(src)
else if (cooldown < world.time)
cooldown = world.time + 600 //1 minute
@@ -1081,7 +1081,7 @@
/obj/item/toy/minimeteor/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if (obj_flags & EMAGGED)
playsound(src, 'sound/effects/meteorimpact.ogg', 40, TRUE)
- explosion(get_turf(hit_atom), -1, -1, 1)
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 1)
for(var/mob/M in urange(10, src))
if(!M.stat && !isAI(M))
shake_camera(M, 3, 1)
diff --git a/code/game/objects/items/wayfinding.dm b/code/game/objects/items/wayfinding.dm
index a597d6eb766..6cd9158b83b 100644
--- a/code/game/objects/items/wayfinding.dm
+++ b/code/game/objects/items/wayfinding.dm
@@ -95,7 +95,7 @@
say("Ouch.")
//An inexplicable explosion is never not funny plus it kind of explains why the machine just disappears
if(!isnull(loc))
- explosion(get_turf(src), devastation_range = 0, heavy_impact_range = 0, light_impact_range = 1, flash_range = 3, flame_range = 1, smoke = TRUE)
+ explosion(src, light_impact_range = 1, flame_range = 1, flash_range = 3, smoke = TRUE)
return ..()
/obj/machinery/pinpointer_dispenser/attack_hand(mob/living/user, list/modifiers)
diff --git a/code/game/objects/structures/crates_lockers/crates/secure.dm b/code/game/objects/structures/crates_lockers/crates/secure.dm
index 44f4f4fd761..e08ec573f5e 100644
--- a/code/game/objects/structures/crates_lockers/crates/secure.dm
+++ b/code/game/objects/structures/crates_lockers/crates/secure.dm
@@ -32,7 +32,7 @@
log_bomber(user, "has detonated a", src)
for(var/atom/movable/AM in src)
qdel(AM)
- explosion(get_turf(src), 0, 1, 5, 5)
+ explosion(src, heavy_impact_range = 1, light_impact_range = 5, flash_range = 5)
qdel(src)
/obj/structure/closet/crate/secure/weapon
diff --git a/code/game/objects/structures/industrial_lift.dm b/code/game/objects/structures/industrial_lift.dm
index 1ca7a2a274d..fbeea2779eb 100644
--- a/code/game/objects/structures/industrial_lift.dm
+++ b/code/game/objects/structures/industrial_lift.dm
@@ -211,7 +211,7 @@ GLOBAL_LIST_EMPTY(lifts)
tram_part.travel_distance = 0
tram_part.travelling = FALSE
if(prob(15) || locate(/mob/living) in tram_part.lift_load) //always go boom on people on the track
- explosion(get_turf(tram_part),rand(0,1),2,3) //50% chance of gib
+ explosion(tram_part, devastation_range = rand(0,1), heavy_impact_range = 2, light_impact_range = 3) //50% chance of gib
qdel(tram_part)
/obj/structure/industrial_lift/proc/lift_platform_expansion(datum/lift_master/lift_master_datum)
diff --git a/code/game/objects/structures/training_machine.dm b/code/game/objects/structures/training_machine.dm
index 171557a4ffb..5086ea07cc3 100644
--- a/code/game/objects/structures/training_machine.dm
+++ b/code/game/objects/structures/training_machine.dm
@@ -49,7 +49,7 @@
*/
/obj/structure/training_machine/obj_destruction(damage_flag)
remove_attached_item(throwing = TRUE)
- explosion(src, 0,0,1, flame_range = 2)
+ explosion(src, light_impact_range = 1, flash_range = 2)
return ..()
/obj/structure/training_machine/ui_state(mob/user)
diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm
index 37b6a43f01c..33e55d0dd9f 100644
--- a/code/game/turfs/closed/minerals.dm
+++ b/code/game/turfs/closed/minerals.dm
@@ -567,7 +567,7 @@
var/turf/bombturf = get_turf(src)
mineralAmt = 0
stage = GIBTONITE_DETONATE
- explosion(bombturf,1,3,5, adminlog = notify_admins)
+ explosion(bombturf, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 5, adminlog = notify_admins)
/turf/closed/mineral/gibtonite/proc/defuse()
if(stage == GIBTONITE_ACTIVE)
@@ -589,7 +589,7 @@
var/turf/bombturf = get_turf(src)
mineralAmt = 0
stage = GIBTONITE_DETONATE
- explosion(bombturf,1,2,5, adminlog = FALSE)
+ explosion(bombturf, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 5, adminlog = FALSE)
if(stage == GIBTONITE_STABLE) //Gibtonite deposit is now benign and extractable. Depending on how close you were to it blowing up before defusing, you get better quality ore.
var/obj/item/gibtonite/G = new (src)
if(det_time <= 0)
diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm
index 1893c206454..b6a3836f477 100644
--- a/code/game/turfs/open/floor.dm
+++ b/code/game/turfs/open/floor.dm
@@ -66,7 +66,7 @@
if(target == src)
ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
return TRUE
- if(severity != EXPLODE_DEVASTATE && is_shielded())
+ if(severity < EXPLODE_DEVASTATE && is_shielded())
return FALSE
if(target)
diff --git a/code/game/turfs/open/floor/reinf_floor.dm b/code/game/turfs/open/floor/reinf_floor.dm
index b577cbed6af..9987c396974 100644
--- a/code/game/turfs/open/floor/reinf_floor.dm
+++ b/code/game/turfs/open/floor/reinf_floor.dm
@@ -58,7 +58,7 @@
if(target == src)
ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
return TRUE
- if(severity != EXPLODE_DEVASTATE && is_shielded())
+ if(severity < EXPLODE_DEVASTATE && is_shielded())
return FALSE
switch(severity)
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 732f77e6eb2..4343f068741 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -499,31 +499,31 @@ GLOBAL_PROTECT(admin_verbs_hideable)
if(null)
return
if("Small Bomb (1, 2, 3, 3)")
- explosion(epicenter, 1, 2, 3, 3, TRUE, TRUE)
+ explosion(epicenter, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flash_range = 3, adminlog = TRUE, ignorecap = TRUE)
if("Medium Bomb (2, 3, 4, 4)")
- explosion(epicenter, 2, 3, 4, 4, TRUE, TRUE)
+ explosion(epicenter, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4, flash_range = 4, adminlog = TRUE, ignorecap = TRUE)
if("Big Bomb (3, 5, 7, 5)")
- explosion(epicenter, 3, 5, 7, 5, TRUE, TRUE)
+ explosion(epicenter, devastation_range = 3, heavy_impact_range = 5, light_impact_range = 7, flash_range = 5, adminlog = TRUE, ignorecap = TRUE)
if("Maxcap")
- explosion(epicenter, GLOB.MAX_EX_DEVESTATION_RANGE, GLOB.MAX_EX_HEAVY_RANGE, GLOB.MAX_EX_LIGHT_RANGE, GLOB.MAX_EX_FLASH_RANGE)
+ explosion(epicenter, devastation_range = GLOB.MAX_EX_DEVESTATION_RANGE, heavy_impact_range = GLOB.MAX_EX_HEAVY_RANGE, light_impact_range = GLOB.MAX_EX_LIGHT_RANGE, flash_range = GLOB.MAX_EX_FLASH_RANGE, adminlog = TRUE, ignorecap = TRUE)
if("Custom Bomb")
- var/devastation_range = input("Devastation range (in tiles):") as null|num
- if(devastation_range == null)
+ var/range_devastation = input("Devastation range (in tiles):") as null|num
+ if(range_devastation == null)
return
- var/heavy_impact_range = input("Heavy impact range (in tiles):") as null|num
- if(heavy_impact_range == null)
+ var/range_heavy = input("Heavy impact range (in tiles):") as null|num
+ if(range_heavy == null)
return
- var/light_impact_range = input("Light impact range (in tiles):") as null|num
- if(light_impact_range == null)
+ var/range_light = input("Light impact range (in tiles):") as null|num
+ if(range_light == null)
return
- var/flash_range = input("Flash range (in tiles):") as null|num
- if(flash_range == null)
+ var/range_flash = input("Flash range (in tiles):") as null|num
+ if(range_flash == null)
return
- if(devastation_range > GLOB.MAX_EX_DEVESTATION_RANGE || heavy_impact_range > GLOB.MAX_EX_HEAVY_RANGE || light_impact_range > GLOB.MAX_EX_LIGHT_RANGE || flash_range > GLOB.MAX_EX_FLASH_RANGE)
+ if(range_devastation > GLOB.MAX_EX_DEVESTATION_RANGE || range_heavy > GLOB.MAX_EX_HEAVY_RANGE || range_light > GLOB.MAX_EX_LIGHT_RANGE || range_flash > GLOB.MAX_EX_FLASH_RANGE)
if(alert("Bomb is bigger than the maxcap. Continue?",,"Yes","No") != "Yes")
return
epicenter = mob.loc //We need to reupdate as they may have moved again
- explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, TRUE, TRUE)
+ explosion(epicenter, devastation_range = range_devastation, heavy_impact_range = range_heavy, light_impact_range = range_light, flash_range = range_flash, adminlog = TRUE, ignorecap = TRUE)
message_admins("[ADMIN_LOOKUPFLW(usr)] creating an admin explosion at [epicenter.loc].")
log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Bomb") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/smites/bsa.dm b/code/modules/admin/smites/bsa.dm
index 7df6bc8ad42..d8ba8e3e771 100644
--- a/code/modules/admin/smites/bsa.dm
+++ b/code/modules/admin/smites/bsa.dm
@@ -10,7 +10,7 @@
/datum/smite/bsa/effect(client/user, mob/living/target)
. = ..()
- explosion(target.loc, 0, 0, 0, 0)
+ explosion(target.loc)
var/turf/open/floor/target_turf = get_turf(target)
if (istype(target_turf))
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 149d9be1365..1b1d62a1a01 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -592,7 +592,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
if (alert(src, "Are you sure you want to do this? It will laaag.", "Confirmation", "Yes", "No") == "No")
return
- explosion(O, devastation, heavy, light, flash, null, null,flames)
+ explosion(O, devastation, heavy, light, flames, flash)
log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]")
message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Explosion") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/antagonists/blob/structures/core.dm b/code/modules/antagonists/blob/structures/core.dm
index 9d5d65a758f..f1828635a17 100644
--- a/code/modules/antagonists/blob/structures/core.dm
+++ b/code/modules/antagonists/blob/structures/core.dm
@@ -53,7 +53,7 @@
return ..()
/obj/structure/blob/special/core/ex_act(severity, target)
- var/damage = 50 - 10 * severity //remember, the core takes half brute damage, so this is 20/15/10 damage based on severity
+ var/damage = 10 * (severity + 1) //remember, the core takes half brute damage, so this is 20/15/10 damage based on severity
take_damage(damage, BRUTE, BOMB, 0)
/obj/structure/blob/special/core/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, overmind_reagent_trigger = 1)
diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm
index e96b5f4cf02..855fa4dc572 100644
--- a/code/modules/antagonists/changeling/powers/headcrab.dm
+++ b/code/modules/antagonists/changeling/powers/headcrab.dm
@@ -18,7 +18,7 @@
for(var/obj/item/organ/I in organs)
I.Remove(user, 1)
- explosion(get_turf(user), 0, 0, 2, 0, TRUE)
+ explosion(user, light_impact_range = 2, adminlog = TRUE)
for(var/mob/living/carbon/human/H in range(2,user))
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
to_chat(H, "You are blinded by a shower of blood!")
diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
index 19358d49ce3..6ef88f37df0 100644
--- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
+++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
@@ -515,7 +515,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
var/turf/T = get_turf(M)
message_admins("[ADMIN_LOOKUPFLW(usr)] overloaded [M.name] ([M.type]) at [ADMIN_VERBOSEJMP(T)].")
log_game("[key_name(usr)] overloaded [M.name] ([M.type]) at [AREACOORD(T)].")
- explosion(get_turf(M), 0, 2, 3, 0)
+ explosion(M, heavy_impact_range = 2, light_impact_range = 3)
if(M) //to check if the explosion killed it before we try to delete it
qdel(M)
diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm
index b89b2a2a776..00389085e45 100644
--- a/code/modules/assembly/bomb.dm
+++ b/code/modules/assembly/bomb.dm
@@ -161,13 +161,13 @@
strength = (fuel_moles/15)
if(strength >=2)
- explosion(ground_zero, round(strength,1), round(strength*2,1), round(strength*3,1), round(strength*4,1))
+ explosion(src, devastation_range = round(strength,1), heavy_impact_range = round(strength*2,1), light_impact_range = round(strength*3,1), flash_range = round(strength*4,1))
else if(strength >=1)
- explosion(ground_zero, round(strength,1), round(strength*2,1), round(strength*2,1), round(strength*3,1))
+ explosion(src, devastation_range = round(strength,1), heavy_impact_range = round(strength*2,1), light_impact_range = round(strength*2,1), flash_range = round(strength*3,1))
else if(strength >=0.5)
- explosion(ground_zero, 0, 1, 2, 4)
+ explosion(src, heavy_impact_range = 1, light_impact_range = 2, flash_range = 4)
else if(strength >=0.2)
- explosion(ground_zero, -1, 0, 1, 2)
+ explosion(src, devastation_range = -1, light_impact_range = 1, flash_range = 2)
else
ground_zero.assume_air(bomb_mixture)
ground_zero.hotspot_expose(1000, 125)
@@ -176,9 +176,9 @@
strength = (fuel_moles/20)
if(strength >=1)
- explosion(ground_zero, 0, round(strength,1), round(strength*2,1), round(strength*3,1))
+ explosion(ground_zero, heavy_impact_range = round(strength,1), light_impact_range = round(strength*2,1), flash_range = round(strength*3,1))
else if(strength >=0.5)
- explosion(ground_zero, -1, 0, 1, 2)
+ explosion(ground_zero, devastation_range = -1, light_impact_range = 1, flash_range = 2)
else
ground_zero.assume_air(bomb_mixture)
ground_zero.hotspot_expose(1000, 125)
@@ -187,7 +187,7 @@
strength = (fuel_moles/25)
if(strength >=1)
- explosion(ground_zero, -1, 0, round(strength,1), round(strength*3,1))
+ explosion(ground_zero, devastation_range = -1, light_impact_range = round(strength,1), flash_range = round(strength*3,1))
else
ground_zero.assume_air(bomb_mixture)
ground_zero.hotspot_expose(1000, 125)
diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm
index d2462a1ce97..8497b576893 100644
--- a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm
+++ b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm
@@ -309,7 +309,7 @@
* Create the explosion + the gas emission before deleting the machine core.
*/
/obj/machinery/atmospherics/components/unary/hypertorus/core/proc/meltdown()
- explosion(loc, 0, 0, power_level * 5, power_level * 6, 1, 1)
+ explosion(src, light_impact_range = power_level * 5, flash_range = power_level * 6, adminlog = TRUE, ignorecap = TRUE)
radiation_pulse(loc, power_level * 7000, (1 / (power_level + 5)), TRUE)
empulse(loc, power_level * 5, power_level * 7)
var/fusion_moles = internal_fusion.total_moles() ? internal_fusion.total_moles() : 0
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 97037eb5134..efef3d46c72 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -481,7 +481,7 @@ GLOBAL_LIST_INIT(gas_id_to_canister, init_gas_id_to_canister())
var/pressure_dif = expelled_pressure - pressure_limit
var/max_pressure_difference = 20000
var/explosion_range = CEILING(min(pressure_dif, max_pressure_difference) / 1000, 1)
- explosion(T, 0, 0, explosion_range, 0, smoke = FALSE)
+ explosion(T, light_impact_range = explosion_range, smoke = FALSE)
density = FALSE
playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
diff --git a/code/modules/awaymissions/bluespaceartillery.dm b/code/modules/awaymissions/bluespaceartillery.dm
index 9949840923b..2c1e30ba56d 100644
--- a/code/modules/awaymissions/bluespaceartillery.dm
+++ b/code/modules/awaymissions/bluespaceartillery.dm
@@ -51,5 +51,5 @@
for(var/turf/T in get_area_turfs(thearea.type))
L+=T
var/loc = pick(L)
- explosion(loc,explosiondev,explosionmed,explosionlight)
+ explosion(loc, explosiondev, explosionmed, explosionlight)
reload = 0
diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm
index 2bc8abd2de0..60ce808895a 100644
--- a/code/modules/awaymissions/mission_code/Academy.dm
+++ b/code/modules/awaymissions/mission_code/Academy.dm
@@ -271,7 +271,7 @@
if(8)
//Fuel tank Explosion
T.visible_message("An explosion bursts into existence around [user]!")
- explosion(get_turf(user),-1,0,2, flame_range = 2)
+ explosion(get_turf(user), devastation_range = -1, light_impact_range = 2, flame_range = 2)
if(9)
//Cold
var/datum/disease/D = new /datum/disease/cold()
diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm
index b2bf3bbd747..5b8467ec535 100644
--- a/code/modules/awaymissions/mission_code/wildwest.dm
+++ b/code/modules/awaymissions/mission_code/wildwest.dm
@@ -146,7 +146,7 @@
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, src)
s.start()
- explosion(M, 1, 0, 0, 0)
+ explosion(src, devastation_range = 1)
qdel(src)
/////For the Wishgranter///////////
diff --git a/code/modules/buildmode/submodes/boom.dm b/code/modules/buildmode/submodes/boom.dm
index a8460956a0c..d79f2164000 100644
--- a/code/modules/buildmode/submodes/boom.dm
+++ b/code/modules/buildmode/submodes/boom.dm
@@ -34,5 +34,5 @@
var/list/modifiers = params2list(params)
if(LAZYACCESS(modifiers, LEFT_CLICK))
- explosion(object, devastation, heavy, light, flash, FALSE, TRUE, flames)
+ explosion(object, devastation, heavy, light, flames, flash, adminlog = FALSE, ignorecap = TRUE)
log_admin("Build Mode: [key_name(c)] caused an explosion(dev=[devastation], hvy=[heavy], lgt=[light], flash=[flash], flames=[flames]) at [AREACOORD(object)]")
diff --git a/code/modules/events/crystal_event.dm b/code/modules/events/crystal_event.dm
index d17bbf14d8e..d48e417438b 100644
--- a/code/modules/events/crystal_event.dm
+++ b/code/modules/events/crystal_event.dm
@@ -121,7 +121,7 @@ This section is for the event controller
var/area/center_area = get_area(center_turf)
center_areas += center_area
- explosion(center_turf,0,0,5,7,7)
+ explosion(center_turf, light_impact_range = 5, flame_range = 7, flash_range = 7)
new /obj/structure/crystal_portal/huge(center_turf)
@@ -249,7 +249,7 @@ This section is for the event controller
spawners += temp
for(var/i in 1 to rand(15, 25))
spawn_portal(GLOB.crystal_invasion_waves["huge wave"], spawners)
- explosion(dest_crystal.loc, 15, 26, 33, 35, 1, 1) //a bit smaller than max supermatter explosion
+ explosion(dest_crystal, devastation_range = 15, heavy_impact_range = 26, light_impact_range = 33, flash_range = 35, adminlog = TRUE, ignorecap = TRUE) //a bit smaller than max supermatter explosion
priority_announce("WARNING - Portal are appearing everywhere, you failed to contain the event. You people should feel ashamed of yourselves!","Alarm")
QDEL_NULL(dest_crystal)
@@ -550,13 +550,13 @@ This section is for the crystal portals variations
if(!closed)
switch(name)
if("Small Portal")
- explosion(loc, 0,1,3)
+ explosion(src, heavy_impact_range = 1, light_impact_range = 3)
if("Medium Portal")
- explosion(loc, 0,3,5)
+ explosion(src, heavy_impact_range = 3, light_impact_range = 5)
if("Big Portal")
- explosion(loc, 1,3,5)
+ explosion(src, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 5)
if("Huge Portal")
- explosion(loc, 2,5,7)
+ explosion(src, devastation_range = 2, heavy_impact_range = 5, light_impact_range = 7)
new/obj/item/stack/sheet/otherworld_crystal(loc)
return ..()
diff --git a/code/modules/events/processor_overload.dm b/code/modules/events/processor_overload.dm
index 742af87fb2c..4ce140b6b85 100644
--- a/code/modules/events/processor_overload.dm
+++ b/code/modules/events/processor_overload.dm
@@ -31,7 +31,7 @@
if(prob(10))
announce_to_ghosts(P)
// Damage the surrounding area to indicate that it popped
- explosion(get_turf(P), 0, 0, 2)
+ explosion(P, light_impact_range = 2)
// Only a level 1 explosion actually damages the machine
// at all
SSexplosions.high_mov_atom += P
diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm
index e90a8a12a32..559c6cd6204 100644
--- a/code/modules/events/spacevine.dm
+++ b/code/modules/events/spacevine.dm
@@ -116,7 +116,7 @@
QDEL_IN(holder, 5)
/datum/spacevine_mutation/explosive/on_death(obj/structure/spacevine/holder, mob/hitter, obj/item/I)
- explosion(holder.loc, 0, 0, severity, 0, 0)
+ explosion(holder, light_impact_range = severity, adminlog = FALSE)
/datum/spacevine_mutation/fire_proof
name = "fire proof"
@@ -571,7 +571,7 @@
var/i
for(var/datum/spacevine_mutation/SM in mutations)
i += SM.on_explosion(severity, target, src)
- if(!i && prob(100/severity))
+ if(!i && prob(34 * severity))
qdel(src)
/obj/structure/spacevine/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
index 95e88e5ef6e..12bf6344d88 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
@@ -333,7 +333,7 @@
spark()
broken = 2
if(prob(max(metal / 2, 33)))
- explosion(loc, 0, 1, 2)
+ explosion(src, heavy_impact_range = 1, light_impact_range = 2)
else
dump_inventory_contents()
diff --git a/code/modules/hydroponics/grown/citrus.dm b/code/modules/hydroponics/grown/citrus.dm
index cfaafc94b40..0dfe1b5f5d6 100644
--- a/code/modules/hydroponics/grown/citrus.dm
+++ b/code/modules/hydroponics/grown/citrus.dm
@@ -133,23 +133,23 @@
switch(seed.potency) //Combustible lemons are alot like IEDs, lots of flame, very little bang.
if(0 to 30)
update_mob()
- explosion(src.loc,-1,-1,2, flame_range = 1)
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flame_range = 1)
qdel(src)
if(31 to 50)
update_mob()
- explosion(src.loc,-1,-1,2, flame_range = 2)
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flame_range = 2)
qdel(src)
if(51 to 70)
update_mob()
- explosion(src.loc,-1,-1,2, flame_range = 3)
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flame_range = 3)
qdel(src)
if(71 to 90)
update_mob()
- explosion(src.loc,-1,-1,2, flame_range = 4)
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flame_range = 4)
qdel(src)
else
update_mob()
- explosion(src.loc,-1,-1,2, flame_range = 5)
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flame_range = 5)
qdel(src)
//3D Orange
diff --git a/code/modules/meteors/meteors.dm b/code/modules/meteors/meteors.dm
index 986ef990c05..8950d77b435 100644
--- a/code/modules/meteors/meteors.dm
+++ b/code/modules/meteors/meteors.dm
@@ -91,7 +91,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
density = TRUE
anchored = TRUE
var/hits = 4
- var/hitpwr = 2 //Level of ex_act to be called on hit.
+ var/hitpwr = EXPLODE_HEAVY //Level of ex_act to be called on hit.
var/dest
pass_flags = PASSTABLE
var/heavy = FALSE
@@ -223,7 +223,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
icon_state = "dust"
pass_flags = PASSTABLE | PASSGRILLE
hits = 1
- hitpwr = 3
+ hitpwr = EXPLODE_LIGHT
meteorsound = 'sound/weapons/gun/smg/shot.ogg'
meteordrop = list(/obj/item/stack/ore/glass)
threat = 1
@@ -236,7 +236,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
/obj/effect/meteor/medium/meteor_effect()
..()
- explosion(src.loc, 0, 1, 2, 3, 0)
+ explosion(src, heavy_impact_range = 1, light_impact_range = 2, flash_range = 3, adminlog = FALSE)
//Large-sized
/obj/effect/meteor/big
@@ -249,7 +249,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
/obj/effect/meteor/big/meteor_effect()
..()
- explosion(src.loc, 1, 2, 3, 4, 0)
+ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flash_range = 4, adminlog = FALSE)
//Flaming meteor
/obj/effect/meteor/flaming
@@ -263,7 +263,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
/obj/effect/meteor/flaming/meteor_effect()
..()
- explosion(src.loc, 1, 2, 3, 4, 0, 0, 5)
+ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flame_range = 5, flash_range = 4, adminlog = FALSE)
//Radiation meteor
/obj/effect/meteor/irradiated
@@ -276,7 +276,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
/obj/effect/meteor/irradiated/meteor_effect()
..()
- explosion(src.loc, 0, 0, 4, 3, 0)
+ explosion(src, light_impact_range = 4, flash_range = 3, adminlog = FALSE)
new /obj/effect/decal/cleanable/greenglow(get_turf(src))
radiation_pulse(src, 500)
@@ -337,7 +337,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
icon_state = "flaming"
desc = "Your life briefly passes before your eyes the moment you lay them on this monstrosity."
hits = 30
- hitpwr = 1
+ hitpwr = EXPLODE_DEVASTATE
heavy = TRUE
meteorsound = 'sound/effects/bamf.ogg'
meteordrop = list(/obj/item/stack/ore/plasma)
@@ -350,12 +350,12 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
/obj/effect/meteor/tunguska/meteor_effect()
..()
- explosion(src.loc, 5, 10, 15, 20, 0)
+ explosion(src, devastation_range = 5, heavy_impact_range = 10, light_impact_range = 15, flash_range = 20, adminlog = FALSE)
/obj/effect/meteor/tunguska/Bump()
..()
if(prob(20))
- explosion(src.loc,2,4,6,8)
+ explosion(src, devastation_range = 2, heavy_impact_range = 4, light_impact_range = 6, flash_range = 8, adminlog = FALSE)
//////////////////////////
//Spookoween meteors
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 3327d425f77..92ab899b131 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -204,7 +204,7 @@
/obj/machinery/mineral/equipment_vendor/ex_act(severity, target)
do_sparks(5, TRUE, src)
- if(prob(50 / severity) && severity < EXPLODE_LIGHT)
+ if(severity > EXPLODE_LIGHT && prob(17 * severity))
qdel(src)
/****************Golem Point Vendor**************************/
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index c3771b741c6..b111e12f2f3 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -131,7 +131,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
qdel(src)
/obj/item/stack/ore/glass/ex_act(severity, target)
- if(severity != EXPLODE_NONE)
+ if(severity)
qdel(src)
/obj/item/stack/ore/glass/basalt
@@ -321,11 +321,11 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
if(primed)
switch(quality)
if(GIBTONITE_QUALITY_HIGH)
- explosion(src,2,4,9,adminlog = notify_admins)
+ explosion(src, devastation_range = 2, heavy_impact_range = 4, light_impact_range = 9, adminlog = notify_admins)
if(GIBTONITE_QUALITY_MEDIUM)
- explosion(src,1,2,5,adminlog = notify_admins)
+ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 5, adminlog = notify_admins)
if(GIBTONITE_QUALITY_LOW)
- explosion(src,0,1,3,adminlog = notify_admins)
+ explosion(src, heavy_impact_range = 1, light_impact_range = 3, adminlog = notify_admins)
qdel(src)
/obj/item/stack/ore/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1)
@@ -334,7 +334,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
pixel_y = base_pixel_y + rand(0, 8) - 8
/obj/item/stack/ore/ex_act(severity, target)
- if(severity == EXPLODE_DEVASTATE)
+ if(severity >= EXPLODE_DEVASTATE)
qdel(src)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 5dcdaa0d9ca..d9b86cc799b 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -435,7 +435,7 @@
take_overall_damage(brute_loss,burn_loss)
//attempt to dismember bodyparts
- if(severity <= EXPLODE_HEAVY || !bomb_armor)
+ if(severity >= EXPLODE_HEAVY || !bomb_armor)
var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3.
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index da5311be591..43cab939dc5 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -134,7 +134,7 @@
boom_warning = FALSE
if(H.bodytemperature > 850 && H.on_fire && prob(25))
- explosion(get_turf(H), 1, 2, 4, flame_range = 5)
+ explosion(H, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 5)
if(H)
H.gib()
if(H.fire_stacks < 2) //flammable
diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm
index 445db853fed..892d593b821 100644
--- a/code/modules/mob/living/silicon/ai/death.dm
+++ b/code/modules/mob/living/silicon/ai/death.dm
@@ -33,7 +33,7 @@
ShutOffDoomsdayDevice()
if(explosive)
- addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, loc, 3, 6, 12, 15), 1 SECONDS)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, loc, 3, 6, 12, null, 15), 1 SECONDS)
if(istype(loc, /obj/item/aicard/aitater))
loc.icon_state = "aitater-404"
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
index 92bf7ea215a..7d930fa79e9 100644
--- a/code/modules/mob/living/silicon/pai/pai_defense.dm
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -28,7 +28,7 @@
/mob/living/silicon/pai/ex_act(severity, target)
- take_holo_damage(severity * 50)
+ take_holo_damage(50 * severity)
switch(severity)
if(EXPLODE_DEVASTATE) //RIP
qdel(card)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 0f29093ad59..a934c19e062 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -395,9 +395,9 @@
/mob/living/silicon/robot/proc/self_destruct()
if(emagged)
QDEL_NULL(mmi)
- explosion(loc,1,2,4,flame_range = 2)
+ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 2)
else
- explosion(loc,-1,0,2)
+ explosion(src, devastation_range = -1, light_impact_range = 2)
gib()
/mob/living/silicon/robot/proc/UnlinkSelf()
diff --git a/code/modules/mob/living/simple_animal/guardian/types/protector.dm b/code/modules/mob/living/simple_animal/guardian/types/protector.dm
index 2eeb8573343..b042372af21 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/protector.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/protector.dm
@@ -13,7 +13,7 @@
var/toggle = FALSE
/mob/living/simple_animal/hostile/guardian/protector/ex_act(severity)
- if(severity == EXPLODE_DEVASTATE)
+ if(severity >= EXPLODE_DEVASTATE)
adjustBruteLoss(400) //if in protector mode, will do 20 damage and not actually necessarily kill the summoner
else
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index 91699a3367d..32b7fc6cd9f 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -438,7 +438,7 @@ Difficulty: Hard
return ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/ex_act(severity, target)
- if(severity >= EXPLODE_LIGHT)
+ if(severity <= EXPLODE_LIGHT)
return FALSE
severity = EXPLODE_LIGHT // puny mortals
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
index 9d8245545ac..067dc2e9240 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
@@ -151,7 +151,7 @@ Difficulty: Extremely Hard
target.ex_act(EXPLODE_HEAVY)
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/ex_act(severity, target)
- adjustBruteLoss((30 * severity) - 120)
+ adjustBruteLoss(-30 * severity)
visible_message("[src] absorbs the explosion!", "You absorb the explosion!")
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Goto(target, delay, minimum_distance)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index 7d6fd7939ae..f11f24ba723 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -401,7 +401,7 @@
arena_escape_enrage()
/mob/living/simple_animal/hostile/megafauna/dragon/ex_act(severity, target)
- if(severity == EXPLODE_LIGHT)
+ if(severity <= EXPLODE_LIGHT)
return FALSE
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
index 3a7ba71219a..d486c00356f 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
@@ -199,7 +199,7 @@
if(mother != null)
mother.children_list -= src
visible_message("[src] explodes!")
- explosion(get_turf(loc),0,0,0,flame_range = 3, adminlog = FALSE)
+ explosion(src, flame_range = 3, adminlog = FALSE)
gib()
//Tentacles have less stun time compared to regular variant, to balance being able to use them much more often. Also, 10 more damage.
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index e5177a75784..304503731d5 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -104,11 +104,11 @@
var/turf/T = get_turf(src.loc)
if (charge==0)
return
- var/devastation_range = -1 //round(charge/11000)
- var/heavy_impact_range = round(sqrt(charge)/60)
- var/light_impact_range = round(sqrt(charge)/30)
- var/flash_range = light_impact_range
- if (light_impact_range==0)
+ var/range_devastation = -1 //round(charge/11000)
+ var/range_heavy = round(sqrt(charge)/60)
+ var/range_light = round(sqrt(charge)/30)
+ var/range_flash = range_light
+ if (range_light==0)
rigged = FALSE
corrupt()
return
@@ -117,7 +117,7 @@
log_game("[key_name(usr)] has triggered a rigged/corrupted power cell explosion at [AREACOORD(T)].")
//explosion(T, 0, 1, 2, 2)
- explosion(T, devastation_range, heavy_impact_range, light_impact_range, flash_range)
+ explosion(src, devastation_range = range_devastation, heavy_impact_range = range_heavy, light_impact_range = range_light, flash_range = range_flash)
qdel(src)
/obj/item/stock_parts/cell/proc/corrupt()
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index 7d218a0f5f2..63aa6a4bf7e 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -38,7 +38,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
return FALSE
/obj/machinery/gravity_generator/ex_act(severity, target)
- if(severity == EXPLODE_DEVASTATE) // Very sturdy.
+ if(severity >= EXPLODE_DEVASTATE) // Very sturdy.
set_broken()
/obj/machinery/gravity_generator/blob_act(obj/structure/blob/B)
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 7261d447005..9f0dda0a5c6 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -842,7 +842,7 @@
zap_flags &= ~(ZAP_MACHINE_EXPLOSIVE | ZAP_OBJ_DAMAGE)
. = ..()
if(explosive)
- explosion(src,0,0,0,flame_range = 5, adminlog = FALSE)
+ explosion(src, flame_range = 5, adminlog = FALSE)
qdel(src)
// called when area power state changes
@@ -864,10 +864,9 @@
/obj/machinery/light/proc/explode()
set waitfor = 0
- var/turf/T = get_turf(src.loc)
break_light_tube() // break it first to give a warning
sleep(2)
- explosion(T, 0, 0, 2, 2)
+ explosion(src, light_impact_range = 2, flash_range = -1)
sleep(1)
qdel(src)
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 214c0ff7a47..61206609605 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -171,7 +171,7 @@
STOP_PROCESSING(SSmachines, src)
/obj/machinery/power/port_gen/pacman/proc/overheat()
- explosion(src.loc, 2, 5, 2, -1)
+ explosion(src, devastation_range = 2, heavy_impact_range = 5, light_impact_range = 2, flash_range = -1)
/obj/machinery/power/port_gen/pacman/set_anchored(anchorvalue)
. = ..()
@@ -285,4 +285,4 @@
time_per_sheet = 85
/obj/machinery/power/port_gen/pacman/super/overheat()
- explosion(src.loc, 3, 3, 3, -1)
+ explosion(src, devastation_range = 3, heavy_impact_range = 3, light_impact_range = 3, flash_range = -1)
diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm
index 9eff3ce3f8e..3cccca8d0f3 100644
--- a/code/modules/power/rtg.dm
+++ b/code/modules/power/rtg.dm
@@ -76,7 +76,7 @@
"You hear a loud electrical crack!")
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
tesla_zap(src, 5, power_gen * 0.05)
- addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, get_turf(src), 2, 3, 4, 8), 100) // Not a normal explosion.
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, src, 2, 3, 4, null, 8), 10 SECONDS) // Not a normal explosion.
/obj/machinery/power/rtg/abductor/bullet_act(obj/projectile/Proj)
. = ..()
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 8cee829297f..0ccfd492ed2 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -418,7 +418,7 @@
/obj/singularity/singularity_act()
var/gain = (energy/2)
var/dist = max((current_size - 2),1)
- explosion(src.loc,(dist),(dist*2),(dist*4))
+ explosion(src, devastation_range = (dist), heavy_impact_range = (dist*2), light_impact_range = (dist*4))
qdel(src)
return gain
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 7c5ea6f5e08..c64c673462a 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -395,7 +395,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
crystals.runEvent()
return //No boom for me sir
//Dear mappers, balance the sm max explosion radius to 17.5, 37, 39, 41
- explosion(get_turf(T), explosion_power * max(gasmix_power_ratio, 0.205) * 0.5 , explosion_power * max(gasmix_power_ratio, 0.205) + 2, explosion_power * max(gasmix_power_ratio, 0.205) + 4 , explosion_power * max(gasmix_power_ratio, 0.205) + 6, 1, 1)
+ explosion(src, devastation_range = explosion_power * max(gasmix_power_ratio, 0.205) * 0.5 , heavy_impact_range = explosion_power * max(gasmix_power_ratio, 0.205) + 2, light_impact_range = explosion_power * max(gasmix_power_ratio, 0.205) + 4 , flash_range = explosion_power * max(gasmix_power_ratio, 0.205) + 6, adminlog = TRUE, ignorecap = TRUE)
qdel(src)
@@ -1230,7 +1230,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/turf/turf_loc = get_turf(src)
if(!turf_loc)
return
- explosion(turf_loc,0,round(portal_numbers/5),round(portal_numbers),1,1,1)
+ explosion(turf_loc, heavy_impact_range = round(portal_numbers/5), light_impact_range = round(portal_numbers), flash_range = 1, adminlog = TRUE, ignorecap = TRUE)
. = new/obj/machinery/destabilized_crystal(turf_loc)
qdel(src)
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index 26d57e37034..124e4ef3d9d 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -241,7 +241,7 @@
/obj/item/gun/magic/wand/fireball/zap_self(mob/living/user)
..()
- explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2)
+ explosion(user, devastation_range = -1, light_impact_range = 2, flame_range = 2, flash_range = 3, adminlog = FALSE)
charges--
/////////////////////////////////////
diff --git a/code/modules/projectiles/guns/misc/blastcannon.dm b/code/modules/projectiles/guns/misc/blastcannon.dm
index 52a4cb622b7..85460bb6e62 100644
--- a/code/modules/projectiles/guns/misc/blastcannon.dm
+++ b/code/modules/projectiles/guns/misc/blastcannon.dm
@@ -15,16 +15,18 @@
item_flags = NONE
clumsy_check = FALSE
randomspread = FALSE
+
+ // Firing data.
+ /// The person who opened the valve on the TTV loaded into this.
+ var/datum/weakref/cached_firer
+ /// The target from the last click.
+ var/datum/weakref/cached_target
+ /// The modifiers from the last click.
+ var/cached_modifiers
+
+ // Explosion data:
/// The TTV this contains that will be used to create the projectile
var/obj/item/transfer_valve/bomb
- /// Additional volume added to the gasmixture used to calculate the bombs power.
- var/reaction_volume_mod = 0
- /// Whether the gases are reacted once before calculating the range
- var/prereaction = TRUE
- /// How many times gases react() before calculation. Very finnicky value, do not mess with without good reason.
- var/reaction_cycles = 3
- /// The maximum power the blastcannon is capable of reaching
- var/max_power = INFINITY
// For debugging/badminry
/// Whether you can fire this without a bomb.
@@ -33,25 +35,35 @@
var/debug_power = 0
-/obj/item/gun/blastcannon/debug
- debug_power = 80
- bombcheck = FALSE
+/obj/item/gun/blastcannon/Initialize()
+ . = ..()
+ if(!pin)
+ pin = new
+ RegisterSignal(src, COMSIG_ATOM_INTERNAL_EXPLOSION, .proc/channel_blastwave)
+
+/obj/item/gun/blastcannon/Destroy()
+ if(bomb)
+ QDEL_NULL(bomb)
+ UnregisterSignal(src, COMSIG_ATOM_INTERNAL_EXPLOSION)
+ cached_firer = null
+ cached_target = null
+ return ..()
+
+/obj/item/gun/blastcannon/handle_atom_del(atom/A)
+ if(A == bomb)
+ bomb = null
+ update_appearance()
+ return ..()
+
+/obj/item/gun/blastcannon/assume_air(datum/gas_mixture/giver)
+ qdel(giver)
+ return null // Required to make the TTV not vent gas directly into the firer.
/obj/item/gun/blastcannon/examine(mob/user)
. = ..()
if(bomb)
. += "A bomb is loaded inside."
-/obj/item/gun/blastcannon/Initialize()
- . = ..()
- if(!pin)
- pin = new
-
-/obj/item/gun/blastcannon/Destroy()
- if(bomb)
- QDEL_NULL(bomb)
- return ..()
-
/obj/item/gun/blastcannon/attack_self(mob/user)
if(bomb)
bomb.forceMove(user.loc)
@@ -69,6 +81,9 @@
if(!istype(bomb_to_attach))
return ..()
+ if(bomb)
+ to_chat(user, "[bomb] is already attached to [src]!")
+ return
if(!bomb_to_attach.ready())
to_chat(user, "What good would an incomplete bomb do?")
return FALSE
@@ -81,52 +96,177 @@
update_appearance()
return TRUE
-/// Handles the bomb power calculations
-/obj/item/gun/blastcannon/proc/calculate_bomb()
- if(!istype(bomb) || !bomb.ready())
- return 0
-
- var/datum/gas_mixture/temp = new(max(reaction_volume_mod, 0))
- bomb.merge_gases(temp)
-
- if(prereaction)
- temp.react(src)
- var/prereaction_pressure = temp.return_pressure()
- if(prereaction_pressure < TANK_FRAGMENT_PRESSURE)
- return 0
- for(var/i in 1 to reaction_cycles)
- temp.react(src)
-
- var/pressure = temp.return_pressure()
- if(pressure < TANK_FRAGMENT_PRESSURE)
- return 0
- return ((pressure - TANK_FRAGMENT_PRESSURE) / TANK_FRAGMENT_SCALE)
-
-
/obj/item/gun/blastcannon/afterattack(atom/target, mob/user, flag, params)
- if((!bomb && bombcheck) || (!target) || (get_dist(get_turf(target), get_turf(user)) <= 2))
+ if((!bomb && bombcheck) || !target || (get_dist(get_turf(target), get_turf(user)) <= 2))
return ..()
- var/power = bomb ? calculate_bomb() : debug_power
- power = min(power, max_power)
- QDEL_NULL(bomb)
- update_appearance()
+ cached_target = WEAKREF(target)
+ cached_modifiers = params
+ if(bomb?.valve_open)
+ user.visible_message(
+ "[user] points [src] at [target]!",
+ "You point [src] at [target]!"
+ )
+ return
+
+ cached_firer = WEAKREF(user)
+ if(!bomb)
+ fire_debug(target, user, flag, params)
+ return
+
+ playsound(src, dry_fire_sound, 30, TRUE) // *click
+ user.visible_message(
+ "[user] opens [bomb] on [user.p_their()] [src] and points [p_them()] at [target]!",
+ "You open [bomb] on your [src] and point [p_them()] at [target]!"
+ )
+ var/turf/current_turf = get_turf(src)
+ var/turf/target_turf = get_turf(target)
+ message_admins("Blastcannon transfer valve opened by [ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(current_turf)] while aiming at [ADMIN_VERBOSEJMP(target_turf)] (target).")
+ log_game("Blastcannon transfer valve opened by [key_name(user)] at [AREACOORD(current_turf)] while aiming at [AREACOORD(target_turf)] (target).")
+ bomb.toggle_valve()
+ return
+
+
+/**
+ * Channels an internal explosion into a blastwave projectile.
+ *
+ * Arguments:
+ * - [blastwave_data][/list]: A list containing all of the data for the blastwave.
+ */
+/obj/item/gun/blastcannon/proc/channel_blastwave(atom/source, list/arguments)
+ . = COMSIG_CANCEL_EXPLOSION
+
+ var/heavy = arguments[EXARG_KEY_DEV_RANGE]
+ var/medium = arguments[EXARG_KEY_HEAVY_RANGE]
+ var/light = arguments[EXARG_KEY_LIGHT_RANGE]
+ var/range = max(heavy, medium, light, 0)
+ if(!range)
+ visible_message("[src] lets out a little \"phut\".")
+ return
+
+ if(!ismob(loc))
+ fire_dropped(heavy, medium, light)
+ return
+
+ var/mob/holding = loc
+ var/target = cached_target?.resolve()
+ if(target && (holding.get_active_held_item() == src) && cached_firer && (holding == cached_firer.resolve()))
+ fire_intentionally(target, holding, heavy, medium, light, cached_modifiers)
+ else
+ fire_accidentally(holding, heavy, medium, light)
+ return
+
+/**
+ * Prepares and fires a blastwave.
+ *
+ * Arguments:
+ * - [target][/atom]: The thing that the blastwave is being fired at.
+ * - heavy: The devastation range of the blastwave.
+ * - medium: The heavy impact range of the blastwave.
+ * - light: The light impact range of the blastwave.
+ * - modifiers: Modifiers as a string used while firing this.
+ * - spread: How inaccurate the blastwave is.
+ */
+/obj/item/gun/blastcannon/proc/fire_blastwave(atom/target, heavy, medium, light, modifiers, spread = 0)
+ var/turf/start_turf = get_turf(src)
+
+ var/cap_multiplier = SSmapping.level_trait(start_turf.z, ZTRAIT_BOMBCAP_MULTIPLIER)
+ if(isnull(cap_multiplier))
+ cap_multiplier = 1
+ var/capped_heavy = min(GLOB.MAX_EX_DEVESTATION_RANGE * cap_multiplier, heavy)
+ var/capped_medium = min(GLOB.MAX_EX_HEAVY_RANGE * cap_multiplier, medium)
+ SSexplosions.shake_the_room(start_turf, max(heavy, medium, light, 0), (capped_heavy * 15) + (capped_medium * 20), capped_heavy, capped_medium)
+
+ var/obj/projectile/blastwave/blastwave = new(loc, heavy, medium, light)
+ blastwave.preparePixelProjectile(target, start_turf, params2list(modifiers), spread)
+ blastwave.fire()
+ cached_firer = null
+ cached_target = null
+ cached_modifiers = null
+ return
+
+
+/**
+ * Handles firing the blastcannon intentionally at a specific target.
+ *
+ * Arguments:
+ * - [firer][/mob]: The mob who is firing this weapon.
+ * - [target][/atom]: The target we are firing the
+ * - heavy: The devastation range of the blastwave.
+ * - medium: The heavy impact range of the blastwave.
+ * - light: The light impact range of the blastwave.
+ * - modifiers: The modifier string to use when preparing the blastwave.
+ */
+/obj/item/gun/blastcannon/proc/fire_intentionally(atom/target, mob/firer, heavy, medium, light, modifiers)
+ firer.visible_message(
+ "[firer] fires a blast wave at [target]!",
+ "You fire a blast wave at [target]!"
+ )
+ var/turf/start_turf = get_turf(src)
+ var/turf/target_turf = get_turf(target)
+ message_admins("Blast wave fired from [ADMIN_VERBOSEJMP(start_turf)] at [ADMIN_VERBOSEJMP(target_turf)] ([target]) by [ADMIN_LOOKUPFLW(firer)] with power [heavy]/[medium]/[light].")
+ log_game("Blast wave fired from [AREACOORD(start_turf)] at [AREACOORD(target_turf)] ([target]) by [key_name(firer)] with power [heavy]/[medium]/[light].")
+ fire_blastwave(target, heavy, medium, light, modifiers)
+ return
+
+/**
+ * Handles firing the blastcannon if it was handed to someone else between opening the valve and the bomb exploding.
+ *
+ * Arguments:
+ * - [holder][/mob]: The person who happened to be holding the cannon when it went off.
+ * - heavy: The devastation range of the blastwave.
+ * - medium: The heavy impact range of the blastwave.
+ * - light: The light impact range of the blastwave.
+ */
+/obj/item/gun/blastcannon/proc/fire_accidentally(mob/holder, heavy, medium, light)
+ var/turf/target
+ var/holding
+ if(holder.is_holding(src))
+ target = get_edge_target_turf(holder, holder.dir)
+ holding = TRUE
+ else
+ target = get_edge_target_turf(holder, dir)
+ holding = FALSE
+
+ var/mob/firer = cached_firer?.resolve()
+ var/turf/start_turf = get_turf(src)
+ holder.visible_message(
+ "[src] suddenly goes off[holding ? " in [holder]'s hands" : null]!",
+ "[src] suddenly goes off[holding ? " in your hands" : null]!"
+ )
+ message_admins("Blast wave primed by [ADMIN_LOOKUPFLW(firer)] fired from [ADMIN_VERBOSEJMP(start_turf)] roughly towards [ADMIN_VERBOSEJMP(target)] while being held by [ADMIN_LOOKUPFLW(holder)] with power [heavy]/[medium]/[light].")
+ log_game("Blast wave primed by [key_name(firer)] fired from [AREACOORD(start_turf)] roughly towards [AREACOORD(target)] while being held by [key_name(holder)] with power [heavy]/[medium]/[light].")
+ return fire_blastwave(target, heavy, medium, light, null, (90 * (rand() - 0.5))) // +- anywhere between 0 and 45 degrees
+
+/**
+ * Handles firing the blastcannon if it was dropped on the ground or shoved into a backpack.
+ *
+ * Arguments:
+ * - heavy: The devastation range of the blastwave.
+ * - medium: The heavy impact range of the blastwave.
+ * - light: The light impact range of the blastwave.
+ */
+/obj/item/gun/blastcannon/proc/fire_dropped(heavy, medium, light)
+ src.visible_message("[src] suddenly goes off!")
+ var/turf/target = get_edge_target_turf(src, dir)
+ var/mob/firer = cached_firer.resolve()
+ var/turf/start_turf = get_turf(src)
+ message_admins("Blast wave primed by [ADMIN_LOOKUPFLW(firer)] fired from [ADMIN_VERBOSEJMP(start_turf)] roughly towards [ADMIN_VERBOSEJMP(target)] at [ADMIN_VERBOSEJMP(loc)] ([loc]) with power [heavy]/[medium]/[light].")
+ log_game("Blast wave primed by [key_name(firer)] fired from [AREACOORD(start_turf)] roughly towards [AREACOORD(target)] at [AREACOORD(loc)] ([loc]) with power [heavy]/[medium]/[light].")
+ return fire_blastwave(target, heavy, medium, light, null, 360 * rand())
+
+/**
+ * Handles firing the blastcannon with debug power.
+ *
+ * Arguments:
+ * - [target][/atom]: The thing the blastcannon is being fired at.
+ * - [user][/mob]: The person firing the blastcannon.
+ * - modifiers: A string containing click data.
+ */
+/obj/item/gun/blastcannon/proc/fire_debug(atom/target, mob/user, modifiers)
+ fire_intentionally(target, user, debug_power * 0.25, debug_power * 0.5, debug_power, modifiers)
+ return
- var/heavy = power * 0.25
- var/medium = power * 0.5
- var/light = power
- user.visible_message("[user] opens [bomb] on [user.p_their()] [name] and fires a blast wave at [target]!","You open [bomb] on your [name] and fire a blast wave at [target]!")
- playsound(user, "explosion", 100, TRUE)
- var/turf/starting = get_turf(user)
- var/turf/targturf = get_turf(target)
- message_admins("Blast wave fired from [ADMIN_VERBOSEJMP(starting)] at [ADMIN_VERBOSEJMP(targturf)] ([target.name]) by [ADMIN_LOOKUPFLW(user)] with power [heavy]/[medium]/[light].")
- log_game("Blast wave fired from [AREACOORD(starting)] at [AREACOORD(targturf)] ([target.name]) by [key_name(user)] with power [heavy]/[medium]/[light].")
- var/obj/projectile/blastwave/BW = new(loc, heavy, medium, light)
- var/modifiers = params2list(params)
- BW.preparePixelProjectile(target, get_turf(src), modifiers, 0)
- BW.fire()
- name = initial(name)
- desc = initial(desc)
/// The projectile used by the blastcannon
/obj/projectile/blastwave
@@ -137,17 +277,17 @@
movement_type = FLYING
projectile_phasing = ALL // just blows up the turfs lmao
/// The maximum distance this will inflict [EXPLODE_DEVASTATE]
- var/heavyr = 0
+ var/heavy_ex_range = 0
/// The maximum distance this will inflict [EXPLODE_HEAVY]
- var/mediumr = 0
+ var/medium_ex_range = 0
/// The maximum distance this will inflict [EXPLODE_LIGHT]
- var/lightr = 0
+ var/light_ex_range = 0
-/obj/projectile/blastwave/Initialize(mapload, _heavy, _medium, _light)
- range = max(_heavy, _medium, _light, 0)
- heavyr = _heavy
- mediumr = _medium
- lightr = _light
+/obj/projectile/blastwave/Initialize(mapload, heavy_ex_range, medium_ex_range, light_ex_range)
+ range = max(heavy_ex_range, medium_ex_range, light_range, 0)
+ src.heavy_ex_range = heavy_ex_range
+ src.medium_ex_range = medium_ex_range
+ src.light_ex_range = light_ex_range
return ..()
/obj/projectile/blastwave/Range()
@@ -155,15 +295,15 @@
if(QDELETED(src))
return
- heavyr = max(heavyr - 1, 0)
- mediumr = max(mediumr - 1, 0)
- lightr = max(lightr - 1, 0)
+ heavy_ex_range = max(heavy_ex_range - 1, 0)
+ medium_ex_range = max(medium_ex_range - 1, 0)
+ light_ex_range = max(light_ex_range - 1, 0)
- if(heavyr)
+ if(heavy_ex_range)
SSexplosions.highturf += loc
- else if(mediumr)
+ else if(medium_ex_range)
SSexplosions.medturf += loc
- else if(lightr)
+ else if(light_range)
SSexplosions.lowturf += loc
else
qdel(src)
diff --git a/code/modules/projectiles/guns/misc/medbeam.dm b/code/modules/projectiles/guns/misc/medbeam.dm
index 390a5ec6aea..23a53c195fd 100644
--- a/code/modules/projectiles/guns/misc/medbeam.dm
+++ b/code/modules/projectiles/guns/misc/medbeam.dm
@@ -112,7 +112,7 @@
return FALSE
for(var/obj/effect/ebeam/medical/B in turf)// Don't cross the str-beams!
if(B.owner.origin != current_beam.origin)
- explosion(B.loc,0,3,5,8)
+ explosion(B.loc, heavy_impact_range = 3, light_impact_range = 5, flash_range = 8)
qdel(dummy)
return FALSE
qdel(dummy)
diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm
index 9bccd89d488..c28247e98ac 100644
--- a/code/modules/projectiles/pins.dm
+++ b/code/modules/projectiles/pins.dm
@@ -69,7 +69,7 @@
if(user)
user.show_message("SELF-DESTRUCTING...
", MSG_VISUAL)
to_chat(user, "[gun] explodes!")
- explosion(get_turf(gun), -1, 0, 2, 3)
+ explosion(src, devastation_range = -1, light_impact_range = 2, flash_range = 3)
if(gun)
qdel(gun)
diff --git a/code/modules/projectiles/projectile/bullets/cannon.dm b/code/modules/projectiles/projectile/bullets/cannon.dm
index cdaf7e32875..c01c1fc867a 100644
--- a/code/modules/projectiles/projectile/bullets/cannon.dm
+++ b/code/modules/projectiles/projectile/bullets/cannon.dm
@@ -34,7 +34,7 @@
damage = 40 //set to 30 before first mob impact, but they're gonna be gibbed by the explosion
/obj/projectile/bullet/cannonball/explosive/on_hit(atom/target, blocked = FALSE)
- explosion(target, 2, 3, 4)
+ explosion(target, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4)
. = ..()
/obj/projectile/bullet/cannonball/emp
@@ -54,5 +54,5 @@
/obj/projectile/bullet/cannonball/biggest_one/on_hit(atom/target, blocked = FALSE)
if(projectile_piercing == NONE)
- explosion(target, GLOB.MAX_EX_DEVESTATION_RANGE, GLOB.MAX_EX_HEAVY_RANGE, GLOB.MAX_EX_LIGHT_RANGE, GLOB.MAX_EX_FLASH_RANGE)
+ explosion(target, devastation_range = GLOB.MAX_EX_DEVESTATION_RANGE, heavy_impact_range = GLOB.MAX_EX_HEAVY_RANGE, light_impact_range = GLOB.MAX_EX_LIGHT_RANGE, flash_range = GLOB.MAX_EX_FLASH_RANGE)
. = ..()
diff --git a/code/modules/projectiles/projectile/bullets/grenade.dm b/code/modules/projectiles/projectile/bullets/grenade.dm
index 89f350af432..bb9071a6ca3 100644
--- a/code/modules/projectiles/projectile/bullets/grenade.dm
+++ b/code/modules/projectiles/projectile/bullets/grenade.dm
@@ -10,5 +10,5 @@
/obj/projectile/bullet/a40mm/on_hit(atom/target, blocked = FALSE)
..()
- explosion(target, -1, 0, 2, 1, 0, flame_range = 3)
+ explosion(target, devastation_range = -1, light_impact_range = 2, flame_range = 3, flash_range = 1, adminlog = FALSE)
return BULLET_ACT_HIT
diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm
index 343a9bfedca..7486423b15c 100644
--- a/code/modules/projectiles/projectile/bullets/shotgun.dm
+++ b/code/modules/projectiles/projectile/bullets/shotgun.dm
@@ -68,7 +68,7 @@
/obj/projectile/bullet/shotgun_frag12/on_hit(atom/target, blocked = FALSE)
..()
- explosion(target, -1, 0, 1)
+ explosion(target, devastation_range = -1, light_impact_range = 1)
return BULLET_ACT_HIT
/obj/projectile/bullet/pellet
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 4b65d9d8e8b..cb9065c8aa7 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -676,7 +676,7 @@
return BULLET_ACT_BLOCK
M.take_overall_damage(0,10) //between this 10 burn, the 10 brute, the explosion brute, and the onfire burn, your at about 65 damage if you stop drop and roll immediately
var/turf/T = get_turf(target)
- explosion(T, -1, exp_heavy, exp_light, exp_flash, 0, flame_range = exp_fire)
+ explosion(T, devastation_range = -1, heavy_impact_range = exp_heavy, light_impact_range = exp_light, flame_range = exp_fire, flash_range = exp_flash, adminlog = FALSE)
//still magic related, but a different path
diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm
index f50a08f6b51..23e60f8f7ed 100644
--- a/code/modules/projectiles/projectile/special/rocket.dm
+++ b/code/modules/projectiles/projectile/special/rocket.dm
@@ -7,7 +7,7 @@
/obj/projectile/bullet/gyro/on_hit(atom/target, blocked = FALSE)
..()
- explosion(target, -1, 0, 2)
+ explosion(target, devastation_range = -1, light_impact_range = 2)
return BULLET_ACT_HIT
/// PM9 HEDP rocket
@@ -24,7 +24,7 @@
/obj/projectile/bullet/a84mm/on_hit(atom/target, blocked = FALSE)
..()
- explosion(target, -1, 1, 3, 1, 0, flame_range = 4)
+ explosion(target, devastation_range = -1, heavy_impact_range = 1, light_impact_range = 3, flame_range = 4, flash_range = 1, adminlog = FALSE)
if(ismecha(target))
var/obj/vehicle/sealed/mecha/M = target
@@ -47,9 +47,9 @@
/obj/projectile/bullet/a84mm_he/on_hit(atom/target, blocked=0)
..()
if(!isliving(target)) //if the target isn't alive, so is a wall or something
- explosion(target, 0, 1, 2, 4, flame_range = 3)
+ explosion(target, heavy_impact_range = 1, light_impact_range = 2, flame_range = 3, flash_range = 4)
else
- explosion(target, 0, 0, 2, 4, flame_range = 3)
+ explosion(target, light_impact_range = 2, flame_range = 3, flash_range = 4)
return BULLET_ACT_HIT
/// PM9 weak rocket
@@ -65,9 +65,9 @@
/obj/projectile/bullet/a84mm_weak/on_hit(atom/target, blocked=0)
..()
if(!isliving(target)) //if the target isn't alive, so is a wall or something
- explosion(target, 0, 1, 2, 4, flame_range = 3)
+ explosion(target, heavy_impact_range = 1, light_impact_range = 2, flame_range = 3, flash_range = 4)
else
- explosion(target, 0, 0, 2, 4, flame_range = 3)
+ explosion(target, light_impact_range = 2, flame_range = 3, flash_range = 4)
return BULLET_ACT_HIT
/// Mech BRM-6 missile
@@ -99,7 +99,7 @@
..()
for(var/i in sturdy)
if(istype(target, i))
- explosion(target, 0, 1, 1, 2)
+ explosion(target, heavy_impact_range = 1, light_impact_range = 1, flash_range = 2)
return BULLET_ACT_HIT
//if(istype(target, /turf/closed) || ismecha(target))
new /obj/item/broken_missile(get_turf(src), 1)
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index 7315874b53c..2c2afa7756f 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -205,7 +205,7 @@
obj_flags |= EMAGGED
/obj/machinery/chem_dispenser/ex_act(severity, target)
- if(severity >= EXPLODE_LIGHT) // Note that the explosion defines are inverted. Stronger explosions have smaller numbers.
+ if(severity <= EXPLODE_LIGHT)
return FALSE
return ..()
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index b3bf6e8672c..5a0e044db2d 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -65,7 +65,7 @@
reagents.maximum_volume += B.reagents.maximum_volume
/obj/machinery/chem_master/ex_act(severity, target)
- if(severity >= EXPLODE_LIGHT) // This actually makes the dispenser immune to explosions at least as weak as [EXPLODE_LIGHT]. Don't ask me why the defines are inverted. I don't know.
+ if(severity <= EXPLODE_LIGHT)
return FALSE
return ..()
diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
index 32a05cdfef8..84a891b1bda 100644
--- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
@@ -544,7 +544,7 @@ Basically, we fill the time between now and 2s from now with hands based off the
remove_buffs(owner)
var/obj/item/organ/heart/heart = owner.getorganslot(ORGAN_SLOT_HEART)
if(owner.health < -500 || heart.organ_flags & ORGAN_FAILING)//Honestly commendable if you get -500
- explosion(owner, 0, 0, 1)
+ explosion(owner, light_impact_range = 1)
qdel(heart)
owner.visible_message("[owner]'s heart explodes!")
return ..()
@@ -557,7 +557,7 @@ Basically, we fill the time between now and 2s from now with hands based off the
REMOVE_TRAIT(owner, TRAIT_NODEATH, type)
owner.stat = DEAD
return ..()
- explosion(owner, 0, 0, 1)
+ explosion(owner, light_impact_range = 1)
qdel(heart)
owner.visible_message("[owner]'s heart explodes!")
return..()
diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm
index 7d8d5142cc8..f8451b9b990 100644
--- a/code/modules/reagents/chemistry/recipes.dm
+++ b/code/modules/reagents/chemistry/recipes.dm
@@ -440,7 +440,7 @@
//Calls the default explosion subsystem handiler to explode with fire (random firespots and noise)
/datum/chemical_reaction/proc/explode_fire(datum/reagents/holder, datum/equilibrium/equilibrium, range = 3)
- explosion(holder.my_atom, 0, 0, 0, 0, flame_range = range)
+ explosion(holder.my_atom, flame_range = range)
holder.my_atom.audible_message("The [holder.my_atom] suddenly errupts in flames!")
//Creates a ring of fire in a set range around the beaker location
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index 8380168e162..84d0c2d2cc1 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -392,7 +392,7 @@
/datum/chemical_reaction/slime/slimeexplosion/proc/boom(datum/reagents/holder)
if(holder?.my_atom)
- explosion(get_turf(holder.my_atom), 1 ,3, 6)
+ explosion(holder.my_atom, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 6)
/datum/chemical_reaction/slime/slimecornoil
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 60d38a875c3..207e091887b 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -143,10 +143,10 @@
return ..()
-/obj/item/reagent_containers/ex_act()
+/obj/item/reagent_containers/ex_act(severity)
if(reagents)
for(var/datum/reagent/R in reagents.reagent_list)
- R.on_ex_act()
+ R.on_ex_act(severity)
if(!QDELETED(src))
return ..()
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index 25905d7d4c2..837250acbc4 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -87,7 +87,7 @@
reagent_id = /datum/reagent/fuel
/obj/structure/reagent_dispensers/fueltank/boom()
- explosion(get_turf(src), 0, 1, 5, flame_range = 5)
+ explosion(src, heavy_impact_range = 1, light_impact_range = 5, flame_range = 5)
qdel(src)
/obj/structure/reagent_dispensers/fueltank/blob_act(obj/structure/blob/B)
@@ -139,7 +139,7 @@
tank_volume = 5000
/obj/structure/reagent_dispensers/fueltank/large/boom()
- explosion(get_turf(src), 1, 2, 7, flame_range = 12)
+ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 7, flame_range = 12)
qdel(src)
/obj/structure/reagent_dispensers/peppertank
@@ -193,7 +193,7 @@
reagent_id = /datum/reagent/consumable/ethanol/beer
/obj/structure/reagent_dispensers/beerkeg/blob_act(obj/structure/blob/B)
- explosion(src.loc,0,3,5,7,10)
+ explosion(src, heavy_impact_range = 3, light_impact_range = 5, flame_range = 10, flash_range = 7)
if(!QDELETED(src))
qdel(src)
diff --git a/code/modules/research/anomaly/explosive_compressor.dm b/code/modules/research/anomaly/explosive_compressor.dm
index 5b5573f0f41..e41fe01a7b8 100644
--- a/code/modules/research/anomaly/explosive_compressor.dm
+++ b/code/modules/research/anomaly/explosive_compressor.dm
@@ -1,5 +1,8 @@
#define MAX_RADIUS_REQUIRED 20 //maxcap
#define MIN_RADIUS_REQUIRED 4 //1, 2, 4
+/// How long the compression test can last before the machine just gives up and ejects the items.
+#define COMPRESSION_TEST_TIME (SSOBJ_DT SECONDS * 5)
+
/**
* # Explosive compressor machines
*
@@ -18,14 +21,32 @@
var/obj/item/raw_anomaly_core/inserted_core
/// The TTV inserted in the machine.
var/obj/item/transfer_valve/inserted_bomb
+ /// The timer that lets us timeout the test.
+ var/datum/timedevent/timeout_timer
+ /// Whether we are currently testing a bomb and core.
+ var/testing = FALSE
+ /// The message produced by the explosive compressor at the end of the compression test.
+ var/test_status = null
/// The last time we did say_requirements(), because someone will inevitably click spam this.
var/last_requirements_say = 0
+/obj/machinery/research/explosive_compressor/Initialize()
+ . = ..()
+ RegisterSignal(src, COMSIG_ATOM_INTERNAL_EXPLOSION, .proc/check_test)
+
+/obj/machinery/research/explosive_compressor/Destroy()
+ UnregisterSignal(src, COMSIG_ATOM_INTERNAL_EXPLOSION)
+ return ..()
+
/obj/machinery/research/explosive_compressor/examine(mob/user)
. = ..()
. += "Ctrl-Click to remove an inserted core."
. += "Click with an empty hand to gather information about the required radius of an inserted core. Insert a ready TTV to start the implosion process if a core is inserted."
+/obj/machinery/research/explosive_compressor/assume_air(datum/gas_mixture/giver)
+ qdel(giver)
+ return null // Required to make the TTV not vent directly into the air.
+
/obj/machinery/research/explosive_compressor/attack_hand(mob/living/user, list/modifiers)
. = ..()
if(.)
@@ -45,6 +66,9 @@
if(!inserted_core)
to_chat(user, "There is no core inserted.")
return
+ if(testing)
+ to_chat(user, "You can't remove [inserted_core] from [src] while [p_theyre()] in testing mode.")
+ return
inserted_core.forceMove(get_turf(user))
to_chat(user, "You remove [inserted_core] from [src].")
user.put_in_hands(inserted_core)
@@ -53,12 +77,12 @@
/**
* Says (no, literally) the data of required explosive power for a certain anomaly type.
*/
-/obj/machinery/research/explosive_compressor/proc/say_requirements(obj/item/raw_anomaly_core/C)
- var/required = get_required_radius(C.anomaly_type)
+/obj/machinery/research/explosive_compressor/proc/say_requirements(obj/item/raw_anomaly_core/core)
+ var/required = get_required_radius(core.anomaly_type)
if(isnull(required))
- say("Unfortunately, due to diminishing supplies of condensed anomalous matter, [C] and any cores of its type are no longer of a sufficient quality level to be compressed into a working core.")
+ say("Unfortunately, due to diminishing supplies of condensed anomalous matter, [core] and any cores of its type are no longer of a sufficient quality level to be compressed into a working core.")
else
- say("[C] requires a minimum of a theoretical radius of [required] to successfully implode into a charged anomaly core.")
+ say("[core] requires a minimum of a theoretical radius of [required] to successfully implode into a charged anomaly core.")
/**
* Determines how much explosive power (last value, so light impact theoretical radius) is required to make a certain anomaly type.
@@ -80,65 +104,117 @@
var/radius = clamp(round(MIN_RADIUS_REQUIRED + radius_increase_per_core * already_made, 1), MIN_RADIUS_REQUIRED, MAX_RADIUS_REQUIRED)
return radius
-/obj/machinery/research/explosive_compressor/attackby(obj/item/I, mob/living/user, params)
+/obj/machinery/research/explosive_compressor/attackby(obj/item/tool, mob/living/user, params)
. = ..()
- if(istype(I, /obj/item/raw_anomaly_core))
+ if(istype(tool, /obj/item/raw_anomaly_core))
if(inserted_core)
to_chat(user, "There is already a core in [src].")
return
- if(!user.transferItemToLoc(I, src))
- to_chat(user, "[I] is stuck to your hand.")
+ if(testing)
+ to_chat(user, "You can't insert [tool] into [src] while [p_theyre()] in testing mode.")
return
- inserted_core = I
- to_chat(user, "You insert [I] into [src].")
+ if(!user.transferItemToLoc(tool, src))
+ to_chat(user, "[tool] is stuck to your hand.")
+ return
+ inserted_core = tool
+ to_chat(user, "You insert [tool] into [src].")
return
- if(istype(I, /obj/item/transfer_valve))
+ if(istype(tool, /obj/item/transfer_valve))
// If they don't have a bomb core inserted, don't let them insert this. If they do, insert and do implosion.
if(!inserted_core)
to_chat(user, "There is no core inserted in [src]. What would be the point of detonating an implosion without a core?")
return
- var/obj/item/transfer_valve/valve = I
+ if(testing)
+ to_chat(user, "You can't insert [tool] into [src] while [p_theyre()] in testing mode.")
+ return
+ var/obj/item/transfer_valve/valve = tool
if(!valve.ready())
to_chat(user, "[valve] is incomplete.")
return
- if(!user.transferItemToLoc(I, src))
- to_chat(user, "[I] is stuck to your hand.")
+ if(!user.transferItemToLoc(tool, src))
+ to_chat(user, "[tool] is stuck to your hand.")
return
- inserted_bomb = I
- to_chat(user, "You insert [I] and press the start button.")
- do_implosion()
+ inserted_bomb = tool
+ to_chat(user, "You insert [tool] and press the start button.")
+ start_test()
+
/**
- * The ""explosion"" proc.
+ * Starts a compression test.
*/
-/obj/machinery/research/explosive_compressor/proc/do_implosion()
- var/required_radius = get_required_radius(inserted_core.anomaly_type)
- // By now, we should be sure that we have a core, a TTV, and that the TTV has both tanks in place.
- var/datum/gas_mixture/mix = new(0)
- inserted_bomb.merge_gases(mix)
- mix.react()
- if(mix.return_pressure() < TANK_FRAGMENT_PRESSURE)
- // They failed so miserably we're going to give them their bomb back.
+/obj/machinery/research/explosive_compressor/proc/start_test()
+ if(!istype(inserted_core) || !istype(inserted_bomb))
+ end_test("ERROR: Missing equpment. Items ejected.")
+ return
+
+ say("Beginning compression test. Opening transfer valve.")
+ testing = TRUE
+ test_status = null
+ inserted_bomb.toggle_valve()
+ timeout_timer = addtimer(CALLBACK(src, .proc/timeout_test), COMPRESSION_TEST_TIME, TIMER_STOPPABLE | TIMER_UNIQUE | TIMER_NO_HASH_WAIT)
+ return
+
+/**
+ * Ends a compression test.
+ *
+ * Arguments:
+ * - message: A message for the compressor to say when the test ends.
+ */
+/obj/machinery/research/explosive_compressor/proc/end_test(message)
+ if(inserted_core)
+ inserted_core.forceMove(drop_location())
+ inserted_core = null
+ if(inserted_bomb)
inserted_bomb.forceMove(drop_location())
inserted_bomb = null
- inserted_core.forceMove(drop_location())
- inserted_core = null
- say("Transfer valve resulted in negligible explosive power. Items ejected.")
- return FALSE
- mix.react() // build more pressure
+ if(timeout_timer)
+ QDEL_NULL(timeout_timer)
+ if(message)
+ say(message)
+ testing = FALSE
+ return
- var/range = (mix.return_pressure() - TANK_FRAGMENT_PRESSURE) / TANK_FRAGMENT_SCALE
- QDEL_NULL(inserted_bomb) // bomb goes poof
- if(range < required_radius)
- say("Resultant detonation failed to produce enough implosive power to compress [inserted_core]. Core ejected.")
- inserted_core.forceMove(drop_location())
- inserted_core = null
- return FALSE
+/**
+ * Checks whether an internal explosion was sufficient to compress the core.
+ */
+/obj/machinery/research/explosive_compressor/proc/check_test(atom/source, list/arguments)
+ . = COMSIG_CANCEL_EXPLOSION
+ if(!inserted_core)
+ test_status = "ERROR: No core present during detonation."
+ return
- inserted_core.create_core(drop_location(), TRUE, TRUE)
- inserted_core = null
- say("Success. Resultant detonation has theoretical range of [range]. Required radius was [required_radius]. Core production complete.")
- return TRUE
+ var/heavy = arguments[EXARG_KEY_DEV_RANGE]
+ var/medium = arguments[EXARG_KEY_HEAVY_RANGE]
+ var/light = arguments[EXARG_KEY_LIGHT_RANGE]
+ var/explosion_range = max(heavy, medium, light, 0)
+ var/required_range = get_required_radius(inserted_core.anomaly_type)
+ var/turf/location = get_turf(src)
+
+ var/cap_multiplier = SSmapping.level_trait(location.z, ZTRAIT_BOMBCAP_MULTIPLIER)
+ if(isnull(cap_multiplier))
+ cap_multiplier = 1
+ var/capped_heavy = min(GLOB.MAX_EX_DEVESTATION_RANGE * cap_multiplier, heavy)
+ var/capped_medium = min(GLOB.MAX_EX_HEAVY_RANGE * cap_multiplier, medium)
+ SSexplosions.shake_the_room(location, explosion_range, (capped_heavy * 15) + (capped_medium * 20), capped_heavy, capped_medium)
+
+ if(explosion_range < required_range)
+ test_status = "Resultant detonation failed to produce enough implosive power to compress [inserted_core]. Core ejected."
+ return
+
+ if(test_status)
+ return
+ inserted_core = inserted_core.create_core(src, TRUE, TRUE)
+ test_status = "Success. Resultant detonation has theoretical range of [explosion_range]. Required radius was [required_range]. Core production complete."
+ return
+
+/**
+ * Handles timing out the test after a while.
+ */
+/obj/machinery/research/explosive_compressor/proc/timeout_test()
+ timeout_timer = null
+ if(!test_status)
+ test_status = "Transfer valve resulted in negligible explosive power. Items ejected."
+ end_test(test_status)
#undef MAX_RADIUS_REQUIRED
#undef MIN_RADIUS_REQUIRED
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 5cfa4a6c112..35f391ced8f 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -360,7 +360,7 @@
FB.fire()
else if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions, melting [exp_on] and releasing a burst of flame!")
- explosion(loc, -1, 0, 0, 0, 0, flame_range = 2)
+ explosion(src, devastation_range = -1, flame_range = 2, adminlog = FALSE)
investigate_log("Experimentor started a fire.", INVESTIGATE_EXPERIMENTOR)
ejectItem(TRUE)
else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
@@ -517,7 +517,7 @@
addtimer(CALLBACK(src, .proc/reset_exp), resetTime)
/obj/machinery/rnd/experimentor/proc/boom()
- explosion(src, 1, 5, 10, 5, 1)
+ explosion(src, devastation_range = 1, heavy_impact_range = 5, light_impact_range = 10, flash_range = 5, adminlog = TRUE)
/obj/machinery/rnd/experimentor/proc/honk()
playsound(src, 'sound/items/bikehorn.ogg', 500)
@@ -654,7 +654,7 @@
/obj/item/relic/proc/do_explode(mob/user)
if(loc == user)
visible_message("\The [src]'s top opens, releasing a powerful blast!")
- explosion(user.loc, 0, rand(1,5), rand(1,5), rand(1,5), rand(1,5), flame_range = 2)
+ explosion(src, heavy_impact_range = rand(1,5), light_impact_range = rand(1,5), flame_range = 2, flash_range = rand(1,5), adminlog = TRUE)
warn_admins(user, "Explosion")
qdel(src) //Comment this line to produce a light grenade (the bomb that keeps on exploding when used)!!
diff --git a/code/modules/research/nanites/nanite_programs/weapon.dm b/code/modules/research/nanites/nanite_programs/weapon.dm
index a8d276919ec..79bf0444938 100644
--- a/code/modules/research/nanites/nanite_programs/weapon.dm
+++ b/code/modules/research/nanites/nanite_programs/weapon.dm
@@ -88,7 +88,7 @@
addtimer(CALLBACK(src, .proc/boom), clamp((nanites.nanite_volume * 0.35), 25, 150))
/datum/nanite_program/explosive/proc/boom()
- dyn_explosion(get_turf(host_mob), nanites.nanite_volume / 50)
+ dyn_explosion(host_mob, nanites.nanite_volume / 50)
qdel(nanites)
//TODO make it defuse if triggered again
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index 1a6b59a02a3..ccc6a26ac27 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -859,7 +859,7 @@
/datum/status_effect/stabilized/oil/tick()
if(owner.stat == DEAD)
- explosion(get_turf(owner),1,2,4,flame_range = 5)
+ explosion(owner, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 5)
return ..()
/datum/status_effect/stabilized/black
diff --git a/code/modules/research/xenobiology/crossbreeding/charged.dm b/code/modules/research/xenobiology/crossbreeding/charged.dm
index 7b41c0a4661..d23fe1d2687 100644
--- a/code/modules/research/xenobiology/crossbreeding/charged.dm
+++ b/code/modules/research/xenobiology/crossbreeding/charged.dm
@@ -224,7 +224,7 @@ Charged extracts:
addtimer(CALLBACK(src, .proc/boom), 50)
/obj/item/slimecross/charged/oil/proc/boom()
- explosion(get_turf(src), 2, 3, 4) //Much smaller effect than normal oils, but devastatingly strong where it does hit.
+ explosion(src, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4) //Much smaller effect than normal oils, but devastatingly strong where it does hit.
qdel(src)
/obj/item/slimecross/charged/black
diff --git a/code/modules/research/xenobiology/crossbreeding/chilling.dm b/code/modules/research/xenobiology/crossbreeding/chilling.dm
index 5987dc21269..f7aaede8c81 100644
--- a/code/modules/research/xenobiology/crossbreeding/chilling.dm
+++ b/code/modules/research/xenobiology/crossbreeding/chilling.dm
@@ -290,7 +290,7 @@ Chilling extracts:
addtimer(CALLBACK(src, .proc/boom), 50)
/obj/item/slimecross/chilling/oil/proc/boom()
- explosion(get_turf(src), -1, -1, 10, 0) //Large radius, but mostly light damage, and no flash.
+ explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 10) //Large radius, but mostly light damage, and no flash.
qdel(src)
/obj/item/slimecross/chilling/black
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index f9f3acb9ba7..d657b1bc7fa 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -457,7 +457,7 @@
user.visible_message("[user]'s skin starts pulsing and glowing ominously...", "You feel unstable...")
if(do_after(user, 60, target = user))
to_chat(user, "You explode!")
- explosion(get_turf(user), 1 ,3, 6)
+ explosion(user, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 6)
user.gib()
return
to_chat(user, "You stop feeding [src], and the feeling passes.")
diff --git a/code/modules/spells/spell_types/explosion.dm b/code/modules/spells/spell_types/explosion.dm
index dadbd190fa6..a0878826f97 100644
--- a/code/modules/spells/spell_types/explosion.dm
+++ b/code/modules/spells/spell_types/explosion.dm
@@ -4,15 +4,19 @@
school = SCHOOL_EVOCATION
+ /// The devastation range of the resulting explosion.
var/ex_severe = 1
+ /// The heavy impact range of the resulting explosion.
var/ex_heavy = 2
+ /// The light impact range of the resulting explosion.
var/ex_light = 3
+ /// The flash range of the resulting explosion.
var/ex_flash = 4
/obj/effect/proc_holder/spell/targeted/explosion/cast(list/targets,mob/user = usr)
for(var/mob/living/target in targets)
if(target.anti_magic_check())
continue
- explosion(target.loc,ex_severe,ex_heavy,ex_light,ex_flash)
+ explosion(target, devastation_range = ex_severe, heavy_impact_range = ex_heavy, light_impact_range = ex_light, flash_range = ex_flash)
return
diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm
index f75cd18c5d3..d46a7cc30dc 100644
--- a/code/modules/station_goals/bsa.dm
+++ b/code/modules/station_goals/bsa.dm
@@ -205,7 +205,7 @@
if(!blocker)
message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)].")
log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)].")
- explosion(bullseye, ex_power, ex_power*2, ex_power*4)
+ explosion(bullseye, devastation_range = ex_power, heavy_impact_range = ex_power*2, light_impact_range = ex_power*4)
else
message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)] but it was blocked by [blocker] at [ADMIN_VERBOSEJMP(target)].")
log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)] but it was blocked by [blocker] at [AREACOORD(target)].")
diff --git a/code/modules/vehicles/atv.dm b/code/modules/vehicles/atv.dm
index 3ae406bdc03..63aec5b1d55 100644
--- a/code/modules/vehicles/atv.dm
+++ b/code/modules/vehicles/atv.dm
@@ -92,7 +92,7 @@
return TRUE
/obj/vehicle/ridden/atv/obj_destruction()
- explosion(src, -1, 0, 2, 4, flame_range = 3)
+ explosion(src, devastation_range = -1, light_impact_range = 2, flame_range = 3, flash_range = 4)
return ..()
/obj/vehicle/ridden/atv/Destroy()
diff --git a/code/modules/vehicles/cars/car.dm b/code/modules/vehicles/cars/car.dm
index 32e3364b27f..7cd57e4b463 100644
--- a/code/modules/vehicles/cars/car.dm
+++ b/code/modules/vehicles/cars/car.dm
@@ -75,7 +75,7 @@
add_occupant(kidnapped, VEHICLE_CONTROL_KIDNAPPED)
/obj/vehicle/sealed/car/obj_destruction(damage_flag)
- explosion(loc, 0, 1, 2, 3, 0)
+ explosion(src, heavy_impact_range = 1, light_impact_range = 2, flash_range = 3, adminlog = FALSE)
log_message("[src] exploded due to destruction", LOG_ATTACK)
return ..()
diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm
index 193aa8164e8..cd6e032b1df 100644
--- a/code/modules/vehicles/mecha/mecha_defense.dm
+++ b/code/modules/vehicles/mecha/mecha_defense.dm
@@ -120,12 +120,12 @@
/obj/vehicle/sealed/mecha/ex_act(severity, target)
log_message("Affected by explosion of severity: [severity].", LOG_MECHA, color="red")
if(prob(deflect_chance))
- severity++
+ severity--
log_message("Armor saved, changing severity to [severity]", LOG_MECHA)
return ..()
/obj/vehicle/sealed/mecha/contents_explosion(severity, target)
- severity++
+ severity--
switch(severity)
if(EXPLODE_DEVASTATE)
diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm
index 223505cb8c1..e4c531adc31 100644
--- a/code/modules/vehicles/mecha/working/ripley.dm
+++ b/code/modules/vehicles/mecha/working/ripley.dm
@@ -180,7 +180,7 @@
/obj/vehicle/sealed/mecha/working/ripley/contents_explosion(severity, target)
for(var/i in cargo)
var/obj/cargoobj = i
- if(prob(30/severity))
+ if(prob(10 * severity))
LAZYREMOVE(cargo, cargoobj)
cargoobj.forceMove(drop_location())
return ..()
diff --git a/code/modules/vehicles/motorized_wheelchair.dm b/code/modules/vehicles/motorized_wheelchair.dm
index 9b7b3c72745..0e55406ae61 100644
--- a/code/modules/vehicles/motorized_wheelchair.dm
+++ b/code/modules/vehicles/motorized_wheelchair.dm
@@ -144,7 +144,7 @@
. = ..()
// Here is the shitty emag functionality.
if(obj_flags & EMAGGED && (istype(A, /turf/closed) || isliving(A)))
- explosion(src, -1, 1, 3, 2, 0)
+ explosion(src, devastation_range = -1, heavy_impact_range = 1, light_impact_range = 3, flash_range = 2, adminlog = FALSE)
visible_message("[src] explodes!!")
return
// If the speed is higher than delay_multiplier throw the person on the wheelchair away
diff --git a/code/modules/vehicles/secway.dm b/code/modules/vehicles/secway.dm
index d73e4cae7e0..140197acb0e 100644
--- a/code/modules/vehicles/secway.dm
+++ b/code/modules/vehicles/secway.dm
@@ -71,7 +71,7 @@
. += "Something appears to be stuck in its exhaust..."
/obj/vehicle/ridden/secway/obj_destruction()
- explosion(src, -1, 0, 2, 4, flame_range = 3)
+ explosion(src, devastation_range = -1, light_impact_range = 2, flame_range = 3, flash_range = 4)
return ..()
/obj/vehicle/ridden/secway/Destroy()
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 966d59978c9..1ec01d6f94b 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -1170,7 +1170,7 @@ GLOBAL_LIST_EMPTY(vending_products)
if(T)
for(var/obj/item/I in contents)
I.forceMove(T)
- explosion(T, -1, 0, 3)
+ explosion(src, devastation_range = -1, light_impact_range = 3)
return ..()
/obj/machinery/vending/custom/unbreakable
diff --git a/tgstation.dme b/tgstation.dme
index d21976789a2..fd901e2fdbb 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -58,6 +58,7 @@
#include "code\__DEFINES\events.dm"
#include "code\__DEFINES\exosuit_fab.dm"
#include "code\__DEFINES\experisci.dm"
+#include "code\__DEFINES\explosions.dm"
#include "code\__DEFINES\exports.dm"
#include "code\__DEFINES\fantasy_affixes.dm"
#include "code\__DEFINES\flags.dm"