From 5b8a38af3a6d7f584ea5e566a06bccbe39c4c957 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 27 Apr 2021 02:53:17 +0200 Subject: [PATCH] [MIRROR] Makes the explosive compressor and blastcannon actually use the TTVs they're given + the explosion changes to support that. (#5244) * Makes the explosive compressor and blastcannon actually use the TTVs they're given + the explosion changes to support that. (#58015) * Adds explosion SFX to the blastcannon and explosive compressor - Extracts the explosion SFX and screenshake proc from the SSexplosions explosion handling proc and lets the explosive compressor and blastcannon use it. * Miscellaneous changes - Adds defines for the internal explosion arglist keys - Reverses the values of the explosion severity defines - Changes almost everything that uses `/proc/explosion` to use named arguments - Removes a whole bunch of argname = 0 in explosion calls. * Removes named callback arguments. * Changes the explosion signals to just use the arguments list Adds a simple framework to let objects respond to explosions occurring inside of them. Changes a whole bunch of explosions to use the object being exploded as the origin of the explosion rather than the turf the object is on. Makes the explosive compressor and blastcannon actually use the TTVs they are given. Adds support for things responding to internal explosions. Less snowflake code for the explosive compressor and blastcannon calculating bomb range.* Less confusing explosion severity defines. Less opaque explosion arguments *does not guarantee that the solution to letting them actually use the TTV is any less snowflake. * Makes the explosive compressor and blastcannon actually use the TTVs they're given + the explosion changes to support that. Co-authored-by: TemporalOroboros --- code/__DEFINES/_helpers.dm | 3 + code/__DEFINES/combat.dm | 7 +- code/__DEFINES/dcs/signals.dm | 9 + code/__DEFINES/explosions.dm | 32 ++ code/controllers/subsystem/explosions.dm | 252 +++++++++++---- code/datums/components/explodable.dm | 17 +- code/datums/components/uplink.dm | 2 +- code/datums/diseases/advance/symptoms/fire.dm | 4 +- code/datums/diseases/rhumba_beat.dm | 2 +- code/datums/martial/plasma_fist.dm | 24 +- code/datums/materials/basemats.dm | 2 +- code/datums/mutations/body.dm | 2 +- code/game/machinery/_machinery.dm | 2 +- code/game/machinery/computer/arcade/arcade.dm | 2 +- code/game/machinery/computer/arcade/orion.dm | 2 +- code/game/machinery/doors/door.dm | 2 +- code/game/machinery/doors/poddoor.dm | 2 +- code/game/machinery/syndicatebomb.dm | 2 +- code/game/objects/effects/anomalies.dm | 4 +- code/game/objects/effects/decals/cleanable.dm | 4 +- .../objects/effects/decals/cleanable/misc.dm | 2 +- .../effects/effect_system/effects_other.dm | 2 +- code/game/objects/effects/mines.dm | 8 +- code/game/objects/items/RCD.dm | 2 +- code/game/objects/items/crab17.dm | 2 +- code/game/objects/items/devices/PDA/PDA.dm | 4 +- .../items/devices/portable_chem_mixer.dm | 2 +- code/game/objects/items/devices/powersink.dm | 2 +- .../objects/items/devices/transfer_valve.dm | 11 + code/game/objects/items/granters.dm | 2 +- code/game/objects/items/grenades/festive.dm | 3 +- .../game/objects/items/grenades/ghettobomb.dm | 2 +- code/game/objects/items/grenades/grenade.dm | 2 +- code/game/objects/items/grenades/plastic.dm | 6 +- code/game/objects/items/hot_potato.dm | 2 +- .../items/implants/implant_explosive.dm | 4 +- code/game/objects/items/plushes.dm | 4 +- code/game/objects/items/tanks/tanks.dm | 10 +- code/game/objects/items/tools/weldingtool.dm | 3 +- code/game/objects/items/toys.dm | 4 +- code/game/objects/items/wayfinding.dm | 2 +- .../crates_lockers/crates/secure.dm | 2 +- .../objects/structures/industrial_lift.dm | 2 +- .../objects/structures/training_machine.dm | 2 +- code/game/turfs/closed/minerals.dm | 4 +- code/game/turfs/open/floor.dm | 2 +- code/game/turfs/open/floor/reinf_floor.dm | 2 +- code/modules/admin/admin_verbs.dm | 28 +- code/modules/admin/smites/bsa.dm | 2 +- code/modules/admin/verbs/randomverbs.dm | 2 +- .../antagonists/blob/structures/core.dm | 2 +- .../antagonists/changeling/powers/headcrab.dm | 2 +- .../traitor/equipment/Malf_Modules.dm | 2 +- code/modules/assembly/bomb.dm | 14 +- .../machinery/components/fusion/hfr_procs.dm | 2 +- .../machinery/portable/canister.dm | 2 +- .../awaymissions/bluespaceartillery.dm | 2 +- .../awaymissions/mission_code/Academy.dm | 2 +- .../awaymissions/mission_code/wildwest.dm | 2 +- code/modules/buildmode/submodes/boom.dm | 2 +- code/modules/events/crystal_event.dm | 12 +- code/modules/events/processor_overload.dm | 2 +- code/modules/events/spacevine.dm | 4 +- .../kitchen_machinery/microwave.dm | 2 +- code/modules/hydroponics/grown/citrus.dm | 10 +- code/modules/meteors/meteors.dm | 18 +- code/modules/mining/machine_vending.dm | 2 +- code/modules/mining/ores_coins.dm | 10 +- .../mob/living/carbon/human/human_defense.dm | 2 +- .../carbon/human/species_types/golems.dm | 2 +- code/modules/mob/living/silicon/ai/death.dm | 2 +- .../mob/living/silicon/pai/pai_defense.dm | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 4 +- .../simple_animal/guardian/types/protector.dm | 2 +- .../hostile/megafauna/bubblegum.dm | 2 +- .../hostile/megafauna/demonic_frost_miner.dm | 2 +- .../simple_animal/hostile/megafauna/drake.dm | 2 +- .../mining_mobs/elites/goliath_broodmother.dm | 2 +- code/modules/power/cell.dm | 12 +- code/modules/power/gravitygenerator.dm | 2 +- code/modules/power/lighting.dm | 5 +- code/modules/power/port_gen.dm | 4 +- code/modules/power/rtg.dm | 2 +- code/modules/power/singularity/singularity.dm | 2 +- code/modules/power/supermatter/supermatter.dm | 4 +- code/modules/projectiles/guns/magic/wand.dm | 2 +- .../projectiles/guns/misc/blastcannon.dm | 294 +++++++++++++----- code/modules/projectiles/guns/misc/medbeam.dm | 2 +- code/modules/projectiles/pins.dm | 2 +- .../projectiles/projectile/bullets/cannon.dm | 4 +- .../projectiles/projectile/bullets/grenade.dm | 2 +- .../projectiles/projectile/bullets/shotgun.dm | 2 +- code/modules/projectiles/projectile/magic.dm | 2 +- .../projectiles/projectile/special/rocket.dm | 14 +- .../chemistry/machinery/chem_dispenser.dm | 2 +- .../chemistry/machinery/chem_master.dm | 2 +- .../impure_medicine_reagents.dm | 4 +- code/modules/reagents/chemistry/recipes.dm | 2 +- .../chemistry/recipes/slime_extracts.dm | 2 +- code/modules/reagents/reagent_containers.dm | 4 +- code/modules/reagents/reagent_dispenser.dm | 6 +- .../research/anomaly/explosive_compressor.dm | 160 +++++++--- code/modules/research/experimentor.dm | 6 +- .../nanites/nanite_programs/weapon.dm | 2 +- .../crossbreeding/_status_effects.dm | 2 +- .../xenobiology/crossbreeding/charged.dm | 2 +- .../xenobiology/crossbreeding/chilling.dm | 2 +- .../research/xenobiology/xenobiology.dm | 2 +- code/modules/spells/spell_types/explosion.dm | 6 +- code/modules/station_goals/bsa.dm | 2 +- code/modules/vehicles/atv.dm | 2 +- code/modules/vehicles/cars/car.dm | 2 +- code/modules/vehicles/mecha/mecha_defense.dm | 4 +- code/modules/vehicles/mecha/working/ripley.dm | 2 +- code/modules/vehicles/motorized_wheelchair.dm | 2 +- code/modules/vehicles/secway.dm | 2 +- code/modules/vending/_vending.dm | 2 +- tgstation.dme | 1 + 118 files changed, 794 insertions(+), 399 deletions(-) create mode 100644 code/__DEFINES/explosions.dm 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"